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 _UShortPixelPacket
254 typedef struct _MngBox
263 typedef struct _MngPair
270 #ifdef MNG_OBJECT_BUFFERS
271 typedef struct _MngBuffer
303 typedef struct _MngInfo
306 #ifdef MNG_OBJECT_BUFFERS
308 *ob[MNG_MAX_OBJECTS];
319 #ifndef PNG_READ_EMPTY_PLTE_SUPPORTED
320 bytes_in_read_buffer,
326 #if defined(PNG_WRITE_EMPTY_PLTE_SUPPORTED) || \
327 defined(PNG_MNG_FEATURES_SUPPORTED)
339 have_saved_bkgd_index,
340 have_write_global_chrm,
341 have_write_global_gama,
342 have_write_global_plte,
343 have_write_global_srgb,
357 x_off[MNG_MAX_OBJECTS],
358 y_off[MNG_MAX_OBJECTS];
364 object_clip[MNG_MAX_OBJECTS];
367 /* These flags could be combined into one byte */
368 exists[MNG_MAX_OBJECTS],
369 frozen[MNG_MAX_OBJECTS],
371 invisible[MNG_MAX_OBJECTS],
372 viewable[MNG_MAX_OBJECTS];
384 #ifndef PNG_READ_EMPTY_PLTE_SUPPORTED
402 global_x_pixels_per_unit,
403 global_y_pixels_per_unit,
413 global_phys_unit_type,
432 #ifdef MNG_BASI_SUPPORTED
440 basi_compression_method,
442 basi_interlace_method,
465 /* Added at version 6.6.6-7 */
472 /* ping_exclude_iTXt, */
479 ping_exclude_zCCP, /* hex-encoded iCCP */
486 Forward declarations.
488 static MagickBooleanType
489 WritePNGImage(const ImageInfo *,Image *);
491 static MagickBooleanType
492 WriteMNGImage(const ImageInfo *,Image *);
494 #if defined(JNG_SUPPORTED)
495 static MagickBooleanType
496 WriteJNGImage(const ImageInfo *,Image *);
499 #if PNG_LIBPNG_VER > 10011
501 #if (MAGICKCORE_QUANTUM_DEPTH >= 16)
502 static MagickBooleanType
503 LosslessReduceDepthOK(Image *image)
506 ok_to_reduce=MagickFalse;
508 /* Reduce bit depth if it can be reduced losslessly from 16 to 8.
509 * Note that the method GetImageDepth doesn't check background
510 * and doesn't handle PseudoClass specially. Also it uses
511 * multiplication and division by 257 instead of shifting, so
515 if (image->depth == 16)
522 (((((size_t) image->background_color.red >> 8) & 0xff)
523 == ((size_t) image->background_color.red & 0xff)) &&
524 ((((size_t) image->background_color.green >> 8) & 0xff)
525 == ((size_t) image->background_color.green & 0xff)) &&
526 ((((size_t) image->background_color.blue >> 8) & 0xff)
527 == ((size_t) image->background_color.blue & 0xff))) ? MagickTrue :
530 if (ok_to_reduce != MagickFalse && image->storage_class == PseudoClass)
534 for (indx=0; indx < (ssize_t) image->colors; indx++)
536 ok_to_reduce=(((((size_t) image->colormap[indx].red >>
538 == ((size_t) image->colormap[indx].red & 0xff)) &&
539 ((((size_t) image->colormap[indx].green >> 8) & 0xff)
540 == ((size_t) image->colormap[indx].green & 0xff)) &&
541 ((((size_t) image->colormap[indx].blue >> 8) & 0xff)
542 == ((size_t) image->colormap[indx].blue & 0xff)) &&
543 ((((size_t) image->colormap[indx].opacity >> 8) & 0xff)
544 == ((size_t) image->colormap[indx].opacity & 0xff))) ?
545 MagickTrue : MagickFalse;
546 if (ok_to_reduce == MagickFalse)
551 if ((ok_to_reduce != MagickFalse) &&
552 (image->storage_class != PseudoClass))
560 for (y=0; y < (ssize_t) image->rows; y++)
562 p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception);
564 if (p == (const PixelPacket *) NULL)
566 ok_to_reduce = MagickFalse;
570 for (x=(ssize_t) image->columns-1; x >= 0; x--)
573 (((size_t) p->red >> 8) & 0xff) ==
574 ((size_t) p->red & 0xff)) &&
575 ((((size_t) p->green >> 8) & 0xff) ==
576 ((size_t) p->green & 0xff)) &&
577 ((((size_t) p->blue >> 8) & 0xff) ==
578 ((size_t) p->blue & 0xff)) &&
580 (((size_t) p->opacity >> 8) & 0xff) ==
581 ((size_t) p->opacity & 0xff))))) ? MagickTrue : MagickFalse;
583 if (ok_to_reduce == MagickFalse)
593 if (ok_to_reduce != MagickFalse)
595 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
596 " OK to reduce PNG bit depth to 8 without loss of info");
602 #endif /* MAGICKCORE_QUANTUM_DEPTH >= 16 */
605 PNG_RenderingIntent_from_Magick_RenderingIntent(const RenderingIntent intent)
609 case PerceptualIntent:
615 case SaturationIntent:
626 static RenderingIntent
627 PNG_RenderingIntent_to_Magick_RenderingIntent(const int png_intent)
632 return PerceptualIntent;
635 return RelativeIntent;
638 return SaturationIntent;
641 return AbsoluteIntent;
644 return UndefinedIntent;
648 static inline ssize_t MagickMax(const ssize_t x,const ssize_t y)
656 static inline ssize_t MagickMin(const ssize_t x,const ssize_t y)
666 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
670 % I m a g e I s G r a y %
674 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
676 % Like IsGrayImage except does not change DirectClass to PseudoClass %
678 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
680 static MagickBooleanType ImageIsGray(Image *image)
682 register const PixelPacket
690 assert(image != (Image *) NULL);
691 assert(image->signature == MagickSignature);
692 if (image->debug != MagickFalse)
693 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
695 if (image->storage_class == PseudoClass)
697 for (i=0; i < (ssize_t) image->colors; i++)
698 if (IsGray(image->colormap+i) == MagickFalse)
702 for (y=0; y < (ssize_t) image->rows; y++)
704 p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception);
705 if (p == (const PixelPacket *) NULL)
707 for (x=(ssize_t) image->columns-1; x >= 0; x--)
709 if (IsGray(p) == MagickFalse)
718 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
722 % I m a g e I s M o n o c h r o m e %
726 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
728 % Like IsMonochromeImage except does not change DirectClass to PseudoClass %
729 % and is more accurate. %
731 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
733 static MagickBooleanType ImageIsMonochrome(Image *image)
735 register const PixelPacket
743 assert(image != (Image *) NULL);
744 assert(image->signature == MagickSignature);
745 if (image->debug != MagickFalse)
746 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
747 if (image->storage_class == PseudoClass)
749 for (i=0; i < (ssize_t) image->colors; i++)
751 if ((IsGray(image->colormap+i) == MagickFalse) ||
752 ((image->colormap[i].red != 0) &&
753 (image->colormap[i].red != (Quantum) QuantumRange)))
758 for (y=0; y < (ssize_t) image->rows; y++)
760 p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception);
761 if (p == (const PixelPacket *) NULL)
763 for (x=(ssize_t) image->columns-1; x >= 0; x--)
765 if ((p->red != 0) && (p->red != (Quantum) QuantumRange))
768 if (IsGray(p) == MagickFalse)
771 if ((p->opacity != OpaqueOpacity) &&
772 (p->opacity != (Quantum) TransparentOpacity))
780 #endif /* PNG_LIBPNG_VER > 10011 */
781 #endif /* MAGICKCORE_PNG_DELEGATE */
784 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
792 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
794 % IsMNG() returns MagickTrue if the image format type, identified by the
795 % magick string, is MNG.
797 % The format of the IsMNG method is:
799 % MagickBooleanType IsMNG(const unsigned char *magick,const size_t length)
801 % A description of each parameter follows:
803 % o magick: compare image format pattern against these bytes.
805 % o length: Specifies the length of the magick string.
809 static MagickBooleanType IsMNG(const unsigned char *magick,const size_t length)
814 if (memcmp(magick,"\212MNG\r\n\032\n",8) == 0)
821 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
829 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
831 % IsJNG() returns MagickTrue if the image format type, identified by the
832 % magick string, is JNG.
834 % The format of the IsJNG method is:
836 % MagickBooleanType IsJNG(const unsigned char *magick,const size_t length)
838 % A description of each parameter follows:
840 % o magick: compare image format pattern against these bytes.
842 % o length: Specifies the length of the magick string.
846 static MagickBooleanType IsJNG(const unsigned char *magick,const size_t length)
851 if (memcmp(magick,"\213JNG\r\n\032\n",8) == 0)
858 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
866 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
868 % IsPNG() returns MagickTrue if the image format type, identified by the
869 % magick string, is PNG.
871 % The format of the IsPNG method is:
873 % MagickBooleanType IsPNG(const unsigned char *magick,const size_t length)
875 % A description of each parameter follows:
877 % o magick: compare image format pattern against these bytes.
879 % o length: Specifies the length of the magick string.
882 static MagickBooleanType IsPNG(const unsigned char *magick,const size_t length)
887 if (memcmp(magick,"\211PNG\r\n\032\n",8) == 0)
893 #if defined(MAGICKCORE_PNG_DELEGATE)
894 #if defined(__cplusplus) || defined(c_plusplus)
898 #if (PNG_LIBPNG_VER > 10011)
899 static size_t WriteBlobMSBULong(Image *image,const size_t value)
904 assert(image != (Image *) NULL);
905 assert(image->signature == MagickSignature);
906 buffer[0]=(unsigned char) (value >> 24);
907 buffer[1]=(unsigned char) (value >> 16);
908 buffer[2]=(unsigned char) (value >> 8);
909 buffer[3]=(unsigned char) value;
910 return((size_t) WriteBlob(image,4,buffer));
913 static void PNGLong(png_bytep p,png_uint_32 value)
915 *p++=(png_byte) ((value >> 24) & 0xff);
916 *p++=(png_byte) ((value >> 16) & 0xff);
917 *p++=(png_byte) ((value >> 8) & 0xff);
918 *p++=(png_byte) (value & 0xff);
921 #if defined(JNG_SUPPORTED)
922 static void PNGsLong(png_bytep p,png_int_32 value)
924 *p++=(png_byte) ((value >> 24) & 0xff);
925 *p++=(png_byte) ((value >> 16) & 0xff);
926 *p++=(png_byte) ((value >> 8) & 0xff);
927 *p++=(png_byte) (value & 0xff);
931 static void PNGShort(png_bytep p,png_uint_16 value)
933 *p++=(png_byte) ((value >> 8) & 0xff);
934 *p++=(png_byte) (value & 0xff);
937 static void PNGType(png_bytep p,png_bytep type)
939 (void) CopyMagickMemory(p,type,4*sizeof(png_byte));
942 static void LogPNGChunk(MagickBooleanType logging, png_bytep type,
945 if (logging != MagickFalse)
946 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
947 " Writing %c%c%c%c chunk, length: %.20g",
948 type[0],type[1],type[2],type[3],(double) length);
950 #endif /* PNG_LIBPNG_VER > 10011 */
952 #if defined(__cplusplus) || defined(c_plusplus)
956 #if PNG_LIBPNG_VER > 10011
958 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
962 % R e a d P N G I m a g e %
966 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
968 % ReadPNGImage() reads a Portable Network Graphics (PNG) or
969 % Multiple-image Network Graphics (MNG) image file and returns it. It
970 % allocates the memory necessary for the new Image structure and returns a
971 % pointer to the new image or set of images.
973 % MNG support written by Glenn Randers-Pehrson, glennrp@image...
975 % The format of the ReadPNGImage method is:
977 % Image *ReadPNGImage(const ImageInfo *image_info,ExceptionInfo *exception)
979 % A description of each parameter follows:
981 % o image_info: the image info.
983 % o exception: return any errors or warnings in this structure.
985 % To do, more or less in chronological order (as of version 5.5.2,
986 % November 26, 2002 -- glennrp -- see also "To do" under WriteMNGImage):
988 % Get 16-bit cheap transparency working.
990 % (At this point, PNG decoding is supposed to be in full MNG-LC compliance)
992 % Preserve all unknown and not-yet-handled known chunks found in input
993 % PNG file and copy them into output PNG files according to the PNG
996 % (At this point, PNG encoding should be in full MNG compliance)
998 % Provide options for choice of background to use when the MNG BACK
999 % chunk is not present or is not mandatory (i.e., leave transparent,
1000 % user specified, MNG BACK, PNG bKGD)
1002 % Implement LOOP/ENDL [done, but could do discretionary loops more
1003 % efficiently by linking in the duplicate frames.].
1005 % Decode and act on the MHDR simplicity profile (offer option to reject
1006 % files or attempt to process them anyway when the profile isn't LC or VLC).
1008 % Upgrade to full MNG without Delta-PNG.
1010 % o BACK [done a while ago except for background image ID]
1011 % o MOVE [done 15 May 1999]
1012 % o CLIP [done 15 May 1999]
1013 % o DISC [done 19 May 1999]
1014 % o SAVE [partially done 19 May 1999 (marks objects frozen)]
1015 % o SEEK [partially done 19 May 1999 (discard function only)]
1019 % o MNG-level tEXt/iTXt/zTXt
1024 % o iTXt (wait for libpng implementation).
1026 % Use the scene signature to discover when an identical scene is
1027 % being reused, and just point to the original image->exception instead
1028 % of storing another set of pixels. This not specific to MNG
1029 % but could be applied generally.
1031 % Upgrade to full MNG with Delta-PNG.
1033 % JNG tEXt/iTXt/zTXt
1035 % We will not attempt to read files containing the CgBI chunk.
1036 % They are really Xcode files meant for display on the iPhone.
1037 % These are not valid PNG files and it is impossible to recover
1038 % the orginal PNG from files that have been converted to Xcode-PNG,
1039 % since irretrievable loss of color data has occurred due to the
1040 % use of premultiplied alpha.
1043 #if defined(__cplusplus) || defined(c_plusplus)
1048 This the function that does the actual reading of data. It is
1049 the same as the one supplied in libpng, except that it receives the
1050 datastream from the ReadBlob() function instead of standard input.
1052 static void png_get_data(png_structp png_ptr,png_bytep data,png_size_t length)
1057 image=(Image *) png_get_io_ptr(png_ptr);
1063 check=(png_size_t) ReadBlob(image,(size_t) length,data);
1064 if (check != length)
1069 (void) FormatMagickString(msg,MaxTextExtent,
1070 "Expected %.20g bytes; found %.20g bytes",(double) length,
1072 png_warning(png_ptr,msg);
1073 png_error(png_ptr,"Read Exception");
1078 #if !defined(PNG_READ_EMPTY_PLTE_SUPPORTED) && \
1079 !defined(PNG_MNG_FEATURES_SUPPORTED)
1080 /* We use mng_get_data() instead of png_get_data() if we have a libpng
1081 * older than libpng-1.0.3a, which was the first to allow the empty
1082 * PLTE, or a newer libpng in which PNG_MNG_FEATURES_SUPPORTED was
1083 * ifdef'ed out. Earlier versions would crash if the bKGD chunk was
1084 * encountered after an empty PLTE, so we have to look ahead for bKGD
1085 * chunks and remove them from the datastream that is passed to libpng,
1086 * and store their contents for later use.
1088 static void mng_get_data(png_structp png_ptr,png_bytep data,png_size_t length)
1103 mng_info=(MngInfo *) png_get_io_ptr(png_ptr);
1104 image=(Image *) mng_info->image;
1105 while (mng_info->bytes_in_read_buffer && length)
1107 data[i]=mng_info->read_buffer[i];
1108 mng_info->bytes_in_read_buffer--;
1114 check=(png_size_t) ReadBlob(image,(size_t) length,(char *) data);
1116 if (check != length)
1117 png_error(png_ptr,"Read Exception");
1121 if ((data[0] == 0) && (data[1] == 0) && (data[2] == 0) &&
1124 check=(png_size_t) ReadBlob(image,(size_t) length,
1125 (char *) mng_info->read_buffer);
1126 mng_info->read_buffer[4]=0;
1127 mng_info->bytes_in_read_buffer=4;
1128 if (memcmp(mng_info->read_buffer,mng_PLTE,4) == 0)
1129 mng_info->found_empty_plte=MagickTrue;
1130 if (memcmp(mng_info->read_buffer,mng_IEND,4) == 0)
1132 mng_info->found_empty_plte=MagickFalse;
1133 mng_info->have_saved_bkgd_index=MagickFalse;
1137 if ((data[0] == 0) && (data[1] == 0) && (data[2] == 0) &&
1140 check=(png_size_t) ReadBlob(image,(size_t) length,
1141 (char *) mng_info->read_buffer);
1142 mng_info->read_buffer[4]=0;
1143 mng_info->bytes_in_read_buffer=4;
1144 if (memcmp(mng_info->read_buffer,mng_bKGD,4) == 0)
1145 if (mng_info->found_empty_plte)
1148 Skip the bKGD data byte and CRC.
1151 ReadBlob(image,5,(char *) mng_info->read_buffer);
1152 check=(png_size_t) ReadBlob(image,(size_t) length,
1153 (char *) mng_info->read_buffer);
1154 mng_info->saved_bkgd_index=mng_info->read_buffer[0];
1155 mng_info->have_saved_bkgd_index=MagickTrue;
1156 mng_info->bytes_in_read_buffer=0;
1164 static void png_put_data(png_structp png_ptr,png_bytep data,png_size_t length)
1169 image=(Image *) png_get_io_ptr(png_ptr);
1175 check=(png_size_t) WriteBlob(image,(size_t) length,data);
1177 if (check != length)
1178 png_error(png_ptr,"WriteBlob Failed");
1182 static void png_flush_data(png_structp png_ptr)
1187 #ifdef PNG_WRITE_EMPTY_PLTE_SUPPORTED
1188 static int PalettesAreEqual(Image *a,Image *b)
1193 if ((a == (Image *) NULL) || (b == (Image *) NULL))
1194 return((int) MagickFalse);
1196 if (a->storage_class != PseudoClass || b->storage_class != PseudoClass)
1197 return((int) MagickFalse);
1199 if (a->colors != b->colors)
1200 return((int) MagickFalse);
1202 for (i=0; i < (ssize_t) a->colors; i++)
1204 if ((a->colormap[i].red != b->colormap[i].red) ||
1205 (a->colormap[i].green != b->colormap[i].green) ||
1206 (a->colormap[i].blue != b->colormap[i].blue))
1207 return((int) MagickFalse);
1210 return((int) MagickTrue);
1214 static void MngInfoDiscardObject(MngInfo *mng_info,int i)
1216 if (i && (i < MNG_MAX_OBJECTS) && (mng_info != (MngInfo *) NULL) &&
1217 mng_info->exists[i] && !mng_info->frozen[i])
1219 #ifdef MNG_OBJECT_BUFFERS
1220 if (mng_info->ob[i] != (MngBuffer *) NULL)
1222 if (mng_info->ob[i]->reference_count > 0)
1223 mng_info->ob[i]->reference_count--;
1225 if (mng_info->ob[i]->reference_count == 0)
1227 if (mng_info->ob[i]->image != (Image *) NULL)
1228 mng_info->ob[i]->image=DestroyImage(mng_info->ob[i]->image);
1230 mng_info->ob[i]=DestroyString(mng_info->ob[i]);
1233 mng_info->ob[i]=(MngBuffer *) NULL;
1235 mng_info->exists[i]=MagickFalse;
1236 mng_info->invisible[i]=MagickFalse;
1237 mng_info->viewable[i]=MagickFalse;
1238 mng_info->frozen[i]=MagickFalse;
1239 mng_info->x_off[i]=0;
1240 mng_info->y_off[i]=0;
1241 mng_info->object_clip[i].left=0;
1242 mng_info->object_clip[i].right=(ssize_t) PNG_UINT_31_MAX;
1243 mng_info->object_clip[i].top=0;
1244 mng_info->object_clip[i].bottom=(ssize_t) PNG_UINT_31_MAX;
1248 static void MngInfoFreeStruct(MngInfo *mng_info,
1249 MagickBooleanType *have_mng_structure)
1251 if (*have_mng_structure != MagickFalse && (mng_info != (MngInfo *) NULL))
1256 for (i=1; i < MNG_MAX_OBJECTS; i++)
1257 MngInfoDiscardObject(mng_info,i);
1259 if (mng_info->global_plte != (png_colorp) NULL)
1260 mng_info->global_plte=(png_colorp)
1261 RelinquishMagickMemory(mng_info->global_plte);
1263 mng_info=(MngInfo *) RelinquishMagickMemory(mng_info);
1264 *have_mng_structure=MagickFalse;
1268 static MngBox mng_minimum_box(MngBox box1,MngBox box2)
1274 if (box.left < box2.left)
1277 if (box.top < box2.top)
1280 if (box.right > box2.right)
1281 box.right=box2.right;
1283 if (box.bottom > box2.bottom)
1284 box.bottom=box2.bottom;
1289 static MngBox mng_read_box(MngBox previous_box,char delta_type,unsigned char *p)
1295 Read clipping boundaries from DEFI, CLIP, FRAM, or PAST chunk.
1297 box.left=(ssize_t) ((p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]);
1298 box.right=(ssize_t) ((p[4] << 24) | (p[5] << 16) | (p[6] << 8) | p[7]);
1299 box.top=(ssize_t) ((p[8] << 24) | (p[9] << 16) | (p[10] << 8) | p[11]);
1300 box.bottom=(ssize_t) ((p[12] << 24) | (p[13] << 16) | (p[14] << 8) | p[15]);
1301 if (delta_type != 0)
1303 box.left+=previous_box.left;
1304 box.right+=previous_box.right;
1305 box.top+=previous_box.top;
1306 box.bottom+=previous_box.bottom;
1312 static MngPair mng_read_pair(MngPair previous_pair,int delta_type,
1318 Read two ssize_ts from CLON, MOVE or PAST chunk
1320 pair.a=(long) ((p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]);
1321 pair.b=(long) ((p[4] << 24) | (p[5] << 16) | (p[6] << 8) | p[7]);
1323 if (delta_type != 0)
1325 pair.a+=previous_pair.a;
1326 pair.b+=previous_pair.b;
1332 static long mng_get_long(unsigned char *p)
1334 return((long) ((p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]));
1337 static void PNGErrorHandler(png_struct *ping,png_const_charp message)
1342 image=(Image *) png_get_error_ptr(ping);
1344 if (image->debug != MagickFalse)
1345 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1346 " libpng-%s error: %s", PNG_LIBPNG_VER_STRING,message);
1348 (void) ThrowMagickException(&image->exception,GetMagickModule(),CoderError,
1349 message,"`%s'",image->filename);
1351 #if PNG_LIBPNG_VER < 10500
1352 longjmp(ping->jmpbuf,1);
1354 png_longjmp(ping,1);
1358 static void PNGWarningHandler(png_struct *ping,png_const_charp message)
1363 if (LocaleCompare(message, "Missing PLTE before tRNS") == 0)
1364 png_error(ping, message);
1366 image=(Image *) png_get_error_ptr(ping);
1367 if (image->debug != MagickFalse)
1368 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1369 " libpng-%s warning: %s", PNG_LIBPNG_VER_STRING,message);
1371 (void) ThrowMagickException(&image->exception,GetMagickModule(),CoderWarning,
1372 message,"`%s'",image->filename);
1375 #ifdef PNG_USER_MEM_SUPPORTED
1376 static png_voidp png_IM_malloc(png_structp png_ptr,png_uint_32 size)
1378 #if (PNG_LIBPNG_VER < 10011)
1383 ret=((png_voidp) AcquireMagickMemory((size_t) size));
1386 png_error("Insufficient memory.");
1391 return((png_voidp) AcquireMagickMemory((size_t) size));
1396 Free a pointer. It is removed from the list at the same time.
1398 static png_free_ptr png_IM_free(png_structp png_ptr,png_voidp ptr)
1401 ptr=RelinquishMagickMemory(ptr);
1402 return((png_free_ptr) NULL);
1406 #if defined(__cplusplus) || defined(c_plusplus)
1411 png_read_raw_profile(Image *image, const ImageInfo *image_info,
1412 png_textp text,int ii)
1417 register unsigned char
1431 unhex[103]={0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,
1432 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,
1433 0,0,0,0,0,0,0,0,0,1, 2,3,4,5,6,7,8,9,0,0,
1434 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,
1435 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,10,11,12,
1439 /* look for newline */
1443 /* look for length */
1444 while (*sp == '\0' || *sp == ' ' || *sp == '\n')
1447 length=(png_uint_32) StringToLong(sp);
1449 while (*sp != ' ' && *sp != '\n')
1452 /* allocate space */
1455 (void) ThrowMagickException(&image->exception,GetMagickModule(),
1456 CoderWarning,"UnableToCopyProfile","`%s'","invalid profile length");
1457 return(MagickFalse);
1460 profile=AcquireStringInfo(length);
1462 if (profile == (StringInfo *) NULL)
1464 (void) ThrowMagickException(&image->exception,GetMagickModule(),
1465 ResourceLimitError,"MemoryAllocationFailed","`%s'",
1466 "unable to copy profile");
1467 return(MagickFalse);
1470 /* copy profile, skipping white space and column 1 "=" signs */
1471 dp=GetStringInfoDatum(profile);
1474 for (i=0; i < (ssize_t) nibbles; i++)
1476 while (*sp < '0' || (*sp > '9' && *sp < 'a') || *sp > 'f')
1480 (void) ThrowMagickException(&image->exception,GetMagickModule(),
1481 CoderWarning,"UnableToCopyProfile","`%s'","ran out of data");
1482 profile=DestroyStringInfo(profile);
1483 return(MagickFalse);
1489 *dp=(unsigned char) (16*unhex[(int) *sp++]);
1492 (*dp++)+=unhex[(int) *sp++];
1495 We have already read "Raw profile type.
1497 (void) SetImageProfile(image,&text[ii].key[17],profile);
1498 profile=DestroyStringInfo(profile);
1500 if (image_info->verbose)
1501 (void) printf(" Found a generic profile, type %s\n",&text[ii].key[17]);
1506 #if defined(PNG_UNKNOWN_CHUNKS_SUPPORTED)
1507 static int read_vpag_chunk_callback(png_struct *ping, png_unknown_chunkp chunk)
1513 /* The unknown chunk structure contains the chunk data:
1518 Note that libpng has already taken care of the CRC handling.
1522 if (chunk->name[0] != 118 || chunk->name[1] != 112 ||
1523 chunk->name[2] != 65 ||chunk-> name[3] != 103)
1524 return(0); /* Did not recognize */
1526 /* recognized vpAg */
1528 if (chunk->size != 9)
1529 return(-1); /* Error return */
1531 if (chunk->data[8] != 0)
1532 return(0); /* ImageMagick requires pixel units */
1534 image=(Image *) png_get_user_chunk_ptr(ping);
1536 image->page.width=(size_t) ((chunk->data[0] << 24) |
1537 (chunk->data[1] << 16) | (chunk->data[2] << 8) | chunk->data[3]);
1539 image->page.height=(size_t) ((chunk->data[4] << 24) |
1540 (chunk->data[5] << 16) | (chunk->data[6] << 8) | chunk->data[7]);
1542 /* Return one of the following: */
1543 /* return(-n); chunk had an error */
1544 /* return(0); did not recognize */
1545 /* return(n); success */
1553 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1557 % R e a d O n e P N G I m a g e %
1561 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1563 % ReadOnePNGImage() reads a Portable Network Graphics (PNG) image file
1564 % (minus the 8-byte signature) and returns it. It allocates the memory
1565 % necessary for the new Image structure and returns a pointer to the new
1568 % The format of the ReadOnePNGImage method is:
1570 % Image *ReadOnePNGImage(MngInfo *mng_info, const ImageInfo *image_info,
1571 % ExceptionInfo *exception)
1573 % A description of each parameter follows:
1575 % o mng_info: Specifies a pointer to a MngInfo structure.
1577 % o image_info: the image info.
1579 % o exception: return any errors or warnings in this structure.
1582 static Image *ReadOnePNGImage(MngInfo *mng_info,
1583 const ImageInfo *image_info, ExceptionInfo *exception)
1585 /* Read one PNG image */
1596 ping_interlace_method,
1597 ping_compression_method,
1639 register unsigned char
1642 register IndexPacket
1649 register PixelPacket
1656 #if defined(PNG_UNKNOWN_CHUNKS_SUPPORTED)
1657 png_byte unused_chunks[]=
1659 104, 73, 83, 84, (png_byte) '\0', /* hIST */
1660 105, 84, 88, 116, (png_byte) '\0', /* iTXt */
1661 112, 67, 65, 76, (png_byte) '\0', /* pCAL */
1662 115, 67, 65, 76, (png_byte) '\0', /* sCAL */
1663 115, 80, 76, 84, (png_byte) '\0', /* sPLT */
1664 116, 73, 77, 69, (png_byte) '\0', /* tIME */
1668 logging=LogMagickEvent(CoderEvent,GetMagickModule(),
1669 " enter ReadOnePNGImage()");
1671 #if defined(PNG_SETJMP_NOT_THREAD_SAFE)
1672 LockSemaphoreInfo(png_semaphore);
1675 #if (PNG_LIBPNG_VER < 10200)
1676 if (image_info->verbose)
1677 printf("Your PNG library (libpng-%s) is rather old.\n",
1678 PNG_LIBPNG_VER_STRING);
1681 #if (PNG_LIBPNG_VER >= 10400)
1682 # ifndef PNG_TRANSFORM_GRAY_TO_RGB /* Added at libpng-1.4.0beta67 */
1683 if (image_info->verbose)
1685 printf("Your PNG library (libpng-%s) is an old beta version.\n",
1686 PNG_LIBPNG_VER_STRING);
1687 printf("Please update it.\n");
1693 quantum_info = (QuantumInfo *) NULL;
1694 image=mng_info->image;
1697 Allocate the PNG structures
1699 #ifdef PNG_USER_MEM_SUPPORTED
1700 ping=png_create_read_struct_2(PNG_LIBPNG_VER_STRING, image,
1701 PNGErrorHandler,PNGWarningHandler, NULL,
1702 (png_malloc_ptr) png_IM_malloc,(png_free_ptr) png_IM_free);
1704 ping=png_create_read_struct(PNG_LIBPNG_VER_STRING,image,
1705 PNGErrorHandler,PNGWarningHandler);
1707 if (ping == (png_struct *) NULL)
1708 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1710 ping_info=png_create_info_struct(ping);
1712 if (ping_info == (png_info *) NULL)
1714 png_destroy_read_struct(&ping,(png_info **) NULL,(png_info **) NULL);
1715 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1718 end_info=png_create_info_struct(ping);
1720 if (end_info == (png_info *) NULL)
1722 png_destroy_read_struct(&ping,&ping_info,(png_info **) NULL);
1723 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1726 png_pixels=(unsigned char *) NULL;
1728 if (setjmp(png_jmpbuf(ping)))
1731 PNG image is corrupt.
1733 png_destroy_read_struct(&ping,&ping_info,&end_info);
1734 #if defined(PNG_SETJMP_NOT_THREAD_SAFE)
1735 UnlockSemaphoreInfo(png_semaphore);
1737 if (logging != MagickFalse)
1738 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1739 " exit ReadOnePNGImage() with error.");
1741 if (image != (Image *) NULL)
1743 InheritException(exception,&image->exception);
1747 return(GetFirstImageInList(image));
1750 Prepare PNG for reading.
1753 mng_info->image_found++;
1754 png_set_sig_bytes(ping,8);
1756 if (LocaleCompare(image_info->magick,"MNG") == 0)
1758 #if defined(PNG_MNG_FEATURES_SUPPORTED)
1759 (void) png_permit_mng_features(ping,PNG_ALL_MNG_FEATURES);
1760 png_set_read_fn(ping,image,png_get_data);
1762 #if defined(PNG_READ_EMPTY_PLTE_SUPPORTED)
1763 png_permit_empty_plte(ping,MagickTrue);
1764 png_set_read_fn(ping,image,png_get_data);
1766 mng_info->image=image;
1767 mng_info->bytes_in_read_buffer=0;
1768 mng_info->found_empty_plte=MagickFalse;
1769 mng_info->have_saved_bkgd_index=MagickFalse;
1770 png_set_read_fn(ping,mng_info,mng_get_data);
1776 png_set_read_fn(ping,image,png_get_data);
1778 #if defined(PNG_UNKNOWN_CHUNKS_SUPPORTED)
1779 /* Ignore unused chunks and all unknown chunks except for vpAg */
1780 png_set_keep_unknown_chunks(ping, 1, NULL, 0);
1781 png_set_keep_unknown_chunks(ping, 2, mng_vpAg, 1);
1782 png_set_keep_unknown_chunks(ping, 1, unused_chunks,
1783 (int)sizeof(unused_chunks)/5);
1784 /* Callback for other unknown chunks */
1785 png_set_read_user_chunk_fn(ping, image, read_vpag_chunk_callback);
1788 #if (PNG_LIBPNG_VER < 10400)
1789 # if defined(PNG_USE_PNGGCCRD) && defined(PNG_ASSEMBLER_CODE_SUPPORTED) && \
1790 (PNG_LIBPNG_VER >= 10200) && (PNG_LIBPNG_VER < 10220) && defined(__i386__)
1791 /* Disable thread-unsafe features of pnggccrd */
1792 if (png_access_version_number() >= 10200)
1794 png_uint_32 mmx_disable_mask=0;
1795 png_uint_32 asm_flags;
1797 mmx_disable_mask |= ( PNG_ASM_FLAG_MMX_READ_COMBINE_ROW \
1798 | PNG_ASM_FLAG_MMX_READ_FILTER_SUB \
1799 | PNG_ASM_FLAG_MMX_READ_FILTER_AVG \
1800 | PNG_ASM_FLAG_MMX_READ_FILTER_PAETH );
1801 asm_flags=png_get_asm_flags(ping);
1802 png_set_asm_flags(ping, asm_flags & ~mmx_disable_mask);
1807 png_read_info(ping,ping_info);
1809 png_get_IHDR(ping,ping_info,&ping_width,&ping_height,
1810 &ping_bit_depth,&ping_color_type,
1811 &ping_interlace_method,&ping_compression_method,
1812 &ping_filter_method);
1814 (void) png_get_tRNS(ping, ping_info, &ping_trans_alpha, &ping_num_trans,
1817 (void) png_get_bKGD(ping, ping_info, &ping_background);
1819 if (ping_bit_depth < 8)
1821 if (((int) ping_color_type == PNG_COLOR_TYPE_PALETTE))
1823 png_set_packing(ping);
1828 image->depth=ping_bit_depth;
1829 image->depth=GetImageQuantumDepth(image,MagickFalse);
1830 image->interlace=ping_interlace_method != 0 ? PNGInterlace : NoInterlace;
1831 if (logging != MagickFalse)
1833 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1834 " PNG width: %.20g, height: %.20g",
1835 (double) ping_width, (double) ping_height);
1837 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1838 " PNG color_type: %d, bit_depth: %d",
1839 ping_color_type, ping_bit_depth);
1841 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1842 " PNG compression_method: %d",
1843 ping_compression_method);
1845 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1846 " PNG interlace_method: %d, filter_method: %d",
1847 ping_interlace_method,ping_filter_method);
1850 #ifdef PNG_READ_iCCP_SUPPORTED
1851 if (png_get_valid(ping,ping_info,PNG_INFO_iCCP))
1863 (void) png_get_iCCP(ping,ping_info,&name,(int *) &compression,&info,
1866 if (profile_length != 0)
1871 if (logging != MagickFalse)
1872 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1873 " Reading PNG iCCP chunk.");
1874 profile=AcquireStringInfo(profile_length);
1875 SetStringInfoDatum(profile,(const unsigned char *) info);
1876 (void) SetImageProfile(image,"icc",profile);
1877 profile=DestroyStringInfo(profile);
1881 #if defined(PNG_READ_sRGB_SUPPORTED)
1886 if (mng_info->have_global_srgb)
1887 image->rendering_intent=PNG_RenderingIntent_to_Magick_RenderingIntent(
1888 mng_info->global_srgb_intent);
1890 if (png_get_sRGB(ping,ping_info,&intent))
1892 image->rendering_intent=PNG_RenderingIntent_to_Magick_RenderingIntent(
1895 if (logging != MagickFalse)
1896 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1897 " Reading PNG sRGB chunk: rendering_intent: %d",intent);
1905 if (!png_get_gAMA(ping,ping_info,&file_gamma))
1906 if (mng_info->have_global_gama)
1907 png_set_gAMA(ping,ping_info,mng_info->global_gamma);
1909 if (png_get_gAMA(ping,ping_info,&file_gamma))
1911 image->gamma=(float) file_gamma;
1912 if (logging != MagickFalse)
1913 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1914 " Reading PNG gAMA chunk: gamma: %f",file_gamma);
1917 if (!png_get_valid(ping,ping_info,PNG_INFO_cHRM))
1919 if (mng_info->have_global_chrm != MagickFalse)
1921 (void) png_set_cHRM(ping,ping_info,
1922 mng_info->global_chrm.white_point.x,
1923 mng_info->global_chrm.white_point.y,
1924 mng_info->global_chrm.red_primary.x,
1925 mng_info->global_chrm.red_primary.y,
1926 mng_info->global_chrm.green_primary.x,
1927 mng_info->global_chrm.green_primary.y,
1928 mng_info->global_chrm.blue_primary.x,
1929 mng_info->global_chrm.blue_primary.y);
1933 if (png_get_valid(ping,ping_info,PNG_INFO_cHRM))
1935 (void) png_get_cHRM(ping,ping_info,
1936 &image->chromaticity.white_point.x,
1937 &image->chromaticity.white_point.y,
1938 &image->chromaticity.red_primary.x,
1939 &image->chromaticity.red_primary.y,
1940 &image->chromaticity.green_primary.x,
1941 &image->chromaticity.green_primary.y,
1942 &image->chromaticity.blue_primary.x,
1943 &image->chromaticity.blue_primary.y);
1945 if (logging != MagickFalse)
1946 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1947 " Reading PNG cHRM chunk.");
1950 if (image->rendering_intent != UndefinedIntent)
1952 png_set_sRGB(ping,ping_info,
1953 PNG_RenderingIntent_from_Magick_RenderingIntent(
1954 image->rendering_intent));
1955 png_set_gAMA(ping,ping_info,0.45455f);
1956 png_set_cHRM(ping,ping_info,
1957 0.6400f, 0.3300f, 0.3000f, 0.6000f,
1958 0.1500f, 0.0600f, 0.3127f, 0.3290f);
1960 #if defined(PNG_oFFs_SUPPORTED)
1961 if (png_get_valid(ping,ping_info,PNG_INFO_oFFs))
1963 image->page.x=png_get_x_offset_pixels(ping, ping_info);
1964 image->page.y=png_get_y_offset_pixels(ping, ping_info);
1966 if (logging != MagickFalse)
1967 if (image->page.x || image->page.y)
1968 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1969 " Reading PNG oFFs chunk: x: %.20g, y: %.20g.",(double)
1970 image->page.x,(double) image->page.y);
1973 #if defined(PNG_pHYs_SUPPORTED)
1974 if (!png_get_valid(ping,ping_info,PNG_INFO_pHYs))
1976 if (mng_info->have_global_phys)
1978 png_set_pHYs(ping,ping_info,
1979 mng_info->global_x_pixels_per_unit,
1980 mng_info->global_y_pixels_per_unit,
1981 mng_info->global_phys_unit_type);
1985 if (png_get_valid(ping,ping_info,PNG_INFO_pHYs))
1995 Set image resolution.
1997 (void) png_get_pHYs(ping,ping_info,&x_resolution,&y_resolution,
1999 image->x_resolution=(double) x_resolution;
2000 image->y_resolution=(double) y_resolution;
2002 if (unit_type == PNG_RESOLUTION_METER)
2004 image->units=PixelsPerCentimeterResolution;
2005 image->x_resolution=(double) x_resolution/100.0;
2006 image->y_resolution=(double) y_resolution/100.0;
2009 if (logging != MagickFalse)
2010 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2011 " Reading PNG pHYs chunk: xres: %.20g, yres: %.20g, units: %d.",
2012 (double) x_resolution,(double) y_resolution,unit_type);
2015 if (png_get_valid(ping,ping_info,PNG_INFO_PLTE))
2023 (void) png_get_PLTE(ping,ping_info,&palette,&number_colors);
2025 if ((number_colors == 0) &&
2026 ((int) ping_color_type == PNG_COLOR_TYPE_PALETTE))
2028 if (mng_info->global_plte_length)
2030 png_set_PLTE(ping,ping_info,mng_info->global_plte,
2031 (int) mng_info->global_plte_length);
2033 if (!png_get_valid(ping,ping_info,PNG_INFO_tRNS))
2034 if (mng_info->global_trns_length)
2036 if (mng_info->global_trns_length >
2037 mng_info->global_plte_length)
2038 (void) ThrowMagickException(&image->exception,
2039 GetMagickModule(),CoderError,
2040 "global tRNS has more entries than global PLTE",
2041 "`%s'",image_info->filename);
2042 png_set_tRNS(ping,ping_info,mng_info->global_trns,
2043 (int) mng_info->global_trns_length,NULL);
2045 #if defined(PNG_READ_bKGD_SUPPORTED)
2047 #ifndef PNG_READ_EMPTY_PLTE_SUPPORTED
2048 mng_info->have_saved_bkgd_index ||
2050 png_get_valid(ping,ping_info,PNG_INFO_bKGD))
2055 #ifndef PNG_READ_EMPTY_PLTE_SUPPORTED
2056 if (mng_info->have_saved_bkgd_index)
2057 background.index=mng_info->saved_bkgd_index;
2059 if (png_get_valid(ping, ping_info, PNG_INFO_bKGD))
2060 background.index=ping_background->index;
2062 background.red=(png_uint_16)
2063 mng_info->global_plte[background.index].red;
2065 background.green=(png_uint_16)
2066 mng_info->global_plte[background.index].green;
2068 background.blue=(png_uint_16)
2069 mng_info->global_plte[background.index].blue;
2071 png_set_bKGD(ping,ping_info,&background);
2076 (void) ThrowMagickException(&image->exception,GetMagickModule(),
2077 CoderError,"No global PLTE in file","`%s'",
2078 image_info->filename);
2082 #if defined(PNG_READ_bKGD_SUPPORTED)
2083 if (mng_info->have_global_bkgd &&
2084 (!png_get_valid(ping,ping_info,PNG_INFO_bKGD)))
2085 image->background_color=mng_info->mng_global_bkgd;
2087 if (png_get_valid(ping,ping_info,PNG_INFO_bKGD))
2090 Set image background color.
2092 if (logging != MagickFalse)
2093 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2094 " Reading PNG bKGD chunk.");
2096 if (ping_bit_depth == MAGICKCORE_QUANTUM_DEPTH)
2098 image->background_color.red=ping_background->red;
2099 image->background_color.green=ping_background->green;
2100 image->background_color.blue=ping_background->blue;
2103 else /* Scale background components to 16-bit */
2108 if (logging != MagickFalse)
2109 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2110 " raw ping_background=(%d,%d,%d).",ping_background->red,
2111 ping_background->green,ping_background->blue);
2115 if (ping_bit_depth == 1)
2118 else if (ping_bit_depth == 2)
2121 else if (ping_bit_depth == 4)
2124 if (ping_bit_depth <= 8)
2127 ping_background->red *= bkgd_scale;
2128 ping_background->green *= bkgd_scale;
2129 ping_background->blue *= bkgd_scale;
2131 if (logging != MagickFalse)
2133 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2134 " bkgd_scale=%d.",bkgd_scale);
2136 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2137 " ping_background=(%d,%d,%d).",ping_background->red,
2138 ping_background->green,ping_background->blue);
2141 image->background_color.red=
2142 ScaleShortToQuantum(ping_background->red);
2144 image->background_color.green=
2145 ScaleShortToQuantum(ping_background->green);
2147 image->background_color.blue=
2148 ScaleShortToQuantum(ping_background->blue);
2150 image->background_color.opacity=OpaqueOpacity;
2152 if (logging != MagickFalse)
2153 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2154 " image->background_color=(%.20g,%.20g,%.20g).",
2155 (double) image->background_color.red,
2156 (double) image->background_color.green,
2157 (double) image->background_color.blue);
2161 transparent_color.red=0;
2162 transparent_color.green=0;
2163 transparent_color.blue=0;
2164 transparent_color.opacity=0;
2165 if (png_get_valid(ping,ping_info,PNG_INFO_tRNS))
2168 Image has a transparent background.
2176 if (logging != MagickFalse)
2177 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2178 " Reading PNG tRNS chunk.");
2180 max_sample = (int) ((one << ping_bit_depth) - 1);
2182 if ((ping_color_type == PNG_COLOR_TYPE_GRAY &&
2183 (int)ping_trans_color->gray > max_sample) ||
2184 (ping_color_type == PNG_COLOR_TYPE_RGB &&
2185 ((int)ping_trans_color->red > max_sample ||
2186 (int)ping_trans_color->green > max_sample ||
2187 (int)ping_trans_color->blue > max_sample)))
2189 if (logging != MagickFalse)
2190 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2191 " Ignoring PNG tRNS chunk with out-of-range sample.");
2192 png_free_data(ping, ping_info, PNG_FREE_TRNS, 0);
2193 png_set_invalid(ping,ping_info,PNG_INFO_tRNS);
2194 image->matte=MagickFalse;
2198 transparent_color.red= (unsigned short)(ping_trans_color->red);
2199 transparent_color.green= (unsigned short) (ping_trans_color->green);
2200 transparent_color.blue= (unsigned short) (ping_trans_color->blue);
2201 transparent_color.opacity= (unsigned short) (ping_trans_color->gray);
2203 if (ping_color_type == PNG_COLOR_TYPE_GRAY)
2205 #if (MAGICKCORE_QUANTUM_DEPTH == 8)
2206 if (ping_bit_depth < MAGICKCORE_QUANTUM_DEPTH)
2208 transparent_color.opacity=(unsigned short) (
2209 ping_trans_color->gray *
2210 (65535L/((1UL << ping_bit_depth)-1)));
2212 #if (MAGICKCORE_QUANTUM_DEPTH == 8)
2214 transparent_color.opacity=(unsigned short) (
2215 (ping_trans_color->gray * 65535L)/
2216 ((1UL << ping_bit_depth)-1));
2218 if (logging != MagickFalse)
2220 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2221 " Raw tRNS graylevel is %d.",ping_trans_color->gray);
2223 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2224 " scaled graylevel is %d.",transparent_color.opacity);
2226 transparent_color.red=transparent_color.opacity;
2227 transparent_color.green=transparent_color.opacity;
2228 transparent_color.blue=transparent_color.opacity;
2232 #if defined(PNG_READ_sBIT_SUPPORTED)
2233 if (mng_info->have_global_sbit)
2235 if (!png_get_valid(ping,ping_info,PNG_INFO_sBIT))
2236 png_set_sBIT(ping,ping_info,&mng_info->global_sbit);
2239 num_passes=png_set_interlace_handling(ping);
2241 png_read_update_info(ping,ping_info);
2243 ping_rowbytes=png_get_rowbytes(ping,ping_info);
2246 Initialize image structure.
2248 mng_info->image_box.left=0;
2249 mng_info->image_box.right=(ssize_t) ping_width;
2250 mng_info->image_box.top=0;
2251 mng_info->image_box.bottom=(ssize_t) ping_height;
2252 if (mng_info->mng_type == 0)
2254 mng_info->mng_width=ping_width;
2255 mng_info->mng_height=ping_height;
2256 mng_info->frame=mng_info->image_box;
2257 mng_info->clip=mng_info->image_box;
2262 image->page.y=mng_info->y_off[mng_info->object_id];
2265 image->compression=ZipCompression;
2266 image->columns=ping_width;
2267 image->rows=ping_height;
2268 if (((int) ping_color_type == PNG_COLOR_TYPE_PALETTE) ||
2269 ((int) ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA) ||
2270 ((int) ping_color_type == PNG_COLOR_TYPE_GRAY))
2275 image->storage_class=PseudoClass;
2277 image->colors=one << ping_bit_depth;
2278 #if (MAGICKCORE_QUANTUM_DEPTH == 8)
2279 if (image->colors > 256)
2282 if (image->colors > 65536L)
2283 image->colors=65536L;
2285 if ((int) ping_color_type == PNG_COLOR_TYPE_PALETTE)
2293 (void) png_get_PLTE(ping,ping_info,&palette,&number_colors);
2294 image->colors=(size_t) number_colors;
2296 if (logging != MagickFalse)
2297 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2298 " Reading PNG PLTE chunk: number_colors: %d.",number_colors);
2302 if (image->storage_class == PseudoClass)
2305 Initialize image colormap.
2307 if (AcquireImageColormap(image,image->colors) == MagickFalse)
2308 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
2310 if ((int) ping_color_type == PNG_COLOR_TYPE_PALETTE)
2318 (void) png_get_PLTE(ping,ping_info,&palette,&number_colors);
2320 for (i=0; i < (ssize_t) image->colors; i++)
2322 image->colormap[i].red=ScaleCharToQuantum(palette[i].red);
2323 image->colormap[i].green=ScaleCharToQuantum(palette[i].green);
2324 image->colormap[i].blue=ScaleCharToQuantum(palette[i].blue);
2333 scale=(QuantumRange/((1UL << ping_bit_depth)-1));
2338 for (i=0; i < (ssize_t) image->colors; i++)
2340 image->colormap[i].red=(Quantum) (i*scale);
2341 image->colormap[i].green=(Quantum) (i*scale);
2342 image->colormap[i].blue=(Quantum) (i*scale);
2347 Read image scanlines.
2349 if (image->delay != 0)
2350 mng_info->scenes_found++;
2352 if ((mng_info->mng_type == 0 && (image->ping != MagickFalse)) || (
2353 (image_info->number_scenes != 0) && (mng_info->scenes_found > (ssize_t)
2354 (image_info->first_scene+image_info->number_scenes))))
2356 if (logging != MagickFalse)
2357 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2358 " Skipping PNG image data for scene %.20g",(double)
2359 mng_info->scenes_found-1);
2360 png_destroy_read_struct(&ping,&ping_info,&end_info);
2361 #if defined(PNG_SETJMP_NOT_THREAD_SAFE)
2362 UnlockSemaphoreInfo(png_semaphore);
2364 if (logging != MagickFalse)
2365 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2366 " exit ReadOnePNGImage().");
2371 if (logging != MagickFalse)
2372 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2373 " Reading PNG IDAT chunk(s)");
2376 png_pixels=(unsigned char *) AcquireQuantumMemory(image->rows,
2377 ping_rowbytes*sizeof(*png_pixels));
2380 png_pixels=(unsigned char *) AcquireQuantumMemory(ping_rowbytes,
2381 sizeof(*png_pixels));
2383 if (png_pixels == (unsigned char *) NULL)
2384 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
2386 if (logging != MagickFalse)
2387 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2388 " Converting PNG pixels to pixel packets");
2390 Convert PNG pixels to pixel packets.
2392 if (setjmp(png_jmpbuf(ping)))
2395 PNG image is corrupt.
2397 png_destroy_read_struct(&ping,&ping_info,&end_info);
2398 #if defined(PNG_SETJMP_NOT_THREAD_SAFE)
2399 UnlockSemaphoreInfo(png_semaphore);
2401 if (quantum_info != (QuantumInfo *) NULL)
2402 quantum_info = DestroyQuantumInfo(quantum_info);
2404 if (png_pixels != (unsigned char *) NULL)
2405 png_pixels=(unsigned char *) RelinquishMagickMemory(png_pixels);
2407 if (logging != MagickFalse)
2408 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2409 " exit ReadOnePNGImage() with error.");
2411 if (image != (Image *) NULL)
2413 InheritException(exception,&image->exception);
2417 return(GetFirstImageInList(image));
2420 quantum_info=AcquireQuantumInfo(image_info,image);
2422 if (quantum_info == (QuantumInfo *) NULL)
2423 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
2428 found_transparent_pixel;
2430 found_transparent_pixel=MagickFalse;
2432 if (image->storage_class == DirectClass)
2434 for (pass=0; pass < num_passes; pass++)
2437 Convert image to DirectClass pixel packets.
2439 #if (MAGICKCORE_QUANTUM_DEPTH == 8)
2443 depth=(ssize_t) ping_bit_depth;
2445 image->matte=(((int) ping_color_type == PNG_COLOR_TYPE_RGB_ALPHA) ||
2446 ((int) ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA) ||
2447 (png_get_valid(ping,ping_info,PNG_INFO_tRNS))) ?
2448 MagickTrue : MagickFalse;
2450 for (y=0; y < (ssize_t) image->rows; y++)
2453 row_offset=ping_rowbytes*y;
2458 png_read_row(ping,png_pixels+row_offset,NULL);
2459 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
2461 if (q == (PixelPacket *) NULL)
2464 #if (0 && (MAGICKCORE_QUANTUM_DEPTH == 8) && !defined(MAGICKCORE_HDRI_SUPPORT))
2465 /* code deleted from version 6.6.6-8 */
2466 #else /* (MAGICKCORE_QUANTUM_DEPTH != 8) */
2468 if ((int) ping_color_type == PNG_COLOR_TYPE_GRAY)
2469 (void) ImportQuantumPixels(image,(CacheView *) NULL,quantum_info,
2470 GrayQuantum,png_pixels+row_offset,exception);
2472 else if ((int) ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
2473 (void) ImportQuantumPixels(image,(CacheView *) NULL,quantum_info,
2474 GrayAlphaQuantum,png_pixels+row_offset,exception);
2476 else if ((int) ping_color_type == PNG_COLOR_TYPE_RGB_ALPHA)
2477 (void) ImportQuantumPixels(image,(CacheView *) NULL,quantum_info,
2478 RGBAQuantum,png_pixels+row_offset,exception);
2480 else if ((int) ping_color_type == PNG_COLOR_TYPE_PALETTE)
2481 (void) ImportQuantumPixels(image,(CacheView *) NULL,quantum_info,
2482 IndexQuantum,png_pixels+row_offset,exception);
2484 else /* ping_color_type == PNG_COLOR_TYPE_RGB */
2485 (void) ImportQuantumPixels(image,(CacheView *) NULL,quantum_info,
2486 RGBQuantum,png_pixels+row_offset,exception);
2488 if (found_transparent_pixel == MagickFalse)
2490 /* Is there a transparent pixel in the row? */
2491 for (x=(ssize_t) image->columns-1; x >= 0; x--)
2493 if ((ping_color_type == PNG_COLOR_TYPE_RGBA ||
2494 ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA) &&
2495 (q->opacity != OpaqueOpacity))
2497 found_transparent_pixel = MagickTrue;
2500 if ((ping_color_type == PNG_COLOR_TYPE_RGB ||
2501 ping_color_type == PNG_COLOR_TYPE_GRAY) &&
2502 (q->red == transparent_color.red &&
2503 q->green == transparent_color.green &&
2504 q->blue == transparent_color.blue))
2506 found_transparent_pixel = MagickTrue;
2513 if ((image->previous == (Image *) NULL) && (num_passes == 1))
2515 status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
2518 if (status == MagickFalse)
2521 if (SyncAuthenticPixels(image,exception) == MagickFalse)
2525 if ((image->previous == (Image *) NULL) && (num_passes != 1))
2527 status=SetImageProgress(image,LoadImageTag,pass,num_passes);
2528 if (status == MagickFalse)
2534 else /* image->storage_class != DirectClass */
2536 for (pass=0; pass < num_passes; pass++)
2545 Convert grayscale image to PseudoClass pixel packets.
2547 image->matte=ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA ?
2548 MagickTrue : MagickFalse;
2550 quantum_scanline=(Quantum *) AcquireQuantumMemory(image->columns,
2551 (image->matte ? 2 : 1)*sizeof(*quantum_scanline));
2553 if (quantum_scanline == (Quantum *) NULL)
2554 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
2556 for (y=0; y < (ssize_t) image->rows; y++)
2559 row_offset=ping_rowbytes*y;
2564 png_read_row(ping,png_pixels+row_offset,NULL);
2565 q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
2567 if (q == (PixelPacket *) NULL)
2570 indexes=GetAuthenticIndexQueue(image);
2571 p=png_pixels+row_offset;
2574 switch (ping_bit_depth)
2581 for (x=(ssize_t) image->columns-7; x > 0; x-=8)
2583 for (bit=7; bit >= 0; bit--)
2584 *r++=(Quantum) ((*p) & (0x01 << bit) ? 0x01 : 0x00);
2588 if ((image->columns % 8) != 0)
2590 for (bit=7; bit >= (ssize_t) (8-(image->columns % 8)); bit--)
2591 *r++=(Quantum) ((*p) & (0x01 << bit) ? 0x01 : 0x00);
2599 for (x=(ssize_t) image->columns-3; x > 0; x-=4)
2601 *r++=(*p >> 6) & 0x03;
2602 *r++=(*p >> 4) & 0x03;
2603 *r++=(*p >> 2) & 0x03;
2607 if ((image->columns % 4) != 0)
2609 for (i=3; i >= (ssize_t) (4-(image->columns % 4)); i--)
2610 *r++=(Quantum) ((*p >> (i*2)) & 0x03);
2618 for (x=(ssize_t) image->columns-1; x > 0; x-=2)
2620 *r++=(*p >> 4) & 0x0f;
2624 if ((image->columns % 2) != 0)
2625 *r++=(*p++ >> 4) & 0x0f;
2632 if (ping_color_type == 4)
2633 for (x=(ssize_t) image->columns-1; x >= 0; x--)
2636 /* In image.h, OpaqueOpacity is 0
2637 * TransparentOpacity is QuantumRange
2638 * In a PNG datastream, Opaque is QuantumRange
2639 * and Transparent is 0.
2641 q->opacity=ScaleCharToQuantum((unsigned char) (255-(*p++)));
2642 if (q->opacity != OpaqueOpacity)
2643 found_transparent_pixel = MagickTrue;
2648 for (x=(ssize_t) image->columns-1; x >= 0; x--)
2656 for (x=(ssize_t) image->columns-1; x >= 0; x--)
2658 #if (MAGICKCORE_QUANTUM_DEPTH == 16)
2662 if (image->colors > 256)
2670 *r=(Quantum) quantum;
2673 if (ping_color_type == 4)
2675 quantum=((*p++) << 8);
2677 q->opacity=(Quantum) (QuantumRange-quantum);
2678 if (q->opacity != OpaqueOpacity)
2679 found_transparent_pixel = MagickTrue;
2683 #if (MAGICKCORE_QUANTUM_DEPTH == 32)
2687 if (image->colors > 256)
2698 if (ping_color_type == 4)
2700 q->opacity=(*p << 8) | *(p+1);
2702 q->opacity=(Quantum) GetAlphaPixelComponent(q);
2703 if (q->opacity != OpaqueOpacity)
2704 found_transparent_pixel = MagickTrue;
2709 #else /* MAGICKCORE_QUANTUM_DEPTH == 8 */
2711 p++; /* strip low byte */
2713 if (ping_color_type == 4)
2715 q->opacity=(Quantum) (QuantumRange-(*p++));
2716 if (q->opacity != OpaqueOpacity)
2717 found_transparent_pixel = MagickTrue;
2732 Transfer image scanline.
2736 for (x=0; x < (ssize_t) image->columns; x++)
2737 indexes[x]=(IndexPacket) (*r++);
2739 if (SyncAuthenticPixels(image,exception) == MagickFalse)
2742 if ((image->previous == (Image *) NULL) && (num_passes == 1))
2744 status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
2747 if (status == MagickFalse)
2752 if ((image->previous == (Image *) NULL) && (num_passes != 1))
2754 status=SetImageProgress(image,LoadImageTag,pass,num_passes);
2756 if (status == MagickFalse)
2760 quantum_scanline=(Quantum *) RelinquishMagickMemory(quantum_scanline);
2763 image->matte=found_transparent_pixel;
2765 if (logging != MagickFalse)
2767 if (found_transparent_pixel != MagickFalse)
2768 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2769 " Found transparent pixel");
2772 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2773 " No transparent pixel was found");
2774 ping_color_type&=0x03;
2779 if (quantum_info != (QuantumInfo *) NULL)
2780 quantum_info=DestroyQuantumInfo(quantum_info);
2782 if (image->storage_class == PseudoClass)
2788 image->matte=MagickFalse;
2789 (void) SyncImage(image);
2793 png_read_end(ping,ping_info);
2795 if (image_info->number_scenes != 0 && mng_info->scenes_found-1 <
2796 (ssize_t) image_info->first_scene && image->delay != 0)
2798 png_destroy_read_struct(&ping,&ping_info,&end_info);
2799 png_pixels=(unsigned char *) RelinquishMagickMemory(png_pixels);
2801 (void) SetImageBackgroundColor(image);
2802 #if defined(PNG_SETJMP_NOT_THREAD_SAFE)
2803 UnlockSemaphoreInfo(png_semaphore);
2805 if (logging != MagickFalse)
2806 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2807 " exit ReadOnePNGImage() early.");
2811 if (png_get_valid(ping,ping_info,PNG_INFO_tRNS))
2817 Image has a transparent background.
2819 storage_class=image->storage_class;
2820 image->matte=MagickTrue;
2822 /* Balfour fix from imagemagick discourse server, 5 Feb 2010 */
2824 if (storage_class == PseudoClass)
2826 if ((int) ping_color_type == PNG_COLOR_TYPE_PALETTE)
2828 for (x=0; x < ping_num_trans; x++)
2830 image->colormap[x].opacity =
2831 ScaleCharToQuantum((unsigned char)(255-ping_trans_alpha[x]));
2835 else if (ping_color_type == PNG_COLOR_TYPE_GRAY)
2837 for (x=0; x < (int) image->colors; x++)
2839 if (ScaleQuantumToShort(image->colormap[x].red) ==
2840 transparent_color.opacity)
2842 image->colormap[x].opacity = (Quantum) TransparentOpacity;
2846 (void) SyncImage(image);
2851 for (y=0; y < (ssize_t) image->rows; y++)
2853 image->storage_class=storage_class;
2854 q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
2856 if (q == (PixelPacket *) NULL)
2859 indexes=GetAuthenticIndexQueue(image);
2861 for (x=(ssize_t) image->columns-1; x >= 0; x--)
2863 if (ScaleQuantumToChar(q->red) == transparent_color.red &&
2864 ScaleQuantumToChar(q->green) == transparent_color.green &&
2865 ScaleQuantumToChar(q->blue) == transparent_color.blue)
2867 q->opacity=(Quantum) TransparentOpacity;
2872 q->opacity=(Quantum) OpaqueOpacity;
2878 if (SyncAuthenticPixels(image,exception) == MagickFalse)
2883 image->storage_class=DirectClass;
2886 if ((ping_color_type == PNG_COLOR_TYPE_GRAY) ||
2887 (ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA))
2888 image->colorspace=GRAYColorspace;
2890 if (png_get_text(ping,ping_info,&text,&num_text) != 0)
2891 for (i=0; i < (ssize_t) num_text; i++)
2893 /* Check for a profile */
2895 if (logging != MagickFalse)
2896 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2897 " Reading PNG text chunk");
2899 if (memcmp(text[i].key, "Raw profile type ",17) == 0)
2900 (void) png_read_raw_profile(image,image_info,text,(int) i);
2907 length=text[i].text_length;
2908 value=(char *) AcquireQuantumMemory(length+MaxTextExtent,
2910 if (value == (char *) NULL)
2912 (void) ThrowMagickException(&image->exception,GetMagickModule(),
2913 ResourceLimitError,"MemoryAllocationFailed","`%s'",
2918 (void) ConcatenateMagickString(value,text[i].text,length+2);
2919 (void) SetImageProperty(image,text[i].key,value);
2921 if (logging != MagickFalse)
2922 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2923 " Keyword: %s",text[i].key);
2925 value=DestroyString(value);
2929 #ifdef MNG_OBJECT_BUFFERS
2931 Store the object if necessary.
2933 if (object_id && !mng_info->frozen[object_id])
2935 if (mng_info->ob[object_id] == (MngBuffer *) NULL)
2938 create a new object buffer.
2940 mng_info->ob[object_id]=(MngBuffer *)
2941 AcquireMagickMemory(sizeof(MngBuffer));
2943 if (mng_info->ob[object_id] != (MngBuffer *) NULL)
2945 mng_info->ob[object_id]->image=(Image *) NULL;
2946 mng_info->ob[object_id]->reference_count=1;
2950 if ((mng_info->ob[object_id] == (MngBuffer *) NULL) ||
2951 mng_info->ob[object_id]->frozen)
2953 if (mng_info->ob[object_id] == (MngBuffer *) NULL)
2954 (void) ThrowMagickException(&image->exception,GetMagickModule(),
2955 ResourceLimitError,"MemoryAllocationFailed","`%s'",
2958 if (mng_info->ob[object_id]->frozen)
2959 (void) ThrowMagickException(&image->exception,GetMagickModule(),
2960 ResourceLimitError,"Cannot overwrite frozen MNG object buffer",
2961 "`%s'",image->filename);
2967 if (mng_info->ob[object_id]->image != (Image *) NULL)
2968 mng_info->ob[object_id]->image=DestroyImage
2969 (mng_info->ob[object_id]->image);
2971 mng_info->ob[object_id]->image=CloneImage(image,0,0,MagickTrue,
2974 if (mng_info->ob[object_id]->image != (Image *) NULL)
2975 mng_info->ob[object_id]->image->file=(FILE *) NULL;
2978 (void) ThrowMagickException(&image->exception,GetMagickModule(),
2979 ResourceLimitError,"Cloning image for object buffer failed",
2980 "`%s'",image->filename);
2982 if (ping_width > 250000L || ping_height > 250000L)
2983 png_error(ping,"PNG Image dimensions are too large.");
2985 mng_info->ob[object_id]->width=ping_width;
2986 mng_info->ob[object_id]->height=ping_height;
2987 mng_info->ob[object_id]->color_type=ping_color_type;
2988 mng_info->ob[object_id]->sample_depth=ping_bit_depth;
2989 mng_info->ob[object_id]->interlace_method=ping_interlace_method;
2990 mng_info->ob[object_id]->compression_method=
2991 ping_compression_method;
2992 mng_info->ob[object_id]->filter_method=ping_filter_method;
2994 if (png_get_valid(ping,ping_info,PNG_INFO_PLTE))
3003 Copy the PLTE to the object buffer.
3005 png_get_PLTE(ping,ping_info,&plte,&number_colors);
3006 mng_info->ob[object_id]->plte_length=number_colors;
3008 for (i=0; i < number_colors; i++)
3010 mng_info->ob[object_id]->plte[i]=plte[i];
3015 mng_info->ob[object_id]->plte_length=0;
3020 Relinquish resources.
3022 png_destroy_read_struct(&ping,&ping_info,&end_info);
3024 png_pixels=(unsigned char *) RelinquishMagickMemory(png_pixels);
3025 #if defined(PNG_SETJMP_NOT_THREAD_SAFE)
3026 UnlockSemaphoreInfo(png_semaphore);
3029 if (logging != MagickFalse)
3030 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3031 " exit ReadOnePNGImage()");
3035 /* end of reading one PNG image */
3038 static Image *ReadPNGImage(const ImageInfo *image_info,ExceptionInfo *exception)
3053 magic_number[MaxTextExtent];
3061 assert(image_info != (const ImageInfo *) NULL);
3062 assert(image_info->signature == MagickSignature);
3064 if (image_info->debug != MagickFalse)
3065 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
3066 image_info->filename);
3068 assert(exception != (ExceptionInfo *) NULL);
3069 assert(exception->signature == MagickSignature);
3070 logging=LogMagickEvent(CoderEvent,GetMagickModule(),"enter ReadPNGImage()");
3071 image=AcquireImage(image_info);
3072 mng_info=(MngInfo *) NULL;
3073 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
3075 if (status == MagickFalse)
3076 ThrowReaderException(FileOpenError,"UnableToOpenFile");
3079 Verify PNG signature.
3081 count=ReadBlob(image,8,(unsigned char *) magic_number);
3083 if (memcmp(magic_number,"\211PNG\r\n\032\n",8) != 0)
3084 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
3087 Allocate a MngInfo structure.
3089 have_mng_structure=MagickFalse;
3090 mng_info=(MngInfo *) AcquireMagickMemory(sizeof(MngInfo));
3092 if (mng_info == (MngInfo *) NULL)
3093 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
3096 Initialize members of the MngInfo structure.
3098 (void) ResetMagickMemory(mng_info,0,sizeof(MngInfo));
3099 mng_info->image=image;
3100 have_mng_structure=MagickTrue;
3103 image=ReadOnePNGImage(mng_info,image_info,exception);
3104 MngInfoFreeStruct(mng_info,&have_mng_structure);
3106 if (image == (Image *) NULL)
3108 if (previous != (Image *) NULL)
3110 if (previous->signature != MagickSignature)
3111 ThrowReaderException(CorruptImageError,"CorruptImage");
3113 (void) CloseBlob(previous);
3114 (void) DestroyImageList(previous);
3117 if (logging != MagickFalse)
3118 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3119 "exit ReadPNGImage() with error");
3121 return((Image *) NULL);
3124 (void) CloseBlob(image);
3126 if ((image->columns == 0) || (image->rows == 0))
3128 if (logging != MagickFalse)
3129 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3130 "exit ReadPNGImage() with error.");
3132 ThrowReaderException(CorruptImageError,"CorruptImage");
3135 if (LocaleCompare(image_info->magick,"PNG8") == 0)
3137 (void) SetImageType(image,PaletteType);
3139 if (image->matte != MagickFalse)
3141 /* To do: Reduce to binary transparency */
3145 if (LocaleCompare(image_info->magick,"PNG24") == 0)
3147 (void) SetImageType(image,TrueColorType);
3148 image->matte=MagickFalse;
3151 if (LocaleCompare(image_info->magick,"PNG32") == 0)
3152 (void) SetImageType(image,TrueColorMatteType);
3154 if (logging != MagickFalse)
3155 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"exit ReadPNGImage()");
3162 #if defined(JNG_SUPPORTED)
3164 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3168 % R e a d O n e J N G I m a g e %
3172 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3174 % ReadOneJNGImage() reads a JPEG Network Graphics (JNG) image file
3175 % (minus the 8-byte signature) and returns it. It allocates the memory
3176 % necessary for the new Image structure and returns a pointer to the new
3179 % JNG support written by Glenn Randers-Pehrson, glennrp@image...
3181 % The format of the ReadOneJNGImage method is:
3183 % Image *ReadOneJNGImage(MngInfo *mng_info, const ImageInfo *image_info,
3184 % ExceptionInfo *exception)
3186 % A description of each parameter follows:
3188 % o mng_info: Specifies a pointer to a MngInfo structure.
3190 % o image_info: the image info.
3192 % o exception: return any errors or warnings in this structure.
3195 static Image *ReadOneJNGImage(MngInfo *mng_info,
3196 const ImageInfo *image_info, ExceptionInfo *exception)
3223 jng_image_sample_depth,
3224 jng_image_compression_method,
3225 jng_image_interlace_method,
3226 jng_alpha_sample_depth,
3227 jng_alpha_compression_method,
3228 jng_alpha_filter_method,
3229 jng_alpha_interlace_method;
3231 register const PixelPacket
3238 register PixelPacket
3241 register unsigned char
3252 jng_alpha_compression_method=0;
3253 jng_alpha_sample_depth=8;
3257 alpha_image=(Image *) NULL;
3258 color_image=(Image *) NULL;
3259 alpha_image_info=(ImageInfo *) NULL;
3260 color_image_info=(ImageInfo *) NULL;
3262 logging=LogMagickEvent(CoderEvent,GetMagickModule(),
3263 " enter ReadOneJNGImage()");
3265 image=mng_info->image;
3267 if (GetAuthenticPixelQueue(image) != (PixelPacket *) NULL)
3270 Allocate next image structure.
3272 if (logging != MagickFalse)
3273 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3274 " AcquireNextImage()");
3276 AcquireNextImage(image_info,image);
3278 if (GetNextImageInList(image) == (Image *) NULL)
3279 return((Image *) NULL);
3281 image=SyncNextImageInList(image);
3283 mng_info->image=image;
3286 Signature bytes have already been read.
3289 read_JSEP=MagickFalse;
3290 reading_idat=MagickFalse;
3291 skip_to_iend=MagickFalse;
3295 type[MaxTextExtent];
3304 Read a new JNG chunk.
3306 status=SetImageProgress(image,LoadImagesTag,TellBlob(image),
3307 2*GetBlobSize(image));
3309 if (status == MagickFalse)
3313 (void) ConcatenateMagickString(type,"errr",MaxTextExtent);
3314 length=ReadBlobMSBLong(image);
3315 count=(unsigned int) ReadBlob(image,4,(unsigned char *) type);
3317 if (logging != MagickFalse)
3318 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3319 " Reading JNG chunk type %c%c%c%c, length: %.20g",
3320 type[0],type[1],type[2],type[3],(double) length);
3322 if (length > PNG_UINT_31_MAX || count == 0)
3323 ThrowReaderException(CorruptImageError,"CorruptImage");
3326 chunk=(unsigned char *) NULL;
3330 chunk=(unsigned char *) AcquireQuantumMemory(length,sizeof(*chunk));
3332 if (chunk == (unsigned char *) NULL)
3333 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
3335 for (i=0; i < (ssize_t) length; i++)
3336 chunk[i]=(unsigned char) ReadBlobByte(image);
3341 (void) ReadBlobMSBLong(image); /* read crc word */
3346 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
3351 if (memcmp(type,mng_JHDR,4) == 0)
3355 jng_width=(size_t) ((p[0] << 24) | (p[1] << 16) |
3356 (p[2] << 8) | p[3]);
3357 jng_height=(size_t) ((p[4] << 24) | (p[5] << 16) |
3358 (p[6] << 8) | p[7]);
3359 jng_color_type=p[8];
3360 jng_image_sample_depth=p[9];
3361 jng_image_compression_method=p[10];
3362 jng_image_interlace_method=p[11];
3364 image->interlace=jng_image_interlace_method != 0 ? PNGInterlace :
3367 jng_alpha_sample_depth=p[12];
3368 jng_alpha_compression_method=p[13];
3369 jng_alpha_filter_method=p[14];
3370 jng_alpha_interlace_method=p[15];
3372 if (logging != MagickFalse)
3374 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3375 " jng_width: %16lu",(unsigned long) jng_width);
3377 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3378 " jng_width: %16lu",(unsigned long) jng_height);
3380 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3381 " jng_color_type: %16d",jng_color_type);
3383 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3384 " jng_image_sample_depth: %3d",
3385 jng_image_sample_depth);
3387 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3388 " jng_image_compression_method:%3d",
3389 jng_image_compression_method);
3391 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3392 " jng_image_interlace_method: %3d",
3393 jng_image_interlace_method);
3395 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3396 " jng_alpha_sample_depth: %3d",
3397 jng_alpha_sample_depth);
3399 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3400 " jng_alpha_compression_method:%3d",
3401 jng_alpha_compression_method);
3403 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3404 " jng_alpha_filter_method: %3d",
3405 jng_alpha_filter_method);
3407 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3408 " jng_alpha_interlace_method: %3d",
3409 jng_alpha_interlace_method);
3414 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
3420 if ((reading_idat == MagickFalse) && (read_JSEP == MagickFalse) &&
3421 ((memcmp(type,mng_JDAT,4) == 0) || (memcmp(type,mng_JdAA,4) == 0) ||
3422 (memcmp(type,mng_IDAT,4) == 0) || (memcmp(type,mng_JDAA,4) == 0)))
3425 o create color_image
3426 o open color_blob, attached to color_image
3427 o if (color type has alpha)
3428 open alpha_blob, attached to alpha_image
3431 color_image_info=(ImageInfo *)AcquireMagickMemory(sizeof(ImageInfo));
3433 if (color_image_info == (ImageInfo *) NULL)
3434 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
3436 GetImageInfo(color_image_info);
3437 color_image=AcquireImage(color_image_info);
3439 if (color_image == (Image *) NULL)
3440 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
3442 if (logging != MagickFalse)
3443 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3444 " Creating color_blob.");
3446 (void) AcquireUniqueFilename(color_image->filename);
3447 status=OpenBlob(color_image_info,color_image,WriteBinaryBlobMode,
3450 if (status == MagickFalse)
3451 return((Image *) NULL);
3453 if ((image_info->ping == MagickFalse) && (jng_color_type >= 12))
3455 alpha_image_info=(ImageInfo *)
3456 AcquireMagickMemory(sizeof(ImageInfo));
3458 if (alpha_image_info == (ImageInfo *) NULL)
3459 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
3461 GetImageInfo(alpha_image_info);
3462 alpha_image=AcquireImage(alpha_image_info);
3464 if (alpha_image == (Image *) NULL)
3466 alpha_image=DestroyImage(alpha_image);
3467 ThrowReaderException(ResourceLimitError,
3468 "MemoryAllocationFailed");
3471 if (logging != MagickFalse)
3472 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3473 " Creating alpha_blob.");
3475 (void) AcquireUniqueFilename(alpha_image->filename);
3476 status=OpenBlob(alpha_image_info,alpha_image,WriteBinaryBlobMode,
3479 if (status == MagickFalse)
3480 return((Image *) NULL);
3482 if (jng_alpha_compression_method == 0)
3487 if (logging != MagickFalse)
3488 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3489 " Writing IHDR chunk to alpha_blob.");
3491 (void) WriteBlob(alpha_image,8,(const unsigned char *)
3492 "\211PNG\r\n\032\n");
3494 (void) WriteBlobMSBULong(alpha_image,13L);
3495 PNGType(data,mng_IHDR);
3496 LogPNGChunk(logging,mng_IHDR,13L);
3497 PNGLong(data+4,jng_width);
3498 PNGLong(data+8,jng_height);
3499 data[12]=jng_alpha_sample_depth;
3500 data[13]=0; /* color_type gray */
3501 data[14]=0; /* compression method 0 */
3502 data[15]=0; /* filter_method 0 */
3503 data[16]=0; /* interlace_method 0 */
3504 (void) WriteBlob(alpha_image,17,data);
3505 (void) WriteBlobMSBULong(alpha_image,crc32(0,data,17));
3508 reading_idat=MagickTrue;
3511 if (memcmp(type,mng_JDAT,4) == 0)
3513 /* Copy chunk to color_image->blob */
3515 if (logging != MagickFalse)
3516 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3517 " Copying JDAT chunk data to color_blob.");
3519 (void) WriteBlob(color_image,length,chunk);
3522 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
3527 if (memcmp(type,mng_IDAT,4) == 0)
3532 /* Copy IDAT header and chunk data to alpha_image->blob */
3534 if (image_info->ping == MagickFalse)
3536 if (logging != MagickFalse)
3537 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3538 " Copying IDAT chunk data to alpha_blob.");
3540 (void) WriteBlobMSBULong(alpha_image,(size_t) length);
3541 PNGType(data,mng_IDAT);
3542 LogPNGChunk(logging,mng_IDAT,length);
3543 (void) WriteBlob(alpha_image,4,data);
3544 (void) WriteBlob(alpha_image,length,chunk);
3545 (void) WriteBlobMSBULong(alpha_image,
3546 crc32(crc32(0,data,4),chunk,(uInt) length));
3550 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
3555 if ((memcmp(type,mng_JDAA,4) == 0) || (memcmp(type,mng_JdAA,4) == 0))
3557 /* Copy chunk data to alpha_image->blob */
3559 if (image_info->ping == MagickFalse)
3561 if (logging != MagickFalse)
3562 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3563 " Copying JDAA chunk data to alpha_blob.");
3565 (void) WriteBlob(alpha_image,length,chunk);
3569 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
3574 if (memcmp(type,mng_JSEP,4) == 0)
3576 read_JSEP=MagickTrue;
3579 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
3584 if (memcmp(type,mng_bKGD,4) == 0)
3588 image->background_color.red=ScaleCharToQuantum(p[1]);
3589 image->background_color.green=image->background_color.red;
3590 image->background_color.blue=image->background_color.red;
3595 image->background_color.red=ScaleCharToQuantum(p[1]);
3596 image->background_color.green=ScaleCharToQuantum(p[3]);
3597 image->background_color.blue=ScaleCharToQuantum(p[5]);
3600 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
3604 if (memcmp(type,mng_gAMA,4) == 0)
3607 image->gamma=((float) mng_get_long(p))*0.00001;
3609 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
3613 if (memcmp(type,mng_cHRM,4) == 0)
3617 image->chromaticity.white_point.x=0.00001*mng_get_long(p);
3618 image->chromaticity.white_point.y=0.00001*mng_get_long(&p[4]);
3619 image->chromaticity.red_primary.x=0.00001*mng_get_long(&p[8]);
3620 image->chromaticity.red_primary.y=0.00001*mng_get_long(&p[12]);
3621 image->chromaticity.green_primary.x=0.00001*mng_get_long(&p[16]);
3622 image->chromaticity.green_primary.y=0.00001*mng_get_long(&p[20]);
3623 image->chromaticity.blue_primary.x=0.00001*mng_get_long(&p[24]);
3624 image->chromaticity.blue_primary.y=0.00001*mng_get_long(&p[28]);
3627 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
3631 if (memcmp(type,mng_sRGB,4) == 0)
3635 image->rendering_intent=
3636 PNG_RenderingIntent_to_Magick_RenderingIntent(p[0]);
3637 image->gamma=0.45455f;
3638 image->chromaticity.red_primary.x=0.6400f;
3639 image->chromaticity.red_primary.y=0.3300f;
3640 image->chromaticity.green_primary.x=0.3000f;
3641 image->chromaticity.green_primary.y=0.6000f;
3642 image->chromaticity.blue_primary.x=0.1500f;
3643 image->chromaticity.blue_primary.y=0.0600f;
3644 image->chromaticity.white_point.x=0.3127f;
3645 image->chromaticity.white_point.y=0.3290f;
3648 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
3652 if (memcmp(type,mng_oFFs,4) == 0)
3656 image->page.x=mng_get_long(p);
3657 image->page.y=mng_get_long(&p[4]);
3659 if ((int) p[8] != 0)
3661 image->page.x/=10000;
3662 image->page.y/=10000;
3667 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
3672 if (memcmp(type,mng_pHYs,4) == 0)
3676 image->x_resolution=(double) mng_get_long(p);
3677 image->y_resolution=(double) mng_get_long(&p[4]);
3678 if ((int) p[8] == PNG_RESOLUTION_METER)
3680 image->units=PixelsPerCentimeterResolution;
3681 image->x_resolution=image->x_resolution/100.0f;
3682 image->y_resolution=image->y_resolution/100.0f;
3686 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
3691 if (memcmp(type,mng_iCCP,4) == 0)
3695 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
3702 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
3704 if (memcmp(type,mng_IEND,4))
3714 Finish up reading image data:
3716 o read main image from color_blob.
3720 o if (color_type has alpha)
3721 if alpha_encoding is PNG
3722 read secondary image from alpha_blob via ReadPNG
3723 if alpha_encoding is JPEG
3724 read secondary image from alpha_blob via ReadJPEG
3728 o copy intensity of secondary image into
3729 opacity samples of main image.
3731 o destroy the secondary image.
3734 (void) CloseBlob(color_image);
3736 if (logging != MagickFalse)
3737 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3738 " Reading jng_image from color_blob.");
3740 (void) FormatMagickString(color_image_info->filename,MaxTextExtent,"%s",
3741 color_image->filename);
3743 color_image_info->ping=MagickFalse; /* To do: avoid this */
3744 jng_image=ReadImage(color_image_info,exception);
3746 if (jng_image == (Image *) NULL)
3747 return((Image *) NULL);
3749 (void) RelinquishUniqueFileResource(color_image->filename);
3750 color_image=DestroyImage(color_image);
3751 color_image_info=DestroyImageInfo(color_image_info);
3753 if (jng_image == (Image *) NULL)
3754 return((Image *) NULL);
3756 if (logging != MagickFalse)
3757 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3758 " Copying jng_image pixels to main image.");
3760 image->rows=jng_height;
3761 image->columns=jng_width;
3762 length=image->columns*sizeof(PixelPacket);
3764 for (y=0; y < (ssize_t) image->rows; y++)
3766 s=GetVirtualPixels(jng_image,0,y,image->columns,1,&image->exception);
3767 q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
3768 (void) CopyMagickMemory(q,s,length);
3770 if (SyncAuthenticPixels(image,exception) == MagickFalse)
3774 jng_image=DestroyImage(jng_image);
3776 if (image_info->ping == MagickFalse)
3778 if (jng_color_type >= 12)
3780 if (jng_alpha_compression_method == 0)
3784 (void) WriteBlobMSBULong(alpha_image,0x00000000L);
3785 PNGType(data,mng_IEND);
3786 LogPNGChunk(logging,mng_IEND,0L);
3787 (void) WriteBlob(alpha_image,4,data);
3788 (void) WriteBlobMSBULong(alpha_image,crc32(0,data,4));
3791 (void) CloseBlob(alpha_image);
3793 if (logging != MagickFalse)
3794 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3795 " Reading opacity from alpha_blob.");
3797 (void) FormatMagickString(alpha_image_info->filename,MaxTextExtent,
3798 "%s",alpha_image->filename);
3800 jng_image=ReadImage(alpha_image_info,exception);
3802 if (jng_image != (Image *) NULL)
3803 for (y=0; y < (ssize_t) image->rows; y++)
3805 s=GetVirtualPixels(jng_image,0,y,image->columns,1,
3807 q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
3809 if (image->matte != MagickFalse)
3810 for (x=(ssize_t) image->columns; x != 0; x--,q++,s++)
3811 q->opacity=(Quantum) QuantumRange-s->red;
3814 for (x=(ssize_t) image->columns; x != 0; x--,q++,s++)
3816 q->opacity=(Quantum) QuantumRange-s->red;
3817 if (q->opacity != OpaqueOpacity)
3818 image->matte=MagickTrue;
3821 if (SyncAuthenticPixels(image,exception) == MagickFalse)
3824 (void) RelinquishUniqueFileResource(alpha_image->filename);
3825 alpha_image=DestroyImage(alpha_image);
3826 alpha_image_info=DestroyImageInfo(alpha_image_info);
3827 if (jng_image != (Image *) NULL)
3828 jng_image=DestroyImage(jng_image);
3832 /* Read the JNG image. */
3834 if (mng_info->mng_type == 0)
3836 mng_info->mng_width=jng_width;
3837 mng_info->mng_height=jng_height;
3840 if (image->page.width == 0 && image->page.height == 0)
3842 image->page.width=jng_width;
3843 image->page.height=jng_height;
3846 if (image->page.x == 0 && image->page.y == 0)
3848 image->page.x=mng_info->x_off[mng_info->object_id];
3849 image->page.y=mng_info->y_off[mng_info->object_id];
3854 image->page.y=mng_info->y_off[mng_info->object_id];
3857 mng_info->image_found++;
3858 status=SetImageProgress(image,LoadImagesTag,2*TellBlob(image),
3859 2*GetBlobSize(image));
3861 if (logging != MagickFalse)
3862 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3863 " exit ReadOneJNGImage()");
3869 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3873 % R e a d J N G I m a g e %
3877 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3879 % ReadJNGImage() reads a JPEG Network Graphics (JNG) image file
3880 % (including the 8-byte signature) and returns it. It allocates the memory
3881 % necessary for the new Image structure and returns a pointer to the new
3884 % JNG support written by Glenn Randers-Pehrson, glennrp@image...
3886 % The format of the ReadJNGImage method is:
3888 % Image *ReadJNGImage(const ImageInfo *image_info, ExceptionInfo
3891 % A description of each parameter follows:
3893 % o image_info: the image info.
3895 % o exception: return any errors or warnings in this structure.
3899 static Image *ReadJNGImage(const ImageInfo *image_info,ExceptionInfo *exception)
3914 magic_number[MaxTextExtent];
3922 assert(image_info != (const ImageInfo *) NULL);
3923 assert(image_info->signature == MagickSignature);
3924 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image_info->filename);
3925 assert(exception != (ExceptionInfo *) NULL);
3926 assert(exception->signature == MagickSignature);
3927 logging=LogMagickEvent(CoderEvent,GetMagickModule(),"enter ReadJNGImage()");
3928 image=AcquireImage(image_info);
3929 mng_info=(MngInfo *) NULL;
3930 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
3932 if (status == MagickFalse)
3933 return((Image *) NULL);
3935 if (LocaleCompare(image_info->magick,"JNG") != 0)
3936 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
3938 /* Verify JNG signature. */
3940 count=(size_t) ReadBlob(image,8,(unsigned char *) magic_number);
3942 if (memcmp(magic_number,"\213JNG\r\n\032\n",8) != 0)
3943 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
3945 /* Allocate a MngInfo structure. */
3947 have_mng_structure=MagickFalse;
3948 mng_info=(MngInfo *) AcquireMagickMemory(sizeof(*mng_info));
3950 if (mng_info == (MngInfo *) NULL)
3951 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
3953 /* Initialize members of the MngInfo structure. */
3955 (void) ResetMagickMemory(mng_info,0,sizeof(MngInfo));
3956 have_mng_structure=MagickTrue;
3958 mng_info->image=image;
3960 image=ReadOneJNGImage(mng_info,image_info,exception);
3961 MngInfoFreeStruct(mng_info,&have_mng_structure);
3963 if (image == (Image *) NULL)
3965 if (IsImageObject(previous) != MagickFalse)
3967 (void) CloseBlob(previous);
3968 (void) DestroyImageList(previous);
3971 if (logging != MagickFalse)
3972 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3973 "exit ReadJNGImage() with error");
3975 return((Image *) NULL);
3977 (void) CloseBlob(image);
3979 if (image->columns == 0 || image->rows == 0)
3981 if (logging != MagickFalse)
3982 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3983 "exit ReadJNGImage() with error");
3985 ThrowReaderException(CorruptImageError,"CorruptImage");
3988 if (logging != MagickFalse)
3989 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"exit ReadJNGImage()");
3995 static Image *ReadMNGImage(const ImageInfo *image_info,ExceptionInfo *exception)
3998 page_geometry[MaxTextExtent];
4031 #if defined(MNG_INSERT_LAYERS)
4033 mng_background_color;
4036 register unsigned char
4051 #if defined(MNG_INSERT_LAYERS)
4056 volatile unsigned int
4057 #ifdef MNG_OBJECT_BUFFERS
4058 mng_background_object=0,
4060 mng_type=0; /* 0: PNG or JNG; 1: MNG; 2: MNG-LC; 3: MNG-VLC */
4063 default_frame_timeout,
4065 #if defined(MNG_INSERT_LAYERS)
4071 /* These delays are all measured in image ticks_per_second,
4072 * not in MNG ticks_per_second
4075 default_frame_delay,
4079 #if defined(MNG_INSERT_LAYERS)
4088 previous_fb.bottom=0;
4090 previous_fb.right=0;
4092 default_fb.bottom=0;
4096 /* Open image file. */
4098 assert(image_info != (const ImageInfo *) NULL);
4099 assert(image_info->signature == MagickSignature);
4100 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image_info->filename);
4101 assert(exception != (ExceptionInfo *) NULL);
4102 assert(exception->signature == MagickSignature);
4103 logging=LogMagickEvent(CoderEvent,GetMagickModule(),"enter ReadMNGImage()");
4104 image=AcquireImage(image_info);
4105 mng_info=(MngInfo *) NULL;
4106 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
4108 if (status == MagickFalse)
4109 return((Image *) NULL);
4111 first_mng_object=MagickFalse;
4113 have_mng_structure=MagickFalse;
4115 /* Allocate a MngInfo structure. */
4117 mng_info=(MngInfo *) AcquireMagickMemory(sizeof(MngInfo));
4119 if (mng_info == (MngInfo *) NULL)
4120 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
4122 /* Initialize members of the MngInfo structure. */
4124 (void) ResetMagickMemory(mng_info,0,sizeof(MngInfo));
4125 mng_info->image=image;
4126 have_mng_structure=MagickTrue;
4128 if (LocaleCompare(image_info->magick,"MNG") == 0)
4131 magic_number[MaxTextExtent];
4133 /* Verify MNG signature. */
4134 count=(size_t) ReadBlob(image,8,(unsigned char *) magic_number);
4135 if (memcmp(magic_number,"\212MNG\r\n\032\n",8) != 0)
4136 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
4138 /* Initialize some nonzero members of the MngInfo structure. */
4139 for (i=0; i < MNG_MAX_OBJECTS; i++)
4141 mng_info->object_clip[i].right=(ssize_t) PNG_UINT_31_MAX;
4142 mng_info->object_clip[i].bottom=(ssize_t) PNG_UINT_31_MAX;
4144 mng_info->exists[0]=MagickTrue;
4147 first_mng_object=MagickTrue;
4149 #if defined(MNG_INSERT_LAYERS)
4150 insert_layers=MagickFalse; /* should be False when converting or mogrifying */
4152 default_frame_delay=0;
4153 default_frame_timeout=0;
4156 mng_info->ticks_per_second=1UL*image->ticks_per_second;
4158 skip_to_iend=MagickFalse;
4159 term_chunk_found=MagickFalse;
4160 mng_info->framing_mode=1;
4161 #if defined(MNG_INSERT_LAYERS)
4162 mandatory_back=MagickFalse;
4164 #if defined(MNG_INSERT_LAYERS)
4165 mng_background_color=image->background_color;
4167 default_fb=mng_info->frame;
4168 previous_fb=mng_info->frame;
4172 type[MaxTextExtent];
4174 if (LocaleCompare(image_info->magick,"MNG") == 0)
4183 (void) ConcatenateMagickString(type,"errr",MaxTextExtent);
4184 length=ReadBlobMSBLong(image);
4185 count=(size_t) ReadBlob(image,4,(unsigned char *) type);
4187 if (logging != MagickFalse)
4188 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4189 " Reading MNG chunk type %c%c%c%c, length: %.20g",
4190 type[0],type[1],type[2],type[3],(double) length);
4192 if (length > PNG_UINT_31_MAX)
4196 ThrowReaderException(CorruptImageError,"CorruptImage");
4199 chunk=(unsigned char *) NULL;
4203 chunk=(unsigned char *) AcquireQuantumMemory(length,sizeof(*chunk));
4205 if (chunk == (unsigned char *) NULL)
4206 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
4208 for (i=0; i < (ssize_t) length; i++)
4209 chunk[i]=(unsigned char) ReadBlobByte(image);
4214 (void) ReadBlobMSBLong(image); /* read crc word */
4216 #if !defined(JNG_SUPPORTED)
4217 if (memcmp(type,mng_JHDR,4) == 0)
4219 skip_to_iend=MagickTrue;
4221 if (mng_info->jhdr_warning == 0)
4222 (void) ThrowMagickException(&image->exception,GetMagickModule(),
4223 CoderError,"JNGCompressNotSupported","`%s'",image->filename);
4225 mng_info->jhdr_warning++;
4228 if (memcmp(type,mng_DHDR,4) == 0)
4230 skip_to_iend=MagickTrue;
4232 if (mng_info->dhdr_warning == 0)
4233 (void) ThrowMagickException(&image->exception,GetMagickModule(),
4234 CoderError,"DeltaPNGNotSupported","`%s'",image->filename);
4236 mng_info->dhdr_warning++;
4238 if (memcmp(type,mng_MEND,4) == 0)
4243 if (memcmp(type,mng_IEND,4) == 0)
4244 skip_to_iend=MagickFalse;
4247 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4249 if (logging != MagickFalse)
4250 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4256 if (memcmp(type,mng_MHDR,4) == 0)
4258 mng_info->mng_width=(size_t) ((p[0] << 24) | (p[1] << 16) |
4259 (p[2] << 8) | p[3]);
4261 mng_info->mng_height=(size_t) ((p[4] << 24) | (p[5] << 16) |
4262 (p[6] << 8) | p[7]);
4264 if (logging != MagickFalse)
4266 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4267 " MNG width: %.20g",(double) mng_info->mng_width);
4268 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4269 " MNG height: %.20g",(double) mng_info->mng_height);
4273 mng_info->ticks_per_second=(size_t) mng_get_long(p);
4275 if (mng_info->ticks_per_second == 0)
4276 default_frame_delay=0;
4279 default_frame_delay=1UL*image->ticks_per_second/
4280 mng_info->ticks_per_second;
4282 frame_delay=default_frame_delay;
4288 simplicity=(size_t) mng_get_long(p);
4291 mng_type=1; /* Full MNG */
4293 if ((simplicity != 0) && ((simplicity | 11) == 11))
4294 mng_type=2; /* LC */
4296 if ((simplicity != 0) && ((simplicity | 9) == 9))
4297 mng_type=3; /* VLC */
4299 #if defined(MNG_INSERT_LAYERS)
4301 insert_layers=MagickTrue;
4303 if (GetAuthenticPixelQueue(image) != (PixelPacket *) NULL)
4305 /* Allocate next image structure. */
4306 AcquireNextImage(image_info,image);
4308 if (GetNextImageInList(image) == (Image *) NULL)
4309 return((Image *) NULL);
4311 image=SyncNextImageInList(image);
4312 mng_info->image=image;
4315 if ((mng_info->mng_width > 65535L) ||
4316 (mng_info->mng_height > 65535L))
4317 ThrowReaderException(ImageError,"WidthOrHeightExceedsLimit");
4319 (void) FormatMagickString(page_geometry,MaxTextExtent,
4320 "%.20gx%.20g+0+0",(double) mng_info->mng_width,(double)
4321 mng_info->mng_height);
4323 mng_info->frame.left=0;
4324 mng_info->frame.right=(ssize_t) mng_info->mng_width;
4325 mng_info->frame.top=0;
4326 mng_info->frame.bottom=(ssize_t) mng_info->mng_height;
4327 mng_info->clip=default_fb=previous_fb=mng_info->frame;
4329 for (i=0; i < MNG_MAX_OBJECTS; i++)
4330 mng_info->object_clip[i]=mng_info->frame;
4332 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4336 if (memcmp(type,mng_TERM,4) == 0)
4347 final_delay=(png_uint_32) mng_get_long(&p[2]);
4348 mng_iterations=(png_uint_32) mng_get_long(&p[6]);
4350 if (mng_iterations == PNG_UINT_31_MAX)
4353 image->iterations=mng_iterations;
4354 term_chunk_found=MagickTrue;
4357 if (logging != MagickFalse)
4359 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4360 " repeat=%d",repeat);
4362 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4363 " final_delay=%.20g",(double) final_delay);
4365 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4366 " image->iterations=%.20g",(double) image->iterations);
4369 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4372 if (memcmp(type,mng_DEFI,4) == 0)
4375 (void) ThrowMagickException(&image->exception,GetMagickModule(),
4376 CoderError,"DEFI chunk found in MNG-VLC datastream","`%s'",
4379 object_id=(p[0] << 8) | p[1];
4381 if (mng_type == 2 && object_id != 0)
4382 (void) ThrowMagickException(&image->exception,GetMagickModule(),
4383 CoderError,"Nonzero object_id in MNG-LC datastream","`%s'",
4386 if (object_id > MNG_MAX_OBJECTS)
4389 Instead ofsuing a warning we should allocate a larger
4390 MngInfo structure and continue.
4392 (void) ThrowMagickException(&image->exception,GetMagickModule(),
4393 CoderError,"object id too large","`%s'",image->filename);
4394 object_id=MNG_MAX_OBJECTS;
4397 if (mng_info->exists[object_id])
4398 if (mng_info->frozen[object_id])
4400 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4401 (void) ThrowMagickException(&image->exception,
4402 GetMagickModule(),CoderError,
4403 "DEFI cannot redefine a frozen MNG object","`%s'",
4408 mng_info->exists[object_id]=MagickTrue;
4411 mng_info->invisible[object_id]=p[2];
4414 Extract object offset info.
4418 mng_info->x_off[object_id]=(ssize_t) ((p[4] << 24) |
4419 (p[5] << 16) | (p[6] << 8) | p[7]);
4421 mng_info->y_off[object_id]=(ssize_t) ((p[8] << 24) |
4422 (p[9] << 16) | (p[10] << 8) | p[11]);
4424 if (logging != MagickFalse)
4426 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4427 " x_off[%d]: %.20g",object_id,(double)
4428 mng_info->x_off[object_id]);
4430 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4431 " y_off[%d]: %.20g",object_id,(double)
4432 mng_info->y_off[object_id]);
4437 Extract object clipping info.
4440 mng_info->object_clip[object_id]=mng_read_box(mng_info->frame,0,
4443 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4446 if (memcmp(type,mng_bKGD,4) == 0)
4448 mng_info->have_global_bkgd=MagickFalse;
4452 mng_info->mng_global_bkgd.red=
4453 ScaleShortToQuantum((unsigned short) ((p[0] << 8) | p[1]));
4455 mng_info->mng_global_bkgd.green=
4456 ScaleShortToQuantum((unsigned short) ((p[2] << 8) | p[3]));
4458 mng_info->mng_global_bkgd.blue=
4459 ScaleShortToQuantum((unsigned short) ((p[4] << 8) | p[5]));
4461 mng_info->have_global_bkgd=MagickTrue;
4464 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4467 if (memcmp(type,mng_BACK,4) == 0)
4469 #if defined(MNG_INSERT_LAYERS)
4471 mandatory_back=p[6];
4476 if (mandatory_back && length > 5)
4478 mng_background_color.red=
4479 ScaleShortToQuantum((unsigned short) ((p[0] << 8) | p[1]));
4481 mng_background_color.green=
4482 ScaleShortToQuantum((unsigned short) ((p[2] << 8) | p[3]));
4484 mng_background_color.blue=
4485 ScaleShortToQuantum((unsigned short) ((p[4] << 8) | p[5]));
4487 mng_background_color.opacity=OpaqueOpacity;
4490 #ifdef MNG_OBJECT_BUFFERS
4492 mng_background_object=(p[7] << 8) | p[8];
4495 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4499 if (memcmp(type,mng_PLTE,4) == 0)
4501 /* Read global PLTE. */
4503 if (length && (length < 769))
4505 if (mng_info->global_plte == (png_colorp) NULL)
4506 mng_info->global_plte=(png_colorp) AcquireQuantumMemory(256,
4507 sizeof(*mng_info->global_plte));
4509 for (i=0; i < (ssize_t) (length/3); i++)
4511 mng_info->global_plte[i].red=p[3*i];
4512 mng_info->global_plte[i].green=p[3*i+1];
4513 mng_info->global_plte[i].blue=p[3*i+2];
4516 mng_info->global_plte_length=(unsigned int) (length/3);
4519 for ( ; i < 256; i++)
4521 mng_info->global_plte[i].red=i;
4522 mng_info->global_plte[i].green=i;
4523 mng_info->global_plte[i].blue=i;
4527 mng_info->global_plte_length=256;
4530 mng_info->global_plte_length=0;
4532 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4536 if (memcmp(type,mng_tRNS,4) == 0)
4538 /* read global tRNS */
4541 for (i=0; i < (ssize_t) length; i++)
4542 mng_info->global_trns[i]=p[i];
4545 for ( ; i < 256; i++)
4546 mng_info->global_trns[i]=255;
4548 mng_info->global_trns_length=(unsigned int) length;
4549 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4552 if (memcmp(type,mng_gAMA,4) == 0)
4559 igamma=mng_get_long(p);
4560 mng_info->global_gamma=((float) igamma)*0.00001;
4561 mng_info->have_global_gama=MagickTrue;
4565 mng_info->have_global_gama=MagickFalse;
4567 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4571 if (memcmp(type,mng_cHRM,4) == 0)
4573 /* Read global cHRM */
4577 mng_info->global_chrm.white_point.x=0.00001*mng_get_long(p);
4578 mng_info->global_chrm.white_point.y=0.00001*mng_get_long(&p[4]);
4579 mng_info->global_chrm.red_primary.x=0.00001*mng_get_long(&p[8]);
4580 mng_info->global_chrm.red_primary.y=0.00001*
4581 mng_get_long(&p[12]);
4582 mng_info->global_chrm.green_primary.x=0.00001*
4583 mng_get_long(&p[16]);
4584 mng_info->global_chrm.green_primary.y=0.00001*
4585 mng_get_long(&p[20]);
4586 mng_info->global_chrm.blue_primary.x=0.00001*
4587 mng_get_long(&p[24]);
4588 mng_info->global_chrm.blue_primary.y=0.00001*
4589 mng_get_long(&p[28]);
4590 mng_info->have_global_chrm=MagickTrue;
4593 mng_info->have_global_chrm=MagickFalse;
4595 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4599 if (memcmp(type,mng_sRGB,4) == 0)
4606 mng_info->global_srgb_intent=
4607 PNG_RenderingIntent_to_Magick_RenderingIntent(p[0]);
4608 mng_info->have_global_srgb=MagickTrue;
4611 mng_info->have_global_srgb=MagickFalse;
4613 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4617 if (memcmp(type,mng_iCCP,4) == 0)
4625 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4630 if (memcmp(type,mng_FRAM,4) == 0)
4633 (void) ThrowMagickException(&image->exception,GetMagickModule(),
4634 CoderError,"FRAM chunk found in MNG-VLC datastream","`%s'",
4637 if ((mng_info->framing_mode == 2) || (mng_info->framing_mode == 4))
4638 image->delay=frame_delay;
4640 frame_delay=default_frame_delay;
4641 frame_timeout=default_frame_timeout;
4646 mng_info->framing_mode=p[0];
4648 if (logging != MagickFalse)
4649 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4650 " Framing_mode=%d",mng_info->framing_mode);
4654 /* Note the delay and frame clipping boundaries. */
4656 p++; /* framing mode */
4658 while (*p && ((p-chunk) < (ssize_t) length))
4659 p++; /* frame name */
4661 p++; /* frame name terminator */
4663 if ((p-chunk) < (ssize_t) (length-4))
4670 change_delay=(*p++);
4671 change_timeout=(*p++);
4672 change_clipping=(*p++);
4673 p++; /* change_sync */
4677 frame_delay=1UL*image->ticks_per_second*
4680 if (mng_info->ticks_per_second != 0)
4681 frame_delay/=mng_info->ticks_per_second;
4684 frame_delay=PNG_UINT_31_MAX;
4686 if (change_delay == 2)
4687 default_frame_delay=frame_delay;
4691 if (logging != MagickFalse)
4692 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4693 " Framing_delay=%.20g",(double) frame_delay);
4698 frame_timeout=1UL*image->ticks_per_second*
4701 if (mng_info->ticks_per_second != 0)
4702 frame_timeout/=mng_info->ticks_per_second;
4705 frame_timeout=PNG_UINT_31_MAX;
4707 if (change_delay == 2)
4708 default_frame_timeout=frame_timeout;
4712 if (logging != MagickFalse)
4713 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4714 " Framing_timeout=%.20g",(double) frame_timeout);
4717 if (change_clipping)
4719 fb=mng_read_box(previous_fb,(char) p[0],&p[1]);
4723 if (logging != MagickFalse)
4724 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4725 " Frame_clip: L=%.20g R=%.20g T=%.20g B=%.20g",
4726 (double) fb.left,(double) fb.right,(double) fb.top,
4727 (double) fb.bottom);
4729 if (change_clipping == 2)
4735 mng_info->clip=mng_minimum_box(fb,mng_info->frame);
4737 subframe_width=(size_t) (mng_info->clip.right
4738 -mng_info->clip.left);
4740 subframe_height=(size_t) (mng_info->clip.bottom
4741 -mng_info->clip.top);
4743 Insert a background layer behind the frame if framing_mode is 4.
4745 #if defined(MNG_INSERT_LAYERS)
4746 if (logging != MagickFalse)
4747 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4748 " subframe_width=%.20g, subframe_height=%.20g",(double)
4749 subframe_width,(double) subframe_height);
4751 if (insert_layers && (mng_info->framing_mode == 4) &&
4752 (subframe_width) && (subframe_height))
4754 /* Allocate next image structure. */
4755 if (GetAuthenticPixelQueue(image) != (PixelPacket *) NULL)
4757 AcquireNextImage(image_info,image);
4759 if (GetNextImageInList(image) == (Image *) NULL)
4761 image=DestroyImageList(image);
4762 MngInfoFreeStruct(mng_info,&have_mng_structure);
4763 return((Image *) NULL);
4766 image=SyncNextImageInList(image);
4769 mng_info->image=image;
4771 if (term_chunk_found)
4773 image->start_loop=MagickTrue;
4774 image->iterations=mng_iterations;
4775 term_chunk_found=MagickFalse;
4779 image->start_loop=MagickFalse;
4781 image->columns=subframe_width;
4782 image->rows=subframe_height;
4783 image->page.width=subframe_width;
4784 image->page.height=subframe_height;
4785 image->page.x=mng_info->clip.left;
4786 image->page.y=mng_info->clip.top;
4787 image->background_color=mng_background_color;
4788 image->matte=MagickFalse;
4790 (void) SetImageBackgroundColor(image);
4792 if (logging != MagickFalse)
4793 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4794 " Insert backgd layer, L=%.20g, R=%.20g T=%.20g, B=%.20g",
4795 (double) mng_info->clip.left,(double) mng_info->clip.right,
4796 (double) mng_info->clip.top,(double) mng_info->clip.bottom);
4799 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4802 if (memcmp(type,mng_CLIP,4) == 0)
4811 first_object=(p[0] << 8) | p[1];
4812 last_object=(p[2] << 8) | p[3];
4814 for (i=(int) first_object; i <= (int) last_object; i++)
4816 if (mng_info->exists[i] && !mng_info->frozen[i])
4821 box=mng_info->object_clip[i];
4822 mng_info->object_clip[i]=mng_read_box(box,(char) p[4],&p[5]);
4826 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4829 if (memcmp(type,mng_SAVE,4) == 0)
4831 for (i=1; i < MNG_MAX_OBJECTS; i++)
4832 if (mng_info->exists[i])
4834 mng_info->frozen[i]=MagickTrue;
4835 #ifdef MNG_OBJECT_BUFFERS
4836 if (mng_info->ob[i] != (MngBuffer *) NULL)
4837 mng_info->ob[i]->frozen=MagickTrue;
4842 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4847 if ((memcmp(type,mng_DISC,4) == 0) || (memcmp(type,mng_SEEK,4) == 0))
4849 /* Read DISC or SEEK. */
4851 if ((length == 0) || !memcmp(type,mng_SEEK,4))
4853 for (i=1; i < MNG_MAX_OBJECTS; i++)
4854 MngInfoDiscardObject(mng_info,i);
4862 for (j=0; j < (ssize_t) length; j+=2)
4864 i=p[j] << 8 | p[j+1];
4865 MngInfoDiscardObject(mng_info,i);
4870 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4875 if (memcmp(type,mng_MOVE,4) == 0)
4883 first_object=(p[0] << 8) | p[1];
4884 last_object=(p[2] << 8) | p[3];
4885 for (i=(ssize_t) first_object; i <= (ssize_t) last_object; i++)
4887 if (mng_info->exists[i] && !mng_info->frozen[i])
4895 old_pair.a=mng_info->x_off[i];
4896 old_pair.b=mng_info->y_off[i];
4897 new_pair=mng_read_pair(old_pair,(int) p[4],&p[5]);
4898 mng_info->x_off[i]=new_pair.a;
4899 mng_info->y_off[i]=new_pair.b;
4903 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4907 if (memcmp(type,mng_LOOP,4) == 0)
4909 ssize_t loop_iters=1;
4910 loop_level=chunk[0];
4911 mng_info->loop_active[loop_level]=1; /* mark loop active */
4913 /* Record starting point. */
4914 loop_iters=mng_get_long(&chunk[1]);
4916 if (logging != MagickFalse)
4917 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4918 " LOOP level %.20g has %.20g iterations ",(double) loop_level,
4919 (double) loop_iters);
4921 if (loop_iters == 0)
4922 skipping_loop=loop_level;
4926 mng_info->loop_jump[loop_level]=TellBlob(image);
4927 mng_info->loop_count[loop_level]=loop_iters;
4930 mng_info->loop_iteration[loop_level]=0;
4931 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4935 if (memcmp(type,mng_ENDL,4) == 0)
4937 loop_level=chunk[0];
4939 if (skipping_loop > 0)
4941 if (skipping_loop == loop_level)
4944 Found end of zero-iteration loop.
4947 mng_info->loop_active[loop_level]=0;
4953 if (mng_info->loop_active[loop_level] == 1)
4955 mng_info->loop_count[loop_level]--;
4956 mng_info->loop_iteration[loop_level]++;
4958 if (logging != MagickFalse)
4959 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4960 " ENDL: LOOP level %.20g has %.20g remaining iters ",
4961 (double) loop_level,(double)
4962 mng_info->loop_count[loop_level]);
4964 if (mng_info->loop_count[loop_level] != 0)
4966 offset=SeekBlob(image,mng_info->loop_jump[loop_level],
4970 ThrowReaderException(CorruptImageError,
4971 "ImproperImageHeader");
4982 mng_info->loop_active[loop_level]=0;
4984 for (i=0; i < loop_level; i++)
4985 if (mng_info->loop_active[i] == 1)
4986 last_level=(short) i;
4987 loop_level=last_level;
4992 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4996 if (memcmp(type,mng_CLON,4) == 0)
4998 if (mng_info->clon_warning == 0)
4999 (void) ThrowMagickException(&image->exception,GetMagickModule(),
5000 CoderError,"CLON is not implemented yet","`%s'",
5003 mng_info->clon_warning++;
5006 if (memcmp(type,mng_MAGN,4) == 0)
5021 magn_first=(p[0] << 8) | p[1];
5027 magn_last=(p[2] << 8) | p[3];
5030 magn_last=magn_first;
5031 #ifndef MNG_OBJECT_BUFFERS
5032 if (magn_first || magn_last)
5033 if (mng_info->magn_warning == 0)
5035 (void) ThrowMagickException(&image->exception,
5036 GetMagickModule(),CoderError,
5037 "MAGN is not implemented yet for nonzero objects",
5038 "`%s'",image->filename);
5040 mng_info->magn_warning++;
5050 magn_mx=(p[5] << 8) | p[6];
5059 magn_my=(p[7] << 8) | p[8];
5068 magn_ml=(p[9] << 8) | p[10];
5077 magn_mr=(p[11] << 8) | p[12];
5086 magn_mt=(p[13] << 8) | p[14];
5095 magn_mb=(p[15] << 8) | p[16];
5107 magn_methy=magn_methx;
5110 if (magn_methx > 5 || magn_methy > 5)
5111 if (mng_info->magn_warning == 0)
5113 (void) ThrowMagickException(&image->exception,
5114 GetMagickModule(),CoderError,
5115 "Unknown MAGN method in MNG datastream","`%s'",
5118 mng_info->magn_warning++;
5120 #ifdef MNG_OBJECT_BUFFERS
5121 /* Magnify existing objects in the range magn_first to magn_last */
5123 if (magn_first == 0 || magn_last == 0)
5125 /* Save the magnification factors for object 0 */
5126 mng_info->magn_mb=magn_mb;
5127 mng_info->magn_ml=magn_ml;
5128 mng_info->magn_mr=magn_mr;
5129 mng_info->magn_mt=magn_mt;
5130 mng_info->magn_mx=magn_mx;
5131 mng_info->magn_my=magn_my;
5132 mng_info->magn_methx=magn_methx;
5133 mng_info->magn_methy=magn_methy;
5137 if (memcmp(type,mng_PAST,4) == 0)
5139 if (mng_info->past_warning == 0)
5140 (void) ThrowMagickException(&image->exception,GetMagickModule(),
5141 CoderError,"PAST is not implemented yet","`%s'",
5144 mng_info->past_warning++;
5147 if (memcmp(type,mng_SHOW,4) == 0)
5149 if (mng_info->show_warning == 0)
5150 (void) ThrowMagickException(&image->exception,GetMagickModule(),
5151 CoderError,"SHOW is not implemented yet","`%s'",
5154 mng_info->show_warning++;
5157 if (memcmp(type,mng_sBIT,4) == 0)
5160 mng_info->have_global_sbit=MagickFalse;
5164 mng_info->global_sbit.gray=p[0];
5165 mng_info->global_sbit.red=p[0];
5166 mng_info->global_sbit.green=p[1];
5167 mng_info->global_sbit.blue=p[2];
5168 mng_info->global_sbit.alpha=p[3];
5169 mng_info->have_global_sbit=MagickTrue;
5172 if (memcmp(type,mng_pHYs,4) == 0)
5176 mng_info->global_x_pixels_per_unit=
5177 (size_t) mng_get_long(p);
5178 mng_info->global_y_pixels_per_unit=
5179 (size_t) mng_get_long(&p[4]);
5180 mng_info->global_phys_unit_type=p[8];
5181 mng_info->have_global_phys=MagickTrue;
5185 mng_info->have_global_phys=MagickFalse;
5187 if (memcmp(type,mng_pHYg,4) == 0)
5189 if (mng_info->phyg_warning == 0)
5190 (void) ThrowMagickException(&image->exception,GetMagickModule(),
5191 CoderError,"pHYg is not implemented.","`%s'",image->filename);
5193 mng_info->phyg_warning++;
5195 if (memcmp(type,mng_BASI,4) == 0)
5197 skip_to_iend=MagickTrue;
5199 if (mng_info->basi_warning == 0)
5200 (void) ThrowMagickException(&image->exception,GetMagickModule(),
5201 CoderError,"BASI is not implemented yet","`%s'",
5204 mng_info->basi_warning++;
5205 #ifdef MNG_BASI_SUPPORTED
5206 basi_width=(size_t) ((p[0] << 24) | (p[1] << 16) |
5207 (p[2] << 8) | p[3]);
5208 basi_height=(size_t) ((p[4] << 24) | (p[5] << 16) |
5209 (p[6] << 8) | p[7]);
5210 basi_color_type=p[8];
5211 basi_compression_method=p[9];
5212 basi_filter_type=p[10];
5213 basi_interlace_method=p[11];
5215 basi_red=(p[12] << 8) & p[13];
5221 basi_green=(p[14] << 8) & p[15];
5227 basi_blue=(p[16] << 8) & p[17];
5233 basi_alpha=(p[18] << 8) & p[19];
5237 if (basi_sample_depth == 16)
5244 basi_viewable=p[20];
5250 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5254 if (memcmp(type,mng_IHDR,4)
5255 #if defined(JNG_SUPPORTED)
5256 && memcmp(type,mng_JHDR,4)
5260 /* Not an IHDR or JHDR chunk */
5262 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5267 if (logging != MagickFalse)
5268 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5269 " Processing %c%c%c%c chunk",type[0],type[1],type[2],type[3]);
5271 mng_info->exists[object_id]=MagickTrue;
5272 mng_info->viewable[object_id]=MagickTrue;
5274 if (mng_info->invisible[object_id])
5276 if (logging != MagickFalse)
5277 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5278 " Skipping invisible object");
5280 skip_to_iend=MagickTrue;
5281 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5284 #if defined(MNG_INSERT_LAYERS)
5286 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
5288 image_width=(size_t) mng_get_long(p);
5289 image_height=(size_t) mng_get_long(&p[4]);
5291 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5294 Insert a transparent background layer behind the entire animation
5295 if it is not full screen.
5297 #if defined(MNG_INSERT_LAYERS)
5298 if (insert_layers && mng_type && first_mng_object)
5300 if ((mng_info->clip.left > 0) || (mng_info->clip.top > 0) ||
5301 (image_width < mng_info->mng_width) ||
5302 (mng_info->clip.right < (ssize_t) mng_info->mng_width) ||
5303 (image_height < mng_info->mng_height) ||
5304 (mng_info->clip.bottom < (ssize_t) mng_info->mng_height))
5306 if (GetAuthenticPixelQueue(image) != (PixelPacket *) NULL)
5309 Allocate next image structure.
5311 AcquireNextImage(image_info,image);
5313 if (GetNextImageInList(image) == (Image *) NULL)
5315 image=DestroyImageList(image);
5316 MngInfoFreeStruct(mng_info,&have_mng_structure);
5317 return((Image *) NULL);
5320 image=SyncNextImageInList(image);
5322 mng_info->image=image;
5324 if (term_chunk_found)
5326 image->start_loop=MagickTrue;
5327 image->iterations=mng_iterations;
5328 term_chunk_found=MagickFalse;
5332 image->start_loop=MagickFalse;
5334 /* Make a background rectangle. */
5337 image->columns=mng_info->mng_width;
5338 image->rows=mng_info->mng_height;
5339 image->page.width=mng_info->mng_width;
5340 image->page.height=mng_info->mng_height;
5343 image->background_color=mng_background_color;
5344 (void) SetImageBackgroundColor(image);
5345 if (logging != MagickFalse)
5346 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5347 " Inserted transparent background layer, W=%.20g, H=%.20g",
5348 (double) mng_info->mng_width,(double) mng_info->mng_height);
5352 Insert a background layer behind the upcoming image if
5353 framing_mode is 3, and we haven't already inserted one.
5355 if (insert_layers && (mng_info->framing_mode == 3) &&
5356 (subframe_width) && (subframe_height) && (simplicity == 0 ||
5357 (simplicity & 0x08)))
5359 if (GetAuthenticPixelQueue(image) != (PixelPacket *) NULL)
5362 Allocate next image structure.
5364 AcquireNextImage(image_info,image);
5366 if (GetNextImageInList(image) == (Image *) NULL)
5368 image=DestroyImageList(image);
5369 MngInfoFreeStruct(mng_info,&have_mng_structure);
5370 return((Image *) NULL);
5373 image=SyncNextImageInList(image);
5376 mng_info->image=image;
5378 if (term_chunk_found)
5380 image->start_loop=MagickTrue;
5381 image->iterations=mng_iterations;
5382 term_chunk_found=MagickFalse;
5386 image->start_loop=MagickFalse;
5389 image->columns=subframe_width;
5390 image->rows=subframe_height;
5391 image->page.width=subframe_width;
5392 image->page.height=subframe_height;
5393 image->page.x=mng_info->clip.left;
5394 image->page.y=mng_info->clip.top;
5395 image->background_color=mng_background_color;
5396 image->matte=MagickFalse;
5397 (void) SetImageBackgroundColor(image);
5399 if (logging != MagickFalse)
5400 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5401 " Insert background layer, L=%.20g, R=%.20g T=%.20g, B=%.20g",
5402 (double) mng_info->clip.left,(double) mng_info->clip.right,
5403 (double) mng_info->clip.top,(double) mng_info->clip.bottom);
5405 #endif /* MNG_INSERT_LAYERS */
5406 first_mng_object=MagickFalse;
5408 if (GetAuthenticPixelQueue(image) != (PixelPacket *) NULL)
5411 Allocate next image structure.
5413 AcquireNextImage(image_info,image);
5415 if (GetNextImageInList(image) == (Image *) NULL)
5417 image=DestroyImageList(image);
5418 MngInfoFreeStruct(mng_info,&have_mng_structure);
5419 return((Image *) NULL);
5422 image=SyncNextImageInList(image);
5424 mng_info->image=image;
5425 status=SetImageProgress(image,LoadImagesTag,TellBlob(image),
5426 GetBlobSize(image));
5428 if (status == MagickFalse)
5431 if (term_chunk_found)
5433 image->start_loop=MagickTrue;
5434 term_chunk_found=MagickFalse;
5438 image->start_loop=MagickFalse;
5440 if (mng_info->framing_mode == 1 || mng_info->framing_mode == 3)
5442 image->delay=frame_delay;
5443 frame_delay=default_frame_delay;
5449 image->page.width=mng_info->mng_width;
5450 image->page.height=mng_info->mng_height;
5451 image->page.x=mng_info->x_off[object_id];
5452 image->page.y=mng_info->y_off[object_id];
5453 image->iterations=mng_iterations;
5456 Seek back to the beginning of the IHDR or JHDR chunk's length field.
5459 if (logging != MagickFalse)
5460 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5461 " Seeking back to beginning of %c%c%c%c chunk",type[0],type[1],
5464 offset=SeekBlob(image,-((ssize_t) length+12),SEEK_CUR);
5467 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
5471 mng_info->image=image;
5472 mng_info->mng_type=mng_type;
5473 mng_info->object_id=object_id;
5475 if (memcmp(type,mng_IHDR,4) == 0)
5476 image=ReadOnePNGImage(mng_info,image_info,exception);
5478 #if defined(JNG_SUPPORTED)
5480 image=ReadOneJNGImage(mng_info,image_info,exception);
5483 if (image == (Image *) NULL)
5485 if (IsImageObject(previous) != MagickFalse)
5487 (void) DestroyImageList(previous);
5488 (void) CloseBlob(previous);
5491 MngInfoFreeStruct(mng_info,&have_mng_structure);
5492 return((Image *) NULL);
5495 if (image->columns == 0 || image->rows == 0)
5497 (void) CloseBlob(image);
5498 image=DestroyImageList(image);
5499 MngInfoFreeStruct(mng_info,&have_mng_structure);
5500 return((Image *) NULL);
5503 mng_info->image=image;
5510 if (mng_info->magn_methx || mng_info->magn_methy)
5516 if (logging != MagickFalse)
5517 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5518 " Processing MNG MAGN chunk");
5520 if (mng_info->magn_methx == 1)
5522 magnified_width=mng_info->magn_ml;
5524 if (image->columns > 1)
5525 magnified_width += mng_info->magn_mr;
5527 if (image->columns > 2)
5528 magnified_width += (png_uint_32)
5529 ((image->columns-2)*(mng_info->magn_mx));
5534 magnified_width=(png_uint_32) image->columns;
5536 if (image->columns > 1)
5537 magnified_width += mng_info->magn_ml-1;
5539 if (image->columns > 2)
5540 magnified_width += mng_info->magn_mr-1;
5542 if (image->columns > 3)
5543 magnified_width += (png_uint_32)
5544 ((image->columns-3)*(mng_info->magn_mx-1));
5547 if (mng_info->magn_methy == 1)
5549 magnified_height=mng_info->magn_mt;
5551 if (image->rows > 1)
5552 magnified_height += mng_info->magn_mb;
5554 if (image->rows > 2)
5555 magnified_height += (png_uint_32)
5556 ((image->rows-2)*(mng_info->magn_my));
5561 magnified_height=(png_uint_32) image->rows;
5563 if (image->rows > 1)
5564 magnified_height += mng_info->magn_mt-1;
5566 if (image->rows > 2)
5567 magnified_height += mng_info->magn_mb-1;
5569 if (image->rows > 3)
5570 magnified_height += (png_uint_32)
5571 ((image->rows-3)*(mng_info->magn_my-1));
5574 if (magnified_height > image->rows ||
5575 magnified_width > image->columns)
5590 register PixelPacket
5602 /* Allocate next image structure. */
5604 if (logging != MagickFalse)
5605 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5606 " Allocate magnified image");
5608 AcquireNextImage(image_info,image);
5610 if (GetNextImageInList(image) == (Image *) NULL)
5612 image=DestroyImageList(image);
5613 MngInfoFreeStruct(mng_info,&have_mng_structure);
5614 return((Image *) NULL);
5617 large_image=SyncNextImageInList(image);
5619 large_image->columns=magnified_width;
5620 large_image->rows=magnified_height;
5622 magn_methx=mng_info->magn_methx;
5623 magn_methy=mng_info->magn_methy;
5625 #if (MAGICKCORE_QUANTUM_DEPTH == 32)
5626 #define QM unsigned short
5627 if (magn_methx != 1 || magn_methy != 1)
5630 Scale pixels to unsigned shorts to prevent
5631 overflow of intermediate values of interpolations
5633 for (y=0; y < (ssize_t) image->rows; y++)
5635 q=GetAuthenticPixels(image,0,y,image->columns,1,
5638 for (x=(ssize_t) image->columns-1; x >= 0; x--)
5640 q->red=ScaleQuantumToShort(q->red);
5641 q->green=ScaleQuantumToShort(q->green);
5642 q->blue=ScaleQuantumToShort(q->blue);
5643 q->opacity=ScaleQuantumToShort(q->opacity);
5647 if (SyncAuthenticPixels(image,exception) == MagickFalse)
5655 if (image->matte != MagickFalse)
5656 (void) SetImageBackgroundColor(large_image);
5660 large_image->background_color.opacity=OpaqueOpacity;
5661 (void) SetImageBackgroundColor(large_image);
5663 if (magn_methx == 4)
5666 if (magn_methx == 5)
5669 if (magn_methy == 4)
5672 if (magn_methy == 5)
5676 /* magnify the rows into the right side of the large image */
5678 if (logging != MagickFalse)
5679 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5680 " Magnify the rows to %.20g",(double) large_image->rows);
5681 m=(ssize_t) mng_info->magn_mt;
5683 length=(size_t) image->columns;
5684 next=(PixelPacket *) AcquireQuantumMemory(length,sizeof(*next));
5685 prev=(PixelPacket *) AcquireQuantumMemory(length,sizeof(*prev));
5687 if ((prev == (PixelPacket *) NULL) ||
5688 (next == (PixelPacket *) NULL))
5690 image=DestroyImageList(image);
5691 MngInfoFreeStruct(mng_info,&have_mng_structure);
5692 ThrowReaderException(ResourceLimitError,
5693 "MemoryAllocationFailed");
5696 n=GetAuthenticPixels(image,0,0,image->columns,1,exception);
5697 (void) CopyMagickMemory(next,n,length);
5699 for (y=0; y < (ssize_t) image->rows; y++)
5702 m=(ssize_t) mng_info->magn_mt;
5704 else if (magn_methy > 1 && y == (ssize_t) image->rows-2)
5705 m=(ssize_t) mng_info->magn_mb;
5707 else if (magn_methy <= 1 && y == (ssize_t) image->rows-1)
5708 m=(ssize_t) mng_info->magn_mb;
5710 else if (magn_methy > 1 && y == (ssize_t) image->rows-1)
5714 m=(ssize_t) mng_info->magn_my;
5720 if (y < (ssize_t) image->rows-1)
5722 n=GetAuthenticPixels(image,0,y+1,image->columns,1,
5724 (void) CopyMagickMemory(next,n,length);
5727 for (i=0; i < m; i++, yy++)
5729 register PixelPacket
5732 assert(yy < (ssize_t) large_image->rows);
5735 q=GetAuthenticPixels(large_image,0,yy,large_image->columns,
5737 q+=(large_image->columns-image->columns);
5739 for (x=(ssize_t) image->columns-1; x >= 0; x--)
5741 /* TO DO: get color as function of indexes[x] */
5743 if (image->storage_class == PseudoClass)
5748 if (magn_methy <= 1)
5750 *q=(*pixels); /* replicate previous */
5753 else if (magn_methy == 2 || magn_methy == 4)
5761 (*q).red=(QM) (((ssize_t) (2*i*((*n).red
5762 -(*pixels).red)+m))/((ssize_t) (m*2))
5764 (*q).green=(QM) (((ssize_t) (2*i*((*n).green
5765 -(*pixels).green)+m))/((ssize_t) (m*2))
5767 (*q).blue=(QM) (((ssize_t) (2*i*((*n).blue
5768 -(*pixels).blue)+m))/((ssize_t) (m*2))
5771 if (image->matte != MagickFalse)
5772 (*q).opacity=(QM) (((ssize_t)
5774 -(*pixels).opacity)+m))
5775 /((ssize_t) (m*2))+(*pixels).opacity);
5778 if (magn_methy == 4)
5780 /* Replicate nearest */
5781 if (i <= ((m+1) << 1))
5782 (*q).opacity=(*pixels).opacity+0;
5784 (*q).opacity=(*n).opacity+0;
5788 else /* if (magn_methy == 3 || magn_methy == 5) */
5790 /* Replicate nearest */
5791 if (i <= ((m+1) << 1))
5797 if (magn_methy == 5)
5799 (*q).opacity=(QM) (((ssize_t) (2*i*((*n).opacity
5800 -(*pixels).opacity)+m))/((ssize_t) (m*2))
5801 +(*pixels).opacity);
5809 if (SyncAuthenticPixels(large_image,exception) == 0)
5815 prev=(PixelPacket *) RelinquishMagickMemory(prev);
5816 next=(PixelPacket *) RelinquishMagickMemory(next);
5818 length=image->columns;
5820 if (logging != MagickFalse)
5821 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5822 " Delete original image");
5824 DeleteImageFromList(&image);
5828 mng_info->image=image;
5830 /* magnify the columns */
5831 if (logging != MagickFalse)
5832 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5833 " Magnify the columns to %.20g",(double) image->columns);
5835 for (y=0; y < (ssize_t) image->rows; y++)
5837 register PixelPacket
5840 q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
5841 pixels=q+(image->columns-length);
5844 for (x=(ssize_t) (image->columns-length);
5845 x < (ssize_t) image->columns; x++)
5847 if (x == (ssize_t) (image->columns-length))
5848 m=(ssize_t) mng_info->magn_ml;
5850 else if (magn_methx > 1 && x == (ssize_t) image->columns-2)
5851 m=(ssize_t) mng_info->magn_mr;
5853 else if (magn_methx <= 1 && x == (ssize_t) image->columns-1)
5854 m=(ssize_t) mng_info->magn_mr;
5856 else if (magn_methx > 1 && x == (ssize_t) image->columns-1)
5860 m=(ssize_t) mng_info->magn_mx;
5862 for (i=0; i < m; i++)
5864 if (magn_methx <= 1)
5866 /* replicate previous */
5870 else if (magn_methx == 2 || magn_methx == 4)
5878 (*q).red=(QM) ((2*i*((*n).red
5880 /((ssize_t) (m*2))+(*pixels).red);
5881 (*q).green=(QM) ((2*i*((*n).green
5883 +m)/((ssize_t) (m*2))+(*pixels).green);
5884 (*q).blue=(QM) ((2*i*((*n).blue
5886 /((ssize_t) (m*2))+(*pixels).blue);
5887 if (image->matte != MagickFalse)
5888 (*q).opacity=(QM) ((2*i*((*n).opacity
5889 -(*pixels).opacity)+m)/((ssize_t) (m*2))
5890 +(*pixels).opacity);
5893 if (magn_methx == 4)
5895 /* Replicate nearest */
5896 if (i <= ((m+1) << 1))
5897 (*q).opacity=(*pixels).opacity+0;
5899 (*q).opacity=(*n).opacity+0;
5903 else /* if (magn_methx == 3 || magn_methx == 5) */
5905 /* Replicate nearest */
5906 if (i <= ((m+1) << 1))
5912 if (magn_methx == 5)
5915 (*q).opacity=(QM) ((2*i*((*n).opacity
5916 -(*pixels).opacity)+m) /((ssize_t) (m*2))
5917 +(*pixels).opacity);
5926 if (SyncAuthenticPixels(image,exception) == MagickFalse)
5929 #if (MAGICKCORE_QUANTUM_DEPTH == 32)
5930 if (magn_methx != 1 || magn_methy != 1)
5933 Rescale pixels to Quantum
5935 for (y=0; y < (ssize_t) image->rows; y++)
5937 q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
5939 for (x=(ssize_t) image->columns-1; x >= 0; x--)
5941 q->red=ScaleShortToQuantum(q->red);
5942 q->green=ScaleShortToQuantum(q->green);
5943 q->blue=ScaleShortToQuantum(q->blue);
5944 q->opacity=ScaleShortToQuantum(q->opacity);
5948 if (SyncAuthenticPixels(image,exception) == MagickFalse)
5953 if (logging != MagickFalse)
5954 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5955 " Finished MAGN processing");
5960 Crop_box is with respect to the upper left corner of the MNG.
5962 crop_box.left=mng_info->image_box.left+mng_info->x_off[object_id];
5963 crop_box.right=mng_info->image_box.right+mng_info->x_off[object_id];
5964 crop_box.top=mng_info->image_box.top+mng_info->y_off[object_id];
5965 crop_box.bottom=mng_info->image_box.bottom+mng_info->y_off[object_id];
5966 crop_box=mng_minimum_box(crop_box,mng_info->clip);
5967 crop_box=mng_minimum_box(crop_box,mng_info->frame);
5968 crop_box=mng_minimum_box(crop_box,mng_info->object_clip[object_id]);
5969 if ((crop_box.left != (mng_info->image_box.left
5970 +mng_info->x_off[object_id])) ||
5971 (crop_box.right != (mng_info->image_box.right
5972 +mng_info->x_off[object_id])) ||
5973 (crop_box.top != (mng_info->image_box.top
5974 +mng_info->y_off[object_id])) ||
5975 (crop_box.bottom != (mng_info->image_box.bottom
5976 +mng_info->y_off[object_id])))
5978 if (logging != MagickFalse)
5979 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5980 " Crop the PNG image");
5982 if ((crop_box.left < crop_box.right) &&
5983 (crop_box.top < crop_box.bottom))
5992 Crop_info is with respect to the upper left corner of
5995 crop_info.x=(crop_box.left-mng_info->x_off[object_id]);
5996 crop_info.y=(crop_box.top-mng_info->y_off[object_id]);
5997 crop_info.width=(size_t) (crop_box.right-crop_box.left);
5998 crop_info.height=(size_t) (crop_box.bottom-crop_box.top);
5999 image->page.width=image->columns;
6000 image->page.height=image->rows;
6003 im=CropImage(image,&crop_info,exception);
6005 if (im != (Image *) NULL)
6007 image->columns=im->columns;
6008 image->rows=im->rows;
6009 im=DestroyImage(im);
6010 image->page.width=image->columns;
6011 image->page.height=image->rows;
6012 image->page.x=crop_box.left;
6013 image->page.y=crop_box.top;
6020 No pixels in crop area. The MNG spec still requires
6021 a layer, though, so make a single transparent pixel in
6022 the top left corner.
6027 (void) SetImageBackgroundColor(image);
6028 image->page.width=1;
6029 image->page.height=1;
6034 #ifndef PNG_READ_EMPTY_PLTE_SUPPORTED
6035 image=mng_info->image;
6039 #if (MAGICKCORE_QUANTUM_DEPTH > 16)
6040 /* PNG does not handle depths greater than 16 so reduce it even
6043 if (image->depth > 16)
6047 #if (MAGICKCORE_QUANTUM_DEPTH >= 16)
6048 if (LosslessReduceDepthOK(image) != MagickFalse)
6052 GetImageException(image,exception);
6054 if (image_info->number_scenes != 0)
6056 if (mng_info->scenes_found >
6057 (ssize_t) (image_info->first_scene+image_info->number_scenes))
6061 if (logging != MagickFalse)
6062 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6063 " Finished reading image datastream.");
6065 } while (LocaleCompare(image_info->magick,"MNG") == 0);
6067 (void) CloseBlob(image);
6069 if (logging != MagickFalse)
6070 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6071 " Finished reading all image datastreams.");
6073 #if defined(MNG_INSERT_LAYERS)
6074 if (insert_layers && !mng_info->image_found && (mng_info->mng_width) &&
6075 (mng_info->mng_height))
6078 Insert a background layer if nothing else was found.
6080 if (logging != MagickFalse)
6081 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6082 " No images found. Inserting a background layer.");
6084 if (GetAuthenticPixelQueue(image) != (PixelPacket *) NULL)
6087 Allocate next image structure.
6089 AcquireNextImage(image_info,image);
6090 if (GetNextImageInList(image) == (Image *) NULL)
6092 image=DestroyImageList(image);
6093 MngInfoFreeStruct(mng_info,&have_mng_structure);
6095 if (logging != MagickFalse)
6096 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6097 " Allocation failed, returning NULL.");
6099 return((Image *) NULL);
6101 image=SyncNextImageInList(image);
6103 image->columns=mng_info->mng_width;
6104 image->rows=mng_info->mng_height;
6105 image->page.width=mng_info->mng_width;
6106 image->page.height=mng_info->mng_height;
6109 image->background_color=mng_background_color;
6110 image->matte=MagickFalse;
6112 if (image_info->ping == MagickFalse)
6113 (void) SetImageBackgroundColor(image);
6115 mng_info->image_found++;
6118 image->iterations=mng_iterations;
6120 if (mng_iterations == 1)
6121 image->start_loop=MagickTrue;
6123 while (GetPreviousImageInList(image) != (Image *) NULL)
6126 if (image_count > 10*mng_info->image_found)
6128 if (logging != MagickFalse)
6129 (void) LogMagickEvent(CoderEvent,GetMagickModule()," No beginning");
6131 (void) ThrowMagickException(&image->exception,GetMagickModule(),
6132 CoderError,"Linked list is corrupted, beginning of list not found",
6133 "`%s'",image_info->filename);
6135 return((Image *) NULL);
6138 image=GetPreviousImageInList(image);
6140 if (GetNextImageInList(image) == (Image *) NULL)
6142 if (logging != MagickFalse)
6143 (void) LogMagickEvent(CoderEvent,GetMagickModule()," Corrupt list");
6145 (void) ThrowMagickException(&image->exception,GetMagickModule(),
6146 CoderError,"Linked list is corrupted; next_image is NULL","`%s'",
6147 image_info->filename);
6151 if (mng_info->ticks_per_second && mng_info->image_found > 1 &&
6152 GetNextImageInList(image) ==
6155 if (logging != MagickFalse)
6156 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6157 " First image null");
6159 (void) ThrowMagickException(&image->exception,GetMagickModule(),
6160 CoderError,"image->next for first image is NULL but shouldn't be.",
6161 "`%s'",image_info->filename);
6164 if (mng_info->image_found == 0)
6166 if (logging != MagickFalse)
6167 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6168 " No visible images found.");
6170 (void) ThrowMagickException(&image->exception,GetMagickModule(),
6171 CoderError,"No visible images in file","`%s'",image_info->filename);
6173 if (image != (Image *) NULL)
6174 image=DestroyImageList(image);
6176 MngInfoFreeStruct(mng_info,&have_mng_structure);
6177 return((Image *) NULL);
6180 if (mng_info->ticks_per_second)
6181 final_delay=1UL*MagickMax(image->ticks_per_second,1L)*
6182 final_delay/mng_info->ticks_per_second;
6185 image->start_loop=MagickTrue;
6187 /* Find final nonzero image delay */
6188 final_image_delay=0;
6190 while (GetNextImageInList(image) != (Image *) NULL)
6193 final_image_delay=image->delay;
6195 image=GetNextImageInList(image);
6198 if (final_delay < final_image_delay)
6199 final_delay=final_image_delay;
6201 image->delay=final_delay;
6203 if (logging != MagickFalse)
6204 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6205 " image->delay=%.20g, final_delay=%.20g",(double) image->delay,
6206 (double) final_delay);
6208 if (logging != MagickFalse)
6214 image=GetFirstImageInList(image);
6216 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6217 " Before coalesce:");
6219 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6220 " scene 0 delay=%.20g",(double) image->delay);
6222 while (GetNextImageInList(image) != (Image *) NULL)
6224 image=GetNextImageInList(image);
6225 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6226 " scene %.20g delay=%.20g",(double) scene++,(double) image->delay);
6230 image=GetFirstImageInList(image);
6231 #ifdef MNG_COALESCE_LAYERS
6241 if (logging != MagickFalse)
6242 (void) LogMagickEvent(CoderEvent,GetMagickModule()," Coalesce Images");
6245 next_image=CoalesceImages(image,&image->exception);
6247 if (next_image == (Image *) NULL)
6248 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
6250 image=DestroyImageList(image);
6253 for (next=image; next != (Image *) NULL; next=next_image)
6255 next->page.width=mng_info->mng_width;
6256 next->page.height=mng_info->mng_height;
6259 next->scene=scene++;
6260 next_image=GetNextImageInList(next);
6262 if (next_image == (Image *) NULL)
6265 if (next->delay == 0)
6268 next_image->previous=GetPreviousImageInList(next);
6269 if (GetPreviousImageInList(next) == (Image *) NULL)
6272 next->previous->next=next_image;
6273 next=DestroyImage(next);
6279 while (GetNextImageInList(image) != (Image *) NULL)
6280 image=GetNextImageInList(image);
6282 image->dispose=BackgroundDispose;
6284 if (logging != MagickFalse)
6290 image=GetFirstImageInList(image);
6292 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6293 " After coalesce:");
6295 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6296 " scene 0 delay=%.20g dispose=%.20g",(double) image->delay,
6297 (double) image->dispose);
6299 while (GetNextImageInList(image) != (Image *) NULL)
6301 image=GetNextImageInList(image);
6303 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6304 " scene %.20g delay=%.20g dispose=%.20g",(double) scene++,
6305 (double) image->delay,(double) image->dispose);
6309 image=GetFirstImageInList(image);
6310 MngInfoFreeStruct(mng_info,&have_mng_structure);
6311 have_mng_structure=MagickFalse;
6313 if (logging != MagickFalse)
6314 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"exit ReadMNGImage()");
6316 return(GetFirstImageInList(image));
6318 #else /* PNG_LIBPNG_VER > 10011 */
6319 static Image *ReadPNGImage(const ImageInfo *image_info,ExceptionInfo *exception)
6321 printf("Your PNG library is too old: You have libpng-%s\n",
6322 PNG_LIBPNG_VER_STRING);
6324 (void) ThrowMagickException(exception,GetMagickModule(),CoderError,
6325 "PNG library is too old","`%s'",image_info->filename);
6327 return(Image *) NULL;
6330 static Image *ReadMNGImage(const ImageInfo *image_info,ExceptionInfo *exception)
6332 return(ReadPNGImage(image_info,exception));
6334 #endif /* PNG_LIBPNG_VER > 10011 */
6338 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6342 % R e g i s t e r P N G I m a g e %
6346 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6348 % RegisterPNGImage() adds properties for the PNG image format to
6349 % the list of supported formats. The properties include the image format
6350 % tag, a method to read and/or write the format, whether the format
6351 % supports the saving of more than one frame to the same file or blob,
6352 % whether the format supports native in-memory I/O, and a brief
6353 % description of the format.
6355 % The format of the RegisterPNGImage method is:
6357 % size_t RegisterPNGImage(void)
6360 ModuleExport size_t RegisterPNGImage(void)
6363 version[MaxTextExtent];
6371 "See http://www.libpng.org/ for details about the PNG format."
6376 "See http://www.libpng.org/pub/mng/ for details about the JNG\n"
6382 "See http://www.libpng.org/pub/mng/ for details about the MNG\n"
6388 #if defined(PNG_LIBPNG_VER_STRING)
6389 (void) ConcatenateMagickString(version,"libpng ",MaxTextExtent);
6390 (void) ConcatenateMagickString(version,PNG_LIBPNG_VER_STRING,MaxTextExtent);
6392 if (LocaleCompare(PNG_LIBPNG_VER_STRING,png_get_header_ver(NULL)) != 0)
6394 (void) ConcatenateMagickString(version,",",MaxTextExtent);
6395 (void) ConcatenateMagickString(version,png_get_libpng_ver(NULL),
6400 entry=SetMagickInfo("MNG");
6401 entry->seekable_stream=MagickTrue; /* To do: eliminate this. */
6403 #if defined(MAGICKCORE_PNG_DELEGATE)
6404 entry->decoder=(DecodeImageHandler *) ReadMNGImage;
6405 entry->encoder=(EncodeImageHandler *) WriteMNGImage;
6408 entry->magick=(IsImageFormatHandler *) IsMNG;
6409 entry->description=ConstantString("Multiple-image Network Graphics");
6411 if (*version != '\0')
6412 entry->version=ConstantString(version);
6414 entry->module=ConstantString("PNG");
6415 entry->note=ConstantString(MNGNote);
6416 (void) RegisterMagickInfo(entry);
6418 entry=SetMagickInfo("PNG");
6420 #if defined(MAGICKCORE_PNG_DELEGATE)
6421 entry->decoder=(DecodeImageHandler *) ReadPNGImage;
6422 entry->encoder=(EncodeImageHandler *) WritePNGImage;
6425 entry->magick=(IsImageFormatHandler *) IsPNG;
6426 entry->adjoin=MagickFalse;
6427 entry->description=ConstantString("Portable Network Graphics");
6428 entry->module=ConstantString("PNG");
6430 if (*version != '\0')
6431 entry->version=ConstantString(version);
6433 entry->note=ConstantString(PNGNote);
6434 (void) RegisterMagickInfo(entry);
6436 entry=SetMagickInfo("PNG8");
6438 #if defined(MAGICKCORE_PNG_DELEGATE)
6439 entry->decoder=(DecodeImageHandler *) ReadPNGImage;
6440 entry->encoder=(EncodeImageHandler *) WritePNGImage;
6443 entry->magick=(IsImageFormatHandler *) IsPNG;
6444 entry->adjoin=MagickFalse;
6445 entry->description=ConstantString(
6446 "8-bit indexed with optional binary transparency");
6447 entry->module=ConstantString("PNG");
6448 (void) RegisterMagickInfo(entry);
6450 entry=SetMagickInfo("PNG24");
6453 #if defined(ZLIB_VERSION)
6454 (void) ConcatenateMagickString(version,"zlib ",MaxTextExtent);
6455 (void) ConcatenateMagickString(version,ZLIB_VERSION,MaxTextExtent);
6457 if (LocaleCompare(ZLIB_VERSION,zlib_version) != 0)
6459 (void) ConcatenateMagickString(version,",",MaxTextExtent);
6460 (void) ConcatenateMagickString(version,zlib_version,MaxTextExtent);
6464 if (*version != '\0')
6465 entry->version=ConstantString(version);
6467 #if defined(MAGICKCORE_PNG_DELEGATE)
6468 entry->decoder=(DecodeImageHandler *) ReadPNGImage;
6469 entry->encoder=(EncodeImageHandler *) WritePNGImage;
6472 entry->magick=(IsImageFormatHandler *) IsPNG;
6473 entry->adjoin=MagickFalse;
6474 entry->description=ConstantString("opaque 24-bit RGB");
6475 entry->module=ConstantString("PNG");
6476 (void) RegisterMagickInfo(entry);
6478 entry=SetMagickInfo("PNG32");
6480 #if defined(MAGICKCORE_PNG_DELEGATE)
6481 entry->decoder=(DecodeImageHandler *) ReadPNGImage;
6482 entry->encoder=(EncodeImageHandler *) WritePNGImage;
6485 entry->magick=(IsImageFormatHandler *) IsPNG;
6486 entry->adjoin=MagickFalse;
6487 entry->description=ConstantString("opaque or transparent 32-bit RGBA");
6488 entry->module=ConstantString("PNG");
6489 (void) RegisterMagickInfo(entry);
6491 entry=SetMagickInfo("JNG");
6493 #if defined(JNG_SUPPORTED)
6494 #if defined(MAGICKCORE_PNG_DELEGATE)
6495 entry->decoder=(DecodeImageHandler *) ReadJNGImage;
6496 entry->encoder=(EncodeImageHandler *) WriteJNGImage;
6500 entry->magick=(IsImageFormatHandler *) IsJNG;
6501 entry->adjoin=MagickFalse;
6502 entry->description=ConstantString("JPEG Network Graphics");
6503 entry->module=ConstantString("PNG");
6504 entry->note=ConstantString(JNGNote);
6505 (void) RegisterMagickInfo(entry);
6507 #if defined(PNG_SETJMP_NOT_THREAD_SAFE)
6508 png_semaphore=AllocateSemaphoreInfo();
6511 return(MagickImageCoderSignature);
6515 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6519 % U n r e g i s t e r P N G I m a g e %
6523 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6525 % UnregisterPNGImage() removes format registrations made by the
6526 % PNG module from the list of supported formats.
6528 % The format of the UnregisterPNGImage method is:
6530 % UnregisterPNGImage(void)
6533 ModuleExport void UnregisterPNGImage(void)
6535 (void) UnregisterMagickInfo("MNG");
6536 (void) UnregisterMagickInfo("PNG");
6537 (void) UnregisterMagickInfo("PNG8");
6538 (void) UnregisterMagickInfo("PNG24");
6539 (void) UnregisterMagickInfo("PNG32");
6540 (void) UnregisterMagickInfo("JNG");
6542 #if defined(PNG_SETJMP_NOT_THREAD_SAFE)
6543 if (png_semaphore != (SemaphoreInfo *) NULL)
6544 DestroySemaphoreInfo(&png_semaphore);
6548 #if defined(MAGICKCORE_PNG_DELEGATE)
6549 #if PNG_LIBPNG_VER > 10011
6551 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6555 % W r i t e M N G I m a g e %
6559 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6561 % WriteMNGImage() writes an image in the Portable Network Graphics
6562 % Group's "Multiple-image Network Graphics" encoded image format.
6564 % MNG support written by Glenn Randers-Pehrson, glennrp@image...
6566 % The format of the WriteMNGImage method is:
6568 % MagickBooleanType WriteMNGImage(const ImageInfo *image_info,Image *image)
6570 % A description of each parameter follows.
6572 % o image_info: the image info.
6574 % o image: The image.
6577 % To do (as of version 5.5.2, November 26, 2002 -- glennrp -- see also
6578 % "To do" under ReadPNGImage):
6580 % Fix problem with palette sorting (when PNG_SORT_PALETTE is enabled,
6581 % some GIF animations don't convert properly)
6583 % Preserve all unknown and not-yet-handled known chunks found in input
6584 % PNG file and copy them into output PNG files according to the PNG
6587 % Write the iCCP chunk at MNG level when (icc profile length > 0)
6589 % Improve selection of color type (use indexed-colour or indexed-colour
6590 % with tRNS when 256 or fewer unique RGBA values are present).
6592 % Figure out what to do with "dispose=<restore-to-previous>" (dispose == 3)
6593 % This will be complicated if we limit ourselves to generating MNG-LC
6594 % files. For now we ignore disposal method 3 and simply overlay the next
6597 % Check for identical PLTE's or PLTE/tRNS combinations and use a
6598 % global MNG PLTE or PLTE/tRNS combination when appropriate.
6599 % [mostly done 15 June 1999 but still need to take care of tRNS]
6601 % Check for identical sRGB and replace with a global sRGB (and remove
6602 % gAMA/cHRM if sRGB is found; check for identical gAMA/cHRM and
6603 % replace with global gAMA/cHRM (or with sRGB if appropriate; replace
6604 % local gAMA/cHRM with local sRGB if appropriate).
6606 % Check for identical sBIT chunks and write global ones.
6608 % Provide option to skip writing the signature tEXt chunks.
6610 % Use signatures to detect identical objects and reuse the first
6611 % instance of such objects instead of writing duplicate objects.
6613 % Use a smaller-than-32k value of compression window size when
6616 % Encode JNG datastreams. Mostly done as of 5.5.2; need to write
6617 % ancillary text chunks and save profiles.
6619 % Provide an option to force LC files (to ensure exact framing rate)
6622 % Provide an option to force VLC files instead of LC, even when offsets
6623 % are present. This will involve expanding the embedded images with a
6624 % transparent region at the top and/or left.
6628 png_write_raw_profile(const ImageInfo *image_info,png_struct *ping,
6629 png_info *ping_info, unsigned char *profile_type, unsigned char
6630 *profile_description, unsigned char *profile_data, png_uint_32 length)
6649 hex[16]={'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
6651 if (LocaleNCompare((char *) profile_type+1, "ng-chunk-",9) == 0)
6654 if (image_info->verbose)
6656 (void) printf("writing raw profile: type=%s, length=%.20g\n",
6657 (char *) profile_type, (double) length);
6660 text=(png_textp) png_malloc(ping,(png_uint_32) sizeof(png_text));
6661 description_length=(png_uint_32) strlen((const char *) profile_description);
6662 allocated_length=(png_uint_32) (length*2 + (length >> 5) + 20
6663 + description_length);
6664 text[0].text=(png_charp) png_malloc(ping,allocated_length);
6665 text[0].key=(png_charp) png_malloc(ping, (png_uint_32) 80);
6666 text[0].key[0]='\0';
6667 (void) ConcatenateMagickString(text[0].key,
6668 "Raw profile type ",MaxTextExtent);
6669 (void) ConcatenateMagickString(text[0].key,(const char *) profile_type,62);
6673 (void) CopyMagickString(dp,(const char *) profile_description,
6675 dp+=description_length;
6677 (void) FormatMagickString(dp,allocated_length-
6678 (png_size_t) (dp-text[0].text),"%8lu ",(unsigned long) length);
6681 for (i=0; i < (ssize_t) length; i++)
6685 *(dp++)=(char) hex[((*sp >> 4) & 0x0f)];
6686 *(dp++)=(char) hex[((*sp++ ) & 0x0f)];
6691 text[0].text_length=(png_size_t) (dp-text[0].text);
6692 text[0].compression=image_info->compression == NoCompression ||
6693 (image_info->compression == UndefinedCompression &&
6694 text[0].text_length < 128) ? -1 : 0;
6696 if (text[0].text_length <= allocated_length)
6697 png_set_text(ping,ping_info,text,1);
6699 png_free(ping,text[0].text);
6700 png_free(ping,text[0].key);
6701 png_free(ping,text);
6704 static MagickBooleanType png_write_chunk_from_profile(Image *image,
6705 const char *string, MagickBooleanType logging)
6718 ResetImageProfileIterator(image);
6720 for (name=GetNextImageProfile(image); name != (const char *) NULL; )
6722 profile=GetImageProfile(image,name);
6724 if (profile != (const StringInfo *) NULL)
6729 if (LocaleNCompare(name,string,11) == 0)
6731 if (logging != MagickFalse)
6732 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6733 " Found %s profile",name);
6735 png_profile=CloneStringInfo(profile);
6736 data=GetStringInfoDatum(png_profile),
6737 length=(png_uint_32) GetStringInfoLength(png_profile);
6742 (void) WriteBlobMSBULong(image,length-5); /* data length */
6743 (void) WriteBlob(image,length-1,data+1);
6744 (void) WriteBlobMSBULong(image,crc32(0,data+1,(uInt) length-1));
6745 png_profile=DestroyStringInfo(png_profile);
6749 name=GetNextImageProfile(image);
6756 /* Write one PNG image */
6757 static MagickBooleanType WriteOnePNGImage(MngInfo *mng_info,
6758 const ImageInfo *IMimage_info,Image *IMimage)
6782 ping_trans_alpha[256];
6820 /* ping_exclude_iTXt, */
6827 ping_exclude_zCCP, /* hex-encoded iCCP */
6830 ping_need_colortype_warning,
6848 ping_interlace_method,
6849 ping_compression_method,
6865 number_semitransparent,
6867 ping_pHYs_unit_type;
6870 ping_pHYs_x_resolution,
6871 ping_pHYs_y_resolution;
6873 logging=LogMagickEvent(CoderEvent,GetMagickModule(),
6874 " enter WriteOnePNGImage()");
6876 image = CloneImage(IMimage,0,0,MagickFalse,&IMimage->exception);
6877 image_info=(ImageInfo *) CloneImageInfo(IMimage_info);
6879 if (mng_info->need_blob != MagickFalse)
6881 if (OpenBlob(image_info,image,WriteBinaryBlobMode,&image->exception) ==
6884 image_info=DestroyImageInfo(image_info);
6885 image=DestroyImage(image);
6886 return(MagickFalse);
6890 #if defined(PNG_SETJMP_NOT_THREAD_SAFE)
6891 LockSemaphoreInfo(png_semaphore);
6894 /* Initialize some stuff */
6897 ping_interlace_method=0,
6898 ping_compression_method=0,
6899 ping_filter_method=0,
6902 ping_background.red = 0;
6903 ping_background.green = 0;
6904 ping_background.blue = 0;
6905 ping_background.gray = 0;
6906 ping_background.index = 0;
6908 ping_trans_color.red=0;
6909 ping_trans_color.green=0;
6910 ping_trans_color.blue=0;
6911 ping_trans_color.gray=0;
6913 ping_pHYs_unit_type = 0;
6914 ping_pHYs_x_resolution = 0;
6915 ping_pHYs_y_resolution = 0;
6917 ping_have_color=MagickTrue;
6918 ping_have_PLTE=MagickFalse;
6919 ping_have_bKGD=MagickFalse;
6920 ping_have_pHYs=MagickFalse;
6921 ping_have_tRNS=MagickFalse;
6923 ping_exclude_bKGD=mng_info->ping_exclude_bKGD;
6924 ping_exclude_cHRM=mng_info->ping_exclude_cHRM;
6925 ping_exclude_EXIF=mng_info->ping_exclude_EXIF; /* hex-encoded EXIF in zTXt */
6926 ping_exclude_gAMA=mng_info->ping_exclude_gAMA;
6927 ping_exclude_cHRM=mng_info->ping_exclude_cHRM;
6928 ping_exclude_iCCP=mng_info->ping_exclude_iCCP;
6929 /* ping_exclude_iTXt=mng_info->ping_exclude_iTXt; */
6930 ping_exclude_oFFs=mng_info->ping_exclude_oFFs;
6931 ping_exclude_pHYs=mng_info->ping_exclude_pHYs;
6932 ping_exclude_sRGB=mng_info->ping_exclude_sRGB;
6933 ping_exclude_tEXt=mng_info->ping_exclude_tEXt;
6934 ping_exclude_tRNS=mng_info->ping_exclude_tRNS;
6935 ping_exclude_vpAg=mng_info->ping_exclude_vpAg;
6936 ping_exclude_zCCP=mng_info->ping_exclude_zCCP; /* hex-encoded iCCP in zTXt */
6937 ping_exclude_zTXt=mng_info->ping_exclude_zTXt;
6939 ping_need_colortype_warning = MagickFalse;
6942 number_semitransparent = 0;
6943 number_transparent = 0;
6945 if (image->colorspace != RGBColorspace)
6946 (void) TransformImageColorspace(image,RGBColorspace);
6949 Sometimes we get PseudoClass images whose RGB values don't match
6950 the colors in the colormap. This code syncs the RGB values.
6952 if (image->depth <= 8 && image->taint && image->storage_class == PseudoClass)
6953 (void) SyncImage(image);
6955 #if (MAGICKCORE_QUANTUM_DEPTH > 16)
6956 /* PNG does not handle depths greater than 16 so reduce it even
6959 if (image->depth > 16)
6963 #if (MAGICKCORE_QUANTUM_DEPTH >= 16)
6964 if (image->depth == 16 && mng_info->write_png_colortype != 16)
6965 if (mng_info->write_png8 || LosslessReduceDepthOK(image) != MagickFalse)
6969 #ifdef PNG_BUILD_PALETTE
6970 if (mng_info->write_png_colortype < 8 /* all */)
6973 * Sometimes we get DirectClass images that have 256 colors or fewer.
6974 * This code will build a colormap.
6976 * Also, sometimes we get PseudoClass images with an out-of-date
6977 * colormap. This code will replace the colormap with a new one.
6978 * Sometimes we get PseudoClass images that have more than 256 colors.
6979 * This code will delete the colormap and change the image to
6982 * Also we gather some information (number of opaque, transparent,
6983 * and semitransparent pixels, and whether the image has any non-gray
6984 * pixels) that we might need later. If the user wants to force
6985 * GrayAlpha or RGBA (colortype 4 or 6) we probably don't need any
6998 semitransparent[260],
7001 register IndexPacket
7004 register const PixelPacket
7007 if (logging != MagickFalse)
7008 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7009 " Enter BUILD_PALETTE:");
7011 image->colors=GetNumberColors(image,(FILE *) NULL,&image->exception);
7012 image_colors=(int) image->colors;
7014 if (logging != MagickFalse)
7016 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7017 " image->columns=%.20g",(double) image->columns);
7018 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7019 " image->rows=%.20g",(double) image->rows);
7020 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7021 " image->matte=%.20g",(double) image->matte);
7022 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7023 " image->depth=%.20g",(double) image->depth);
7025 if (image->colormap != NULL)
7027 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7028 " Original colormap:");
7029 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7030 " i (red,green,blue,opacity)");
7032 for (i=0; i < (ssize_t) image->colors; i++)
7034 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7035 " %d (%d,%d,%d,%d)",
7037 (int) image->colormap[i].red,
7038 (int) image->colormap[i].green,
7039 (int) image->colormap[i].blue,
7040 (int) image->colormap[i].opacity);
7044 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7045 " image->colors=%d",(int) image->colors);
7047 if (image->colors == 0)
7048 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7049 " (zero means unknown)");
7051 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7052 " Regenerate the colormap");
7055 exception=(&image->exception);
7057 ping_have_color=MagickFalse;
7060 for (y=0; y < (ssize_t) image->rows; y++)
7062 q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
7064 if (q == (PixelPacket *) NULL)
7067 for (x=0; x < (ssize_t) image->columns; x++)
7069 if (q->red != q->green || q->red != q->blue)
7070 ping_have_color=MagickTrue;
7072 if (image_colors == 0)
7074 /* Initialize the colormap */
7077 if (image->matte == MagickFalse)
7078 colormap[0].opacity = OpaqueOpacity;
7083 for (i=0; i< (ssize_t) image_colors; i++)
7085 if (((image->matte == MagickFalse ||
7086 colormap[i].opacity == q->opacity)) &&
7087 (IsColorEqual(colormap+i, (PixelPacket *) q)))
7091 if (i == (ssize_t) image_colors && image_colors < 299)
7098 if (image->matte == MagickFalse)
7099 colormap[i].opacity = OpaqueOpacity;
7107 if (logging != MagickFalse)
7109 if (image_colors >= 800)
7110 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7111 " image has more than 800 colors");
7114 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7115 " image has %d colors",image_colors);
7119 Initialize image colormap.
7122 if (logging != MagickFalse)
7123 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7124 " Sort the new colormap");
7126 /* Sort palette, transparent first */;
7127 for (i=0; i< (ssize_t) image_colors; i++)
7129 if (colormap[i].opacity == OpaqueOpacity)
7130 opaque[number_opaque++] = colormap[i];
7132 else if (colormap[i].opacity == TransparentOpacity)
7133 transparent[number_transparent++] = colormap[i];
7136 semitransparent[number_semitransparent++] =
7143 for (i=0; i<number_transparent; i++)
7144 colormap[n++] = transparent[i];
7146 for (i=0; i<number_semitransparent; i++)
7147 colormap[n++] = semitransparent[i];
7149 for (i=0; i<number_opaque; i++)
7150 colormap[n++] = opaque[i];
7152 if (ping_exclude_bKGD == MagickFalse)
7154 /* Add the background color to the palette, if it
7155 * isn't already there.
7157 for (i=0; i<number_opaque; i++)
7159 if (IsColorEqual(opaque+i,
7160 &image->background_color))
7164 if (number_opaque < 257 && i == number_opaque)
7166 opaque[i]=image->background_color;
7167 opaque[i].opacity = OpaqueOpacity;
7172 if (number_transparent == 1)
7174 ping_trans_color.red= (unsigned short)(transparent[0].red);
7175 ping_trans_color.green= (unsigned short) (transparent[0].green);
7176 ping_trans_color.blue= (unsigned short) (transparent[0].blue);
7177 ping_trans_color.gray= (unsigned short) (transparent[0].blue);
7180 if (logging != MagickFalse)
7182 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7183 " number_transparent = %d",
7184 number_transparent);
7186 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7187 " number_opaque = %d",
7190 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7191 " number_semitransparent = %d",
7192 number_semitransparent);
7195 if ((mng_info->ping_exclude_tRNS == MagickFalse ||
7196 (number_transparent == 0 && number_semitransparent == 0)) &&
7197 (((mng_info->write_png_colortype-1) == PNG_COLOR_TYPE_PALETTE) ||
7198 (mng_info->write_png_colortype == 0)))
7200 if (logging != MagickFalse)
7202 if (n != (ssize_t) image_colors)
7203 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7204 " image_colors (%d) and n (%d) don't match",
7207 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7208 " AcquireImageColormap");
7211 image->colors = image_colors;
7213 if (AcquireImageColormap(image,image_colors) ==
7215 ThrowWriterException(ResourceLimitError,
7216 "MemoryAllocationFailed");
7218 for (i=0; i< (ssize_t) image_colors; i++)
7219 image->colormap[i] = colormap[i];
7221 if (logging != MagickFalse)
7223 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7224 " image->colors=%d (%d)",
7225 (int) image->colors, image_colors);
7227 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7228 " Update the pixel indexes");
7231 for (y=0; y < (ssize_t) image->rows; y++)
7233 q=GetAuthenticPixels(image,0,y,image->columns,1,
7236 if (q == (PixelPacket *) NULL)
7239 indexes=GetAuthenticIndexQueue(image);
7241 for (x=0; x < (ssize_t) image->columns; x++)
7243 for (i=0; i< (ssize_t) image_colors; i++)
7245 if ((image->matte == MagickFalse ||
7246 image->colormap[i].opacity == q->opacity) &&
7247 (IsColorEqual(&image->colormap[i],(PixelPacket *) q)))
7249 indexes[x]=(IndexPacket) i;
7256 if (SyncAuthenticPixels(image,exception) == MagickFalse)
7261 if (logging != MagickFalse)
7263 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7264 " image->colors=%d", (int) image->colors);
7266 if (image->colormap != NULL)
7268 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7269 " i (red,green,blue,opacity)");
7271 for (i=0; i < (ssize_t) image->colors; i++)
7273 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7274 " %d (%d,%d,%d,%d)",
7276 (int) image->colormap[i].red,
7277 (int) image->colormap[i].green,
7278 (int) image->colormap[i].blue,
7279 (int) image->colormap[i].opacity);
7283 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7284 " Exit BUILD_PALETTE:");
7287 #endif /* PNG_BUILD_PALETTE */
7289 if (mng_info->ping_exclude_tRNS != MagickFalse &&
7290 (number_transparent != 0 || number_semitransparent != 0))
7292 int colortype=mng_info->write_png_colortype;
7294 if (ping_have_color == MagickFalse)
7295 mng_info->write_png_colortype = 5;
7298 mng_info->write_png_colortype = 7;
7300 if (colortype != 0 && mng_info->write_png_colortype != (ssize_t) colortype)
7301 ping_need_colortype_warning=MagickTrue;
7305 image_depth=image->depth;
7307 quantum_info = (QuantumInfo *) NULL;
7309 image_colors=(int) image->colors;
7310 image_matte=image->matte;
7312 mng_info->IsPalette=image->storage_class == PseudoClass &&
7313 image_colors <= 256;
7316 Allocate the PNG structures
7318 #ifdef PNG_USER_MEM_SUPPORTED
7319 ping=png_create_write_struct_2(PNG_LIBPNG_VER_STRING,image,
7320 PNGErrorHandler,PNGWarningHandler,(void *) NULL,
7321 (png_malloc_ptr) png_IM_malloc,(png_free_ptr) png_IM_free);
7324 ping=png_create_write_struct(PNG_LIBPNG_VER_STRING,image,
7325 PNGErrorHandler,PNGWarningHandler);
7328 if (ping == (png_struct *) NULL)
7329 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
7331 ping_info=png_create_info_struct(ping);
7333 if (ping_info == (png_info *) NULL)
7335 png_destroy_write_struct(&ping,(png_info **) NULL);
7336 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
7339 png_set_write_fn(ping,image,png_put_data,png_flush_data);
7340 png_pixels=(unsigned char *) NULL;
7342 if (setjmp(png_jmpbuf(ping)))
7348 if (image_info->verbose)
7349 (void) printf("PNG write has failed.\n");
7351 png_destroy_write_struct(&ping,&ping_info);
7352 #if defined(PNG_SETJMP_NOT_THREAD_SAFE)
7353 UnlockSemaphoreInfo(png_semaphore);
7355 if (mng_info->need_blob != MagickFalse)
7356 (void) CloseBlob(image);
7357 image_info=DestroyImageInfo(image_info);
7358 image=DestroyImage(image);
7359 return(MagickFalse);
7362 Prepare PNG for writing.
7364 #if defined(PNG_MNG_FEATURES_SUPPORTED)
7365 if (mng_info->write_mng)
7366 (void) png_permit_mng_features(ping,PNG_ALL_MNG_FEATURES);
7369 # ifdef PNG_WRITE_EMPTY_PLTE_SUPPORTED
7370 if (mng_info->write_mng)
7371 png_permit_empty_plte(ping,MagickTrue);
7378 ping_width=(png_uint_32) image->columns;
7379 ping_height=(png_uint_32) image->rows;
7381 if (mng_info->write_png8 || mng_info->write_png24 || mng_info->write_png32)
7384 if (mng_info->write_png_depth != 0)
7385 image_depth=mng_info->write_png_depth;
7387 /* Adjust requested depth to next higher valid depth if necessary */
7388 if (image_depth > 8)
7391 if ((image_depth > 4) && (image_depth < 8))
7394 if (image_depth == 3)
7397 if (logging != MagickFalse)
7399 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7400 " width=%.20g",(double) ping_width);
7401 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7402 " height=%.20g",(double) ping_height);
7403 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7404 " image_matte=%.20g",(double) image->matte);
7405 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7406 " image->depth=%.20g",(double) image->depth);
7407 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7408 " Tentative ping_bit_depth=%.20g",(double) image_depth);
7411 save_image_depth=image_depth;
7412 ping_bit_depth=(png_byte) save_image_depth;
7415 #if defined(PNG_pHYs_SUPPORTED)
7416 if (ping_exclude_pHYs == MagickFalse)
7418 if ((image->x_resolution != 0) && (image->y_resolution != 0) &&
7419 (!mng_info->write_mng || !mng_info->equal_physs))
7421 if (logging != MagickFalse)
7422 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7423 " Setting up pHYs chunk");
7425 if (image->units == PixelsPerInchResolution)
7427 ping_pHYs_unit_type=PNG_RESOLUTION_METER;
7428 ping_pHYs_x_resolution=(png_uint_32) (100.0*image->x_resolution/2.54);
7429 ping_pHYs_y_resolution=(png_uint_32) (100.0*image->y_resolution/2.54);
7432 else if (image->units == PixelsPerCentimeterResolution)
7434 ping_pHYs_unit_type=PNG_RESOLUTION_METER;
7435 ping_pHYs_x_resolution=(png_uint_32) (100.0*image->x_resolution);
7436 ping_pHYs_y_resolution=(png_uint_32) (100.0*image->y_resolution);
7441 ping_pHYs_unit_type=PNG_RESOLUTION_UNKNOWN;
7442 ping_pHYs_x_resolution=(png_uint_32) image->x_resolution;
7443 ping_pHYs_y_resolution=(png_uint_32) image->y_resolution;
7446 ping_have_pHYs = MagickTrue;
7451 if (ping_exclude_bKGD == MagickFalse)
7453 if ((!mng_info->adjoin || !mng_info->equal_backgrounds))
7459 if (ping_bit_depth == 8)
7462 if (ping_bit_depth == 4)
7465 if (ping_bit_depth == 2)
7468 if (ping_bit_depth == 1)
7471 ping_background.red=(png_uint_16)
7472 (ScaleQuantumToShort(image->background_color.red) & mask);
7474 ping_background.green=(png_uint_16)
7475 (ScaleQuantumToShort(image->background_color.green) & mask);
7477 ping_background.blue=(png_uint_16)
7478 (ScaleQuantumToShort(image->background_color.blue) & mask);
7481 if (logging != MagickFalse)
7483 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7484 " Setting up bKGD chunk (1)");
7486 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7487 " ping_bit_depth=%d",ping_bit_depth);
7490 ping_have_bKGD = MagickTrue;
7494 Select the color type.
7499 if (mng_info->write_png8)
7502 /* TO DO: make this a function cause it's used twice, except
7503 for reducing the sample depth from 8. */
7505 number_colors=image_colors;
7507 ping_have_tRNS=MagickFalse;
7512 ping_color_type=(png_byte) PNG_COLOR_TYPE_PALETTE;
7514 if (logging != MagickFalse)
7515 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7516 " Setting up PLTE chunk with %d colors (%d)",
7517 number_colors, image_colors);
7519 for (i=0; i < (ssize_t) number_colors; i++)
7521 palette[i].red=ScaleQuantumToChar(image->colormap[i].red);
7522 palette[i].green=ScaleQuantumToChar(image->colormap[i].green);
7523 palette[i].blue=ScaleQuantumToChar(image->colormap[i].blue);
7524 if (logging != MagickFalse)
7525 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7526 #if MAGICKCORE_QUANTUM_DEPTH == 8
7527 " %3ld (%3d,%3d,%3d)",
7529 " %5ld (%5d,%5d,%5d)",
7531 (long) i,palette[i].red,palette[i].green,palette[i].blue);
7535 ping_have_PLTE=MagickTrue;
7536 image_depth=ping_bit_depth;
7539 if (matte != MagickFalse)
7542 Identify which colormap entry is transparent.
7544 assert(number_colors <= 256);
7545 assert(image->colormap != NULL);
7547 for (i=0; i < (ssize_t) number_transparent; i++)
7548 ping_trans_alpha[i]=0;
7550 /* PNG8 can't have semitransparent colors so we threshold them
7553 for (; i < (ssize_t) number_semitransparent; i++)
7554 ping_trans_alpha[i]=image->colormap[i].opacity >
7555 OpaqueOpacity/2 ? 0 : 255;
7557 ping_num_trans=(unsigned short) (number_transparent +
7558 number_semitransparent);
7560 if (ping_num_trans == 0)
7561 ping_have_tRNS=MagickFalse;
7564 ping_have_tRNS=MagickTrue;
7567 if (ping_exclude_bKGD == MagickFalse)
7570 * Identify which colormap entry is the background color.
7572 for (i=0; i < (ssize_t) MagickMax(1L*number_colors-1L,1L); i++)
7573 if (IsPNGColorEqual(ping_background,image->colormap[i]))
7576 ping_background.index=(png_byte) i;
7578 } /* end of write_png8 */
7580 else if (mng_info->write_png24)
7582 image_matte=MagickFalse;
7583 ping_color_type=(png_byte) PNG_COLOR_TYPE_RGB;
7586 else if (mng_info->write_png32)
7588 image_matte=MagickTrue;
7589 ping_color_type=(png_byte) PNG_COLOR_TYPE_RGB_ALPHA;
7592 else /* mng_info->write_pngNN not specified */
7594 image_depth=ping_bit_depth;
7596 if (mng_info->write_png_colortype != 0)
7598 ping_color_type=(png_byte) mng_info->write_png_colortype-1;
7600 if (ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA ||
7601 ping_color_type == PNG_COLOR_TYPE_RGB_ALPHA)
7602 image_matte=MagickTrue;
7605 image_matte=MagickFalse;
7608 else /* write_ping_colortype not specified */
7610 if (logging != MagickFalse)
7611 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7612 " Selecting PNG colortype:");
7614 ping_color_type=(png_byte) ((matte != MagickFalse)?
7615 PNG_COLOR_TYPE_RGB_ALPHA:PNG_COLOR_TYPE_RGB);
7617 if (image_info->type == TrueColorType)
7619 ping_color_type=(png_byte) PNG_COLOR_TYPE_RGB;
7620 image_matte=MagickFalse;
7623 if (image_info->type == TrueColorMatteType)
7625 ping_color_type=(png_byte) PNG_COLOR_TYPE_RGB_ALPHA;
7626 image_matte=MagickTrue;
7629 if (image_info->type == PaletteType ||
7630 image_info->type == PaletteMatteType)
7631 ping_color_type=(png_byte) PNG_COLOR_TYPE_PALETTE;
7633 if (image_info->type == UndefinedType ||
7634 image_info->type == OptimizeType)
7636 if (ping_have_color == MagickFalse)
7638 if (image_matte == MagickFalse)
7640 ping_color_type=(png_byte) PNG_COLOR_TYPE_GRAY;
7641 image_matte=MagickFalse;
7646 ping_color_type=(png_byte) PNG_COLOR_TYPE_GRAY_ALPHA;
7647 image_matte=MagickTrue;
7652 if (image_matte == MagickFalse)
7654 ping_color_type=(png_byte) PNG_COLOR_TYPE_RGB;
7655 image_matte=MagickFalse;
7660 ping_color_type=(png_byte) PNG_COLOR_TYPE_RGBA;
7661 image_matte=MagickTrue;
7668 if (logging != MagickFalse)
7669 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7670 " Selected PNG colortype=%d",ping_color_type);
7672 if (ping_bit_depth < 8)
7674 if (ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA ||
7675 ping_color_type == PNG_COLOR_TYPE_RGB ||
7676 ping_color_type == PNG_COLOR_TYPE_RGB_ALPHA)
7680 old_bit_depth=ping_bit_depth;
7682 if (ping_color_type == PNG_COLOR_TYPE_GRAY)
7684 if (image->matte == MagickFalse && image->colors < 256)
7686 if (ImageIsMonochrome(image))
7693 if (ping_color_type == PNG_COLOR_TYPE_PALETTE)
7698 if (image->colors == 0)
7701 (void) ThrowMagickException(&image->exception,
7702 GetMagickModule(),CoderError,
7703 "image has 0 colors", "`%s'","");
7706 while ((int) (one << ping_bit_depth) < (ssize_t) image_colors)
7707 ping_bit_depth <<= 1;
7710 if (logging != MagickFalse)
7712 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7713 " Number of colors: %.20g",(double) image_colors);
7715 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7716 " Tentative PNG bit depth: %d",ping_bit_depth);
7719 if (ping_bit_depth < (int) mng_info->write_png_depth)
7720 ping_bit_depth = mng_info->write_png_depth;
7723 image_depth=ping_bit_depth;
7725 if (logging != MagickFalse)
7727 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7728 " Tentative PNG color type: %.20g",(double) ping_color_type);
7730 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7731 " image_info->type: %.20g",(double) image_info->type);
7733 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7734 " image_depth: %.20g",(double) image_depth);
7736 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7738 " image->depth: %.20g",(double) image->depth);
7740 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7741 " ping_bit_depth: %.20g",(double) ping_bit_depth);
7744 if (matte != MagickFalse)
7746 if (mng_info->IsPalette)
7749 ping_color_type=PNG_COLOR_TYPE_GRAY_ALPHA;
7751 if (ping_have_color != MagickFalse)
7752 ping_color_type=PNG_COLOR_TYPE_RGBA;
7755 * Determine if there is any transparent color.
7757 if (number_transparent + number_semitransparent == 0)
7760 No transparent pixels are present. Change 4 or 6 to 0 or 2.
7762 image_matte=MagickFalse;
7763 ping_color_type&=0x03;
7773 if (ping_bit_depth == 8)
7776 if (ping_bit_depth == 4)
7779 if (ping_bit_depth == 2)
7782 if (ping_bit_depth == 1)
7785 ping_trans_color.red=(png_uint_16)
7786 (ScaleQuantumToShort(image->colormap[0].red) & mask);
7788 ping_trans_color.green=(png_uint_16)
7789 (ScaleQuantumToShort(image->colormap[0].green) & mask);
7791 ping_trans_color.blue=(png_uint_16)
7792 (ScaleQuantumToShort(image->colormap[0].blue) & mask);
7794 ping_trans_color.gray=(png_uint_16)
7795 (ScaleQuantumToShort(PixelIntensityToQuantum(
7796 image->colormap)) & mask);
7798 ping_trans_color.index=(png_byte) 0;
7800 ping_have_tRNS=MagickTrue;
7803 if (ping_have_tRNS != MagickFalse)
7806 Determine if there is one and only one transparent color
7807 and if so if it is fully transparent.
7809 if (logging != MagickFalse)
7810 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7811 " Is there a single fully transparent color?");
7813 if (number_transparent > 1 || number_semitransparent > 0)
7815 ping_have_tRNS = MagickFalse;
7816 if (logging != MagickFalse)
7817 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7822 if (logging != MagickFalse)
7823 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7824 " ... Yes: (%d,%d,%d), (gray: %d)",
7825 (int) ping_trans_color.red,
7826 (int) ping_trans_color.green,
7827 (int) ping_trans_color.blue,
7828 (int) ping_trans_color.gray);
7832 if (ping_have_tRNS != MagickFalse)
7834 ping_color_type &= 0x03; /* changes 4 or 6 to 0 or 2 */
7836 if (image_depth == 8)
7838 ping_trans_color.red&=0xff;
7839 ping_trans_color.green&=0xff;
7840 ping_trans_color.blue&=0xff;
7841 ping_trans_color.gray&=0xff;
7847 if (image_depth == 8)
7849 ping_trans_color.red&=0xff;
7850 ping_trans_color.green&=0xff;
7851 ping_trans_color.blue&=0xff;
7852 ping_trans_color.gray&=0xff;
7859 if (ping_have_tRNS != MagickFalse)
7860 image_matte=MagickFalse;
7862 if ((mng_info->IsPalette) &&
7863 mng_info->write_png_colortype-1 != PNG_COLOR_TYPE_PALETTE &&
7864 ImageIsGray(image) && (image_matte == MagickFalse || image_depth >= 8))
7868 if (image_matte != MagickFalse)
7869 ping_color_type=PNG_COLOR_TYPE_GRAY_ALPHA;
7873 ping_color_type=PNG_COLOR_TYPE_GRAY;
7875 if (save_image_depth == 16 && image_depth == 8)
7877 if (logging != MagickFalse)
7879 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7880 " Scaling ping_trans_color (0)");
7882 ping_trans_color.gray*=0x0101;
7886 if (image_depth > MAGICKCORE_QUANTUM_DEPTH)
7887 image_depth=MAGICKCORE_QUANTUM_DEPTH;
7889 if (image_colors == 0 || image_colors-1 > MaxColormapSize)
7890 image_colors=(int) (one << image_depth);
7892 if (image_depth > 8)
7898 if ((int) ping_color_type == PNG_COLOR_TYPE_PALETTE)
7900 if(!mng_info->write_png_depth)
7904 while ((int) (one << ping_bit_depth)
7905 < (ssize_t) image_colors)
7906 ping_bit_depth <<= 1;
7910 else if (ping_color_type ==
7911 PNG_COLOR_TYPE_GRAY && image_colors < 17 &&
7912 mng_info->IsPalette)
7915 /* Check if grayscale is reducible */
7917 depth_4_ok=MagickTrue,
7918 depth_2_ok=MagickTrue,
7919 depth_1_ok=MagickTrue;
7921 for (i=0; i < (ssize_t) image_colors; i++)
7926 intensity=ScaleQuantumToChar(image->colormap[i].red);
7928 if ((intensity & 0x0f) != ((intensity & 0xf0) >> 4))
7929 depth_4_ok=depth_2_ok=depth_1_ok=MagickFalse;
7931 else if ((intensity & 0x03) != ((intensity & 0x0c) >> 2))
7932 depth_2_ok=depth_1_ok=MagickFalse;
7934 else if ((intensity & 0x01) != ((intensity & 0x02) >> 1))
7935 depth_1_ok=MagickFalse;
7938 if (depth_1_ok && mng_info->write_png_depth <= 1)
7941 else if (depth_2_ok && mng_info->write_png_depth <= 2)
7944 else if (depth_4_ok && mng_info->write_png_depth <= 4)
7949 image_depth=ping_bit_depth;
7954 if (mng_info->IsPalette)
7956 number_colors=image_colors;
7958 if (image_depth <= 8)
7963 ping_color_type=(png_byte) PNG_COLOR_TYPE_PALETTE;
7965 if (mng_info->have_write_global_plte && matte == MagickFalse)
7967 png_set_PLTE(ping,ping_info,NULL,0);
7969 if (logging != MagickFalse)
7970 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7971 " Setting up empty PLTE chunk");
7976 for (i=0; i < (ssize_t) number_colors; i++)
7978 palette[i].red=ScaleQuantumToChar(image->colormap[i].red);
7979 palette[i].green=ScaleQuantumToChar(image->colormap[i].green);
7980 palette[i].blue=ScaleQuantumToChar(image->colormap[i].blue);
7983 if (logging != MagickFalse)
7984 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7985 " Setting up PLTE chunk with %d colors",
7988 ping_have_PLTE=MagickTrue;
7991 /* color_type is PNG_COLOR_TYPE_PALETTE */
7992 if (mng_info->write_png_depth == 0)
8000 while ((one << ping_bit_depth) < number_colors)
8001 ping_bit_depth <<= 1;
8006 if (matte != MagickFalse)
8009 * Set up trans_colors array.
8011 assert(number_colors <= 256);
8013 ping_num_trans=(unsigned short) (number_transparent +
8014 number_semitransparent);
8016 if (ping_num_trans == 0)
8017 ping_have_tRNS=MagickFalse;
8021 if (logging != MagickFalse)
8023 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8024 " Scaling ping_trans_color (1)");
8026 ping_have_tRNS=MagickTrue;
8028 for (i=0; i < ping_num_trans; i++)
8030 ping_trans_alpha[i]= (png_byte) (255-
8031 ScaleQuantumToChar(image->colormap[i].opacity));
8041 if (image_depth < 8)
8044 if ((save_image_depth == 16) && (image_depth == 8))
8046 if (logging != MagickFalse)
8048 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8049 " Scaling ping_trans_color from (%d,%d,%d)",
8050 (int) ping_trans_color.red,
8051 (int) ping_trans_color.green,
8052 (int) ping_trans_color.blue);
8055 ping_trans_color.red*=0x0101;
8056 ping_trans_color.green*=0x0101;
8057 ping_trans_color.blue*=0x0101;
8058 ping_trans_color.gray*=0x0101;
8060 if (logging != MagickFalse)
8062 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8064 (int) ping_trans_color.red,
8065 (int) ping_trans_color.green,
8066 (int) ping_trans_color.blue);
8071 if (ping_bit_depth < (ssize_t) mng_info->write_png_depth)
8072 ping_bit_depth = (ssize_t) mng_info->write_png_depth;
8075 Adjust background and transparency samples in sub-8-bit grayscale files.
8077 if (ping_bit_depth < 8 && ping_color_type ==
8078 PNG_COLOR_TYPE_GRAY)
8086 maxval=(png_uint_16) ((one << ping_bit_depth)-1);
8088 if (ping_exclude_bKGD == MagickFalse)
8091 ping_background.gray=(png_uint_16)
8092 (QuantumScale*(maxval*(PixelIntensity(&image->background_color))));
8094 if (logging != MagickFalse)
8095 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8096 " Setting up bKGD chunk (2)");
8098 ping_have_bKGD = MagickTrue;
8101 ping_trans_color.gray=(png_uint_16) (QuantumScale*(maxval*
8102 ping_trans_color.gray));
8105 if (ping_exclude_bKGD == MagickFalse)
8107 if ((int) ping_color_type == PNG_COLOR_TYPE_PALETTE)
8110 Identify which colormap entry is the background color.
8113 number_colors=image_colors;
8115 for (i=0; i < (ssize_t) MagickMax(1L*number_colors,1L); i++)
8116 if (IsPNGColorEqual(image->background_color,image->colormap[i]))
8119 ping_background.index=(png_byte) i;
8121 if (logging != MagickFalse)
8123 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8124 " Setting up bKGD chunk with index=%d",(int) i);
8127 if (i < (ssize_t) number_colors)
8129 ping_have_bKGD = MagickTrue;
8131 if (logging != MagickFalse)
8133 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8134 " background =(%d,%d,%d)",
8135 (int) ping_background.red,
8136 (int) ping_background.green,
8137 (int) ping_background.blue);
8141 else /* Can't happen */
8143 if (logging != MagickFalse)
8144 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8145 " No room in PLTE to add bKGD color");
8146 ping_have_bKGD = MagickFalse;
8151 if (logging != MagickFalse)
8152 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8153 " PNG color type: %d",ping_color_type);
8155 Initialize compression level and filtering.
8157 if (logging != MagickFalse)
8159 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8160 " Setting up deflate compression");
8162 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8163 " Compression buffer size: 32768");
8166 png_set_compression_buffer_size(ping,32768L);
8168 if (logging != MagickFalse)
8169 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8170 " Compression mem level: 9");
8172 png_set_compression_mem_level(ping, 9);
8174 quality=image->quality == UndefinedCompressionQuality ? 75UL :
8182 level=(int) MagickMin((ssize_t) quality/10,9);
8184 if (logging != MagickFalse)
8185 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8186 " Compression level: %d",level);
8188 png_set_compression_level(ping,level);
8193 if (logging != MagickFalse)
8194 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8195 " Compression strategy: Z_HUFFMAN_ONLY");
8197 png_set_compression_strategy(ping, Z_HUFFMAN_ONLY);
8200 if (logging != MagickFalse)
8201 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8202 " Setting up filtering");
8204 #if defined(PNG_MNG_FEATURES_SUPPORTED) && defined(PNG_INTRAPIXEL_DIFFERENCING)
8205 /* This became available in libpng-1.0.9. Output must be a MNG. */
8206 if (mng_info->write_mng && ((quality % 10) == 7))
8208 if (logging != MagickFalse)
8209 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8210 " Filter_type: PNG_INTRAPIXEL_DIFFERENCING");
8212 ping_filter_method=PNG_INTRAPIXEL_DIFFERENCING;
8216 if (logging != MagickFalse)
8217 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8225 if ((quality % 10) > 5)
8226 base_filter=PNG_ALL_FILTERS;
8229 if ((quality % 10) != 5)
8230 base_filter=(int) quality % 10;
8233 if (((int) ping_color_type == PNG_COLOR_TYPE_GRAY) ||
8234 ((int) ping_color_type == PNG_COLOR_TYPE_PALETTE) ||
8236 base_filter=PNG_NO_FILTERS;
8239 base_filter=PNG_ALL_FILTERS;
8241 if (logging != MagickFalse)
8243 if (base_filter == PNG_ALL_FILTERS)
8244 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8245 " Base filter method: ADAPTIVE");
8247 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8248 " Base filter method: NONE");
8251 png_set_filter(ping,PNG_FILTER_TYPE_BASE,base_filter);
8254 if (ping_exclude_iCCP == MagickFalse || ping_exclude_zCCP == MagickFalse)
8256 ResetImageProfileIterator(image);
8257 for (name=GetNextImageProfile(image); name != (const char *) NULL; )
8259 profile=GetImageProfile(image,name);
8261 if (profile != (StringInfo *) NULL)
8263 #ifdef PNG_WRITE_iCCP_SUPPORTED
8264 if ((LocaleCompare(name,"ICC") == 0) ||
8265 (LocaleCompare(name,"ICM") == 0))
8268 if (ping_exclude_iCCP == MagickFalse)
8270 png_set_iCCP(ping,ping_info,(const png_charp) name,0,
8271 (png_charp) GetStringInfoDatum(profile),
8272 (png_uint_32) GetStringInfoLength(profile));
8278 if (ping_exclude_zCCP == MagickFalse)
8280 png_write_raw_profile(image_info,ping,ping_info,
8281 (unsigned char *) name,(unsigned char *) name,
8282 GetStringInfoDatum(profile),
8283 (png_uint_32) GetStringInfoLength(profile));
8287 if (logging != MagickFalse)
8288 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8289 " Setting up text chunk with %s profile",name);
8291 name=GetNextImageProfile(image);
8295 #if defined(PNG_WRITE_sRGB_SUPPORTED)
8296 if ((mng_info->have_write_global_srgb == 0) &&
8297 ((image->rendering_intent != UndefinedIntent) ||
8298 (image->colorspace == sRGBColorspace)))
8300 if (ping_exclude_sRGB == MagickFalse)
8303 Note image rendering intent.
8305 if (logging != MagickFalse)
8306 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8307 " Setting up sRGB chunk");
8309 (void) png_set_sRGB(ping,ping_info,(
8310 PNG_RenderingIntent_from_Magick_RenderingIntent(
8311 image->rendering_intent)));
8313 if (ping_exclude_gAMA == MagickFalse)
8314 png_set_gAMA(ping,ping_info,0.45455);
8318 if ((!mng_info->write_mng) || (!png_get_valid(ping,ping_info,PNG_INFO_sRGB)))
8321 if (ping_exclude_gAMA == MagickFalse &&
8322 (ping_exclude_sRGB == MagickFalse ||
8323 (image->gamma < .45 || image->gamma > .46)))
8325 if ((mng_info->have_write_global_gama == 0) && (image->gamma != 0.0))
8329 To do: check for cHRM+gAMA == sRGB, and write sRGB instead.
8331 if (logging != MagickFalse)
8332 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8333 " Setting up gAMA chunk");
8335 png_set_gAMA(ping,ping_info,image->gamma);
8339 if (ping_exclude_cHRM == MagickFalse)
8341 if ((mng_info->have_write_global_chrm == 0) &&
8342 (image->chromaticity.red_primary.x != 0.0))
8345 Note image chromaticity.
8346 To do: check for cHRM+gAMA == sRGB, and write sRGB instead.
8354 wp=image->chromaticity.white_point;
8355 rp=image->chromaticity.red_primary;
8356 gp=image->chromaticity.green_primary;
8357 bp=image->chromaticity.blue_primary;
8359 if (logging != MagickFalse)
8360 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8361 " Setting up cHRM chunk");
8363 png_set_cHRM(ping,ping_info,wp.x,wp.y,rp.x,rp.y,gp.x,gp.y,
8369 ping_interlace_method=image_info->interlace != NoInterlace;
8371 if (mng_info->write_mng)
8372 png_set_sig_bytes(ping,8);
8374 /* Bail out if cannot meet defined PNG:bit-depth or PNG:color-type */
8376 if (mng_info->write_png_colortype != 0)
8378 if (mng_info->write_png_colortype-1 == PNG_COLOR_TYPE_GRAY)
8379 if (ImageIsGray(image) == MagickFalse)
8381 ping_color_type = PNG_COLOR_TYPE_RGB;
8383 if (ping_bit_depth < 8)
8387 if (mng_info->write_png_colortype-1 == PNG_COLOR_TYPE_GRAY_ALPHA)
8388 if (ImageIsGray(image) == MagickFalse)
8389 ping_color_type = PNG_COLOR_TYPE_RGB_ALPHA;
8392 if (ping_need_colortype_warning != MagickFalse ||
8393 ((mng_info->write_png_depth &&
8394 (int) mng_info->write_png_depth != ping_bit_depth) ||
8395 (mng_info->write_png_colortype &&
8396 ((int) mng_info->write_png_colortype-1 != ping_color_type &&
8397 mng_info->write_png_colortype != 7 &&
8398 !(mng_info->write_png_colortype == 5 && ping_color_type == 0)))))
8400 if (logging != MagickFalse)
8402 if (ping_need_colortype_warning != MagickFalse)
8404 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8405 " Image has transparency but tRNS chunk was excluded");
8408 if (mng_info->write_png_depth)
8410 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8411 " Defined PNG:bit-depth=%u, Computed depth=%u",
8412 mng_info->write_png_depth,
8416 if (mng_info->write_png_colortype)
8418 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8419 " Defined PNG:color-type=%u, Computed color type=%u",
8420 mng_info->write_png_colortype-1,
8426 "Cannot write image with defined PNG:bit-depth or PNG:color-type.");
8429 if (image_matte != MagickFalse && image->matte == MagickFalse)
8431 /* Add an opaque matte channel */
8432 image->matte = MagickTrue;
8433 (void) SetImageOpacity(image,0);
8435 if (logging != MagickFalse)
8436 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8437 " Added an opaque matte channel");
8440 if (image->matte == MagickTrue)
8442 if (ping_color_type < 4)
8443 if (ping_color_type != 3 || ping_num_trans > 0)
8445 ping_have_tRNS=MagickTrue;
8446 if (logging != MagickFalse)
8447 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8448 " Setting ping_have_tRNS=MagickTrue.");
8452 if (logging != MagickFalse)
8453 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8454 " Writing PNG header chunks");
8456 png_set_IHDR(ping,ping_info,ping_width,ping_height,
8457 ping_bit_depth,ping_color_type,
8458 ping_interlace_method,ping_compression_method,
8459 ping_filter_method);
8461 if (ping_color_type == 3 && ping_have_PLTE != MagickFalse)
8463 png_set_PLTE(ping,ping_info,palette,number_colors);
8465 if (logging != MagickFalse)
8467 for (i=0; i< (ssize_t) number_colors; i++)
8469 if (i < ping_num_trans)
8470 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8471 " PLTE[%d] = (%d,%d,%d), tRNS[%d] = (%d)",
8473 (int) palette[i].red,
8474 (int) palette[i].green,
8475 (int) palette[i].blue,
8477 (int) ping_trans_alpha[i]);
8479 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8480 " PLTE[%d] = (%d,%d,%d)",
8482 (int) palette[i].red,
8483 (int) palette[i].green,
8484 (int) palette[i].blue);
8489 if (ping_exclude_bKGD == MagickFalse)
8491 if (ping_have_bKGD != MagickFalse)
8492 png_set_bKGD(ping,ping_info,&ping_background);
8495 if (ping_exclude_pHYs == MagickFalse)
8497 if (ping_have_pHYs != MagickFalse)
8499 png_set_pHYs(ping,ping_info,
8500 ping_pHYs_x_resolution,
8501 ping_pHYs_y_resolution,
8502 ping_pHYs_unit_type);
8506 #if defined(PNG_oFFs_SUPPORTED)
8507 if (ping_exclude_oFFs == MagickFalse)
8509 if (image->page.x || image->page.y)
8511 png_set_oFFs(ping,ping_info,(png_int_32) image->page.x,
8512 (png_int_32) image->page.y, 0);
8514 if (logging != MagickFalse)
8515 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8516 " Setting up oFFs chunk with x=%d, y=%d, units=0",
8517 (int) image->page.x, (int) image->page.y);
8522 png_write_info_before_PLTE(ping, ping_info);
8524 if (ping_have_tRNS != MagickFalse && ping_color_type < 4)
8526 if (logging != MagickFalse)
8528 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8529 " Calling png_set_tRNS with num_trans=%d",ping_num_trans);
8532 if (ping_color_type == 3)
8533 (void) png_set_tRNS(ping, ping_info,
8540 (void) png_set_tRNS(ping, ping_info,
8545 if (logging != MagickFalse)
8547 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8548 " tRNS color =(%d,%d,%d)",
8549 (int) ping_trans_color.red,
8550 (int) ping_trans_color.green,
8551 (int) ping_trans_color.blue);
8556 /* write any png-chunk-b profiles */
8557 (void) png_write_chunk_from_profile(image,"PNG-chunk-b",logging);
8558 png_write_info(ping,ping_info);
8560 /* write any PNG-chunk-m profiles */
8561 (void) png_write_chunk_from_profile(image,"PNG-chunk-m",logging);
8563 if (ping_exclude_vpAg == MagickFalse)
8565 if ((image->page.width != 0 && image->page.width != image->columns) ||
8566 (image->page.height != 0 && image->page.height != image->rows))
8571 (void) WriteBlobMSBULong(image,9L); /* data length=8 */
8572 PNGType(chunk,mng_vpAg);
8573 LogPNGChunk(logging,mng_vpAg,9L);
8574 PNGLong(chunk+4,(png_uint_32) image->page.width);
8575 PNGLong(chunk+8,(png_uint_32) image->page.height);
8576 chunk[12]=0; /* unit = pixels */
8577 (void) WriteBlob(image,13,chunk);
8578 (void) WriteBlobMSBULong(image,crc32(0,chunk,13));
8582 #if (PNG_LIBPNG_VER == 10206)
8583 /* avoid libpng-1.2.6 bug by setting PNG_HAVE_IDAT flag */
8584 #define PNG_HAVE_IDAT 0x04
8585 ping->mode |= PNG_HAVE_IDAT;
8586 #undef PNG_HAVE_IDAT
8589 png_set_packing(ping);
8593 rowbytes=image->columns;
8594 if (image_depth > 8)
8596 switch (ping_color_type)
8598 case PNG_COLOR_TYPE_RGB:
8602 case PNG_COLOR_TYPE_GRAY_ALPHA:
8606 case PNG_COLOR_TYPE_RGBA:
8614 if (logging != MagickFalse)
8616 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8617 " Writing PNG image data");
8619 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8620 " Allocating %.20g bytes of memory for pixels",(double) rowbytes);
8622 png_pixels=(unsigned char *) AcquireQuantumMemory(rowbytes,
8623 sizeof(*png_pixels));
8625 if (png_pixels == (unsigned char *) NULL)
8626 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
8629 Initialize image scanlines.
8631 if (setjmp(png_jmpbuf(ping)))
8637 if (image_info->verbose)
8638 (void) printf("PNG write has failed.\n");
8640 png_destroy_write_struct(&ping,&ping_info);
8641 if (quantum_info != (QuantumInfo *) NULL)
8642 quantum_info=DestroyQuantumInfo(quantum_info);
8643 if (png_pixels != (unsigned char *) NULL)
8644 png_pixels=(unsigned char *) RelinquishMagickMemory(png_pixels);
8645 #if defined(PNG_SETJMP_NOT_THREAD_SAFE)
8646 UnlockSemaphoreInfo(png_semaphore);
8648 if (mng_info->need_blob != MagickFalse)
8649 (void) CloseBlob(image);
8650 image_info=DestroyImageInfo(image_info);
8651 image=DestroyImage(image);
8652 return(MagickFalse);
8654 quantum_info=AcquireQuantumInfo(image_info,image);
8655 if (quantum_info == (QuantumInfo *) NULL)
8656 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
8657 quantum_info->format=UndefinedQuantumFormat;
8658 quantum_info->depth=image_depth;
8659 num_passes=png_set_interlace_handling(ping);
8661 if ((!mng_info->write_png8 && !mng_info->write_png24 &&
8662 !mng_info->write_png32) &&
8663 (mng_info->IsPalette ||
8664 (image_info->type == BilevelType)) &&
8665 image_matte == MagickFalse && ImageIsMonochrome(image))
8667 /* Palette, Bilevel, or Opaque Monochrome */
8668 register const PixelPacket
8671 quantum_info->depth=8;
8672 for (pass=0; pass < num_passes; pass++)
8675 Convert PseudoClass image to a PNG monochrome image.
8677 for (y=0; y < (ssize_t) image->rows; y++)
8680 if (logging != MagickFalse)
8681 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8682 " Writing row of pixels (0)");
8684 p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception);
8686 if (p == (const PixelPacket *) NULL)
8689 if (mng_info->IsPalette)
8691 (void) ExportQuantumPixels(image,(const CacheView *) NULL,
8692 quantum_info,GrayQuantum,png_pixels,&image->exception);
8693 if (mng_info->write_png_colortype-1 == PNG_COLOR_TYPE_PALETTE &&
8694 mng_info->write_png_depth &&
8695 mng_info->write_png_depth != old_bit_depth)
8697 /* Undo pixel scaling */
8698 for (i=0; i < (ssize_t) image->columns; i++)
8699 *(png_pixels+i)=(unsigned char) (*(png_pixels+i)
8700 >> (8-old_bit_depth));
8706 (void) ExportQuantumPixels(image,(const CacheView *) NULL,
8707 quantum_info,RedQuantum,png_pixels,&image->exception);
8710 if (mng_info->write_png_colortype-1 != PNG_COLOR_TYPE_PALETTE)
8711 for (i=0; i < (ssize_t) image->columns; i++)
8712 *(png_pixels+i)=(unsigned char) ((*(png_pixels+i) > 127) ?
8715 if (logging != MagickFalse && y == 0)
8716 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8717 " Writing row of pixels (1)");
8719 png_write_row(ping,png_pixels);
8721 if (image->previous == (Image *) NULL)
8723 status=SetImageProgress(image,LoadImageTag,pass,num_passes);
8724 if (status == MagickFalse)
8730 else /* Not Palette, Bilevel, or Opaque Monochrome */
8732 if ((!mng_info->write_png8 && !mng_info->write_png24 &&
8733 !mng_info->write_png32) &&
8734 (image_matte != MagickFalse ||
8735 (ping_bit_depth >= MAGICKCORE_QUANTUM_DEPTH)) &&
8736 (mng_info->IsPalette) && ImageIsGray(image))
8738 register const PixelPacket
8741 for (pass=0; pass < num_passes; pass++)
8744 for (y=0; y < (ssize_t) image->rows; y++)
8746 p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception);
8748 if (p == (const PixelPacket *) NULL)
8751 if (ping_color_type == PNG_COLOR_TYPE_GRAY)
8753 if (mng_info->IsPalette)
8754 (void) ExportQuantumPixels(image,(const CacheView *) NULL,
8755 quantum_info,GrayQuantum,png_pixels,&image->exception);
8758 (void) ExportQuantumPixels(image,(const CacheView *) NULL,
8759 quantum_info,RedQuantum,png_pixels,&image->exception);
8761 if (logging != MagickFalse && y == 0)
8762 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8763 " Writing GRAY PNG pixels (2)");
8766 else /* PNG_COLOR_TYPE_GRAY_ALPHA */
8768 if (logging != MagickFalse && y == 0)
8769 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8770 " Writing GRAY_ALPHA PNG pixels (2)");
8772 (void) ExportQuantumPixels(image,(const CacheView *) NULL,
8773 quantum_info,GrayAlphaQuantum,png_pixels,&image->exception);
8776 if (logging != MagickFalse && y == 0)
8777 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8778 " Writing row of pixels (2)");
8780 png_write_row(ping,png_pixels);
8783 if (image->previous == (Image *) NULL)
8785 status=SetImageProgress(image,LoadImageTag,pass,num_passes);
8786 if (status == MagickFalse)
8794 register const PixelPacket
8797 for (pass=0; pass < num_passes; pass++)
8799 if ((image_depth > 8) || (mng_info->write_png24 ||
8800 mng_info->write_png32 ||
8801 (!mng_info->write_png8 && !mng_info->IsPalette)))
8803 for (y=0; y < (ssize_t) image->rows; y++)
8805 p=GetVirtualPixels(image,0,y,image->columns,1,
8808 if (p == (const PixelPacket *) NULL)
8811 if (ping_color_type == PNG_COLOR_TYPE_GRAY)
8813 if (image->storage_class == DirectClass)
8814 (void) ExportQuantumPixels(image,(const CacheView *) NULL,
8815 quantum_info,RedQuantum,png_pixels,&image->exception);
8818 (void) ExportQuantumPixels(image,(const CacheView *) NULL,
8819 quantum_info,GrayQuantum,png_pixels,&image->exception);
8822 else if (ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
8824 (void) ExportQuantumPixels(image,(const CacheView *) NULL,
8825 quantum_info,GrayAlphaQuantum,png_pixels,
8828 if (logging != MagickFalse && y == 0)
8829 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8830 " Writing GRAY_ALPHA PNG pixels (3)");
8833 else if (image_matte != MagickFalse)
8834 (void) ExportQuantumPixels(image,(const CacheView *) NULL,
8835 quantum_info,RGBAQuantum,png_pixels,&image->exception);
8838 (void) ExportQuantumPixels(image,(const CacheView *) NULL,
8839 quantum_info,RGBQuantum,png_pixels,&image->exception);
8841 if (logging != MagickFalse && y == 0)
8842 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8843 " Writing row of pixels (3)");
8845 png_write_row(ping,png_pixels);
8850 /* not ((image_depth > 8) || (mng_info->write_png24 ||
8851 mng_info->write_png32 ||
8852 (!mng_info->write_png8 && !mng_info->IsPalette))) */
8854 if ((ping_color_type != PNG_COLOR_TYPE_GRAY) &&
8855 (ping_color_type != PNG_COLOR_TYPE_GRAY_ALPHA))
8857 if (logging != MagickFalse)
8858 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8859 " pass %d, Image Is not GRAY or GRAY_ALPHA",pass);
8861 quantum_info->depth=8;
8865 for (y=0; y < (ssize_t) image->rows; y++)
8867 if (logging != MagickFalse && y == 0)
8868 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8869 " pass %d, Image Is RGB, 16-bit GRAY, or GRAY_ALPHA",pass);
8871 p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception);
8873 if (p == (const PixelPacket *) NULL)
8876 if (ping_color_type == PNG_COLOR_TYPE_GRAY)
8877 (void) ExportQuantumPixels(image,(const CacheView *) NULL,
8878 quantum_info,GrayQuantum,png_pixels,&image->exception);
8880 else if (ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
8882 if (logging != MagickFalse && y == 0)
8883 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8884 " Writing GRAY_ALPHA PNG pixels (4)");
8886 (void) ExportQuantumPixels(image,(const CacheView *) NULL,
8887 quantum_info,GrayAlphaQuantum,png_pixels,
8892 (void) ExportQuantumPixels(image,(const CacheView *) NULL,
8893 quantum_info,IndexQuantum,png_pixels,&image->exception);
8895 if (logging != MagickFalse && y <= 2)
8897 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8898 " Writing row of pixels (4)");
8900 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8901 " png_pixels[0]=%d,png_pixels[1]=%d",
8902 (int)png_pixels[0],(int)png_pixels[1]);
8904 png_write_row(ping,png_pixels);
8908 if (image->previous == (Image *) NULL)
8910 status=SetImageProgress(image,LoadImageTag,pass,num_passes);
8911 if (status == MagickFalse)
8918 if (quantum_info != (QuantumInfo *) NULL)
8919 quantum_info=DestroyQuantumInfo(quantum_info);
8921 if (logging != MagickFalse)
8923 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8924 " Wrote PNG image data");
8926 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8927 " Width: %.20g",(double) ping_width);
8929 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8930 " Height: %.20g",(double) ping_height);
8932 if (mng_info->write_png_depth)
8934 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8935 " Defined PNG:bit-depth: %d",mng_info->write_png_depth);
8938 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8939 " PNG bit-depth written: %d",ping_bit_depth);
8941 if (mng_info->write_png_colortype)
8943 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8944 " Defined PNG:color-type: %d",mng_info->write_png_colortype-1);
8947 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8948 " PNG color-type written: %d",ping_color_type);
8950 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8951 " PNG Interlace method: %d",ping_interlace_method);
8954 Generate text chunks.
8956 if (ping_exclude_tEXt == MagickFalse && ping_exclude_zTXt == MagickFalse)
8958 ResetImagePropertyIterator(image);
8959 property=GetNextImageProperty(image);
8960 while (property != (const char *) NULL)
8965 value=GetImageProperty(image,property);
8966 if (value != (const char *) NULL)
8968 text=(png_textp) png_malloc(ping,(png_uint_32) sizeof(png_text));
8969 text[0].key=(char *) property;
8970 text[0].text=(char *) value;
8971 text[0].text_length=strlen(value);
8973 if (ping_exclude_tEXt != MagickFalse)
8974 text[0].compression=PNG_TEXT_COMPRESSION_zTXt;
8976 else if (ping_exclude_zTXt != MagickFalse)
8977 text[0].compression=PNG_TEXT_COMPRESSION_NONE;
8981 text[0].compression=image_info->compression == NoCompression ||
8982 (image_info->compression == UndefinedCompression &&
8983 text[0].text_length < 128) ? PNG_TEXT_COMPRESSION_NONE :
8984 PNG_TEXT_COMPRESSION_zTXt ;
8987 if (logging != MagickFalse)
8989 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8990 " Setting up text chunk");
8992 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8993 " keyword: %s",text[0].key);
8996 png_set_text(ping,ping_info,text,1);
8997 png_free(ping,text);
8999 property=GetNextImageProperty(image);
9003 /* write any PNG-chunk-e profiles */
9004 (void) png_write_chunk_from_profile(image,"PNG-chunk-e",logging);
9006 if (logging != MagickFalse)
9007 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9008 " Writing PNG end info");
9010 png_write_end(ping,ping_info);
9012 if (mng_info->need_fram && (int) image->dispose == BackgroundDispose)
9014 if (mng_info->page.x || mng_info->page.y ||
9015 (ping_width != mng_info->page.width) ||
9016 (ping_height != mng_info->page.height))
9022 Write FRAM 4 with clipping boundaries followed by FRAM 1.
9024 (void) WriteBlobMSBULong(image,27L); /* data length=27 */
9025 PNGType(chunk,mng_FRAM);
9026 LogPNGChunk(logging,mng_FRAM,27L);
9028 chunk[5]=0; /* frame name separator (no name) */
9029 chunk[6]=1; /* flag for changing delay, for next frame only */
9030 chunk[7]=0; /* flag for changing frame timeout */
9031 chunk[8]=1; /* flag for changing frame clipping for next frame */
9032 chunk[9]=0; /* flag for changing frame sync_id */
9033 PNGLong(chunk+10,(png_uint_32) (0L)); /* temporary 0 delay */
9034 chunk[14]=0; /* clipping boundaries delta type */
9035 PNGLong(chunk+15,(png_uint_32) (mng_info->page.x)); /* left cb */
9037 (png_uint_32) (mng_info->page.x + ping_width));
9038 PNGLong(chunk+23,(png_uint_32) (mng_info->page.y)); /* top cb */
9040 (png_uint_32) (mng_info->page.y + ping_height));
9041 (void) WriteBlob(image,31,chunk);
9042 (void) WriteBlobMSBULong(image,crc32(0,chunk,31));
9043 mng_info->old_framing_mode=4;
9044 mng_info->framing_mode=1;
9048 mng_info->framing_mode=3;
9050 if (mng_info->write_mng && !mng_info->need_fram &&
9051 ((int) image->dispose == 3))
9052 (void) ThrowMagickException(&image->exception,GetMagickModule(),
9053 CoderError,"Cannot convert GIF with disposal method 3 to MNG-LC",
9054 "`%s'",image->filename);
9060 png_destroy_write_struct(&ping,&ping_info);
9062 png_pixels=(unsigned char *) RelinquishMagickMemory(png_pixels);
9064 #if defined(PNG_SETJMP_NOT_THREAD_SAFE)
9065 UnlockSemaphoreInfo(png_semaphore);
9068 if (mng_info->need_blob != MagickFalse)
9069 (void) CloseBlob(image);
9071 image_info=DestroyImageInfo(image_info);
9072 image=DestroyImage(image);
9074 /* Store bit depth actually written */
9075 s[0]=(char) ping_bit_depth;
9078 (void) SetImageProperty(IMimage,"png:bit-depth-written",s);
9080 if (logging != MagickFalse)
9081 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9082 " exit WriteOnePNGImage()");
9085 /* End write one PNG image */
9089 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
9093 % W r i t e P N G I m a g e %
9097 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
9099 % WritePNGImage() writes a Portable Network Graphics (PNG) or
9100 % Multiple-image Network Graphics (MNG) image file.
9102 % MNG support written by Glenn Randers-Pehrson, glennrp@image...
9104 % The format of the WritePNGImage method is:
9106 % MagickBooleanType WritePNGImage(const ImageInfo *image_info,Image *image)
9108 % A description of each parameter follows:
9110 % o image_info: the image info.
9112 % o image: The image.
9114 % Returns MagickTrue on success, MagickFalse on failure.
9116 % Communicating with the PNG encoder:
9118 % While the datastream written is always in PNG format and normally would
9119 % be given the "png" file extension, this method also writes the following
9120 % pseudo-formats which are subsets of PNG:
9122 % o PNG8: An 8-bit indexed PNG datastream is written. If transparency
9123 % is present, the tRNS chunk must only have values 0 and 255
9124 % (i.e., transparency is binary: fully opaque or fully
9125 % transparent). The pixels contain 8-bit indices even if
9126 % they could be represented with 1, 2, or 4 bits. Note: grayscale
9127 % images will be written as indexed PNG files even though the
9128 % PNG grayscale type might be slightly more efficient.
9130 % o PNG24: An 8-bit per sample RGB PNG datastream is written. The tRNS
9131 % chunk can be present to convey binary transparency by naming
9132 % one of the colors as transparent.
9134 % o PNG32: An 8-bit per sample RGBA PNG is written. Partial
9135 % transparency is permitted, i.e., the alpha sample for
9136 % each pixel can have any value from 0 to 255. The alpha
9137 % channel is present even if the image is fully opaque.
9139 % o -define: For more precise control of the PNG output, you can use the
9140 % Image options "png:bit-depth" and "png:color-type". These
9141 % can be set from the commandline with "-define" and also
9142 % from the application programming interfaces. The options
9143 % are case-independent and are converted to lowercase before
9144 % being passed to this encoder.
9146 % png:color-type can be 0, 2, 3, 4, or 6.
9148 % When png:color-type is 0 (Grayscale), png:bit-depth can
9149 % be 1, 2, 4, 8, or 16.
9151 % When png:color-type is 2 (RGB), png:bit-depth can
9154 % When png:color-type is 3 (Indexed), png:bit-depth can
9155 % be 1, 2, 4, or 8. This refers to the number of bits
9156 % used to store the index. The color samples always have
9157 % bit-depth 8 in indexed PNG files.
9159 % When png:color-type is 4 (Gray-Matte) or 6 (RGB-Matte),
9160 % png:bit-depth can be 8 or 16.
9162 % If the image cannot be written without loss in the requested PNG8, PNG24,
9163 % or PNG32 format or with the requested bit-depth and color-type without loss,
9164 % a PNG file will not be written, and the encoder will return MagickFalse.
9165 % Since image encoders should not be responsible for the "heavy lifting",
9166 % the user should make sure that ImageMagick has already reduced the
9167 % image depth and number of colors and limit transparency to binary
9168 % transparency prior to attempting to write the image in a format that
9169 % is subject to depth, color, or transparency limitations.
9171 % TODO: Enforce the previous paragraph.
9173 % Note that another definition, "png:bit-depth-written" exists, but it
9174 % is not intended for external use. It is only used internally by the
9175 % PNG encoder to inform the JNG encoder of the depth of the alpha channel.
9177 % It is possible to request that the PNG encoder write previously-formatted
9178 % ancillary chunks in the output PNG file, using the "-profile" commandline
9179 % option as shown below or by setting the profile via a programming
9182 % -profile PNG-chunk-x:<file>
9184 % where x is a location flag and <file> is a file containing the chunk
9185 % name in the first 4 bytes, then a colon (":"), followed by the chunk data.
9186 % This encoder will compute the chunk length and CRC, so those must not
9187 % be included in the file.
9189 % "x" can be "b" (before PLTE), "m" (middle, i.e., between PLTE and IDAT),
9190 % or "e" (end, i.e., after IDAT). If you want to write multiple chunks
9191 % of the same type, then add a short unique string after the "x" to prevent
9192 % subsequent profiles from overwriting the preceding ones, e.g.,
9194 % -profile PNG-chunk-b01:file01 -profile PNG-chunk-b02:file02
9196 % As of version 6.6.6 the following optimizations are always done:
9198 % o 32-bit depth is reduced to 16.
9199 % o 16-bit depth is reduced to 8 if all pixels contain samples whose
9200 % high byte and low byte are identical.
9201 % o Palette is sorted to remove unused entries and to put a
9202 % transparent color first, if PNG_BUILD_PALETTE is defined.
9203 % o Opaque matte channel is removed when writing an indexed PNG.
9204 % o Grayscale images are reduced to 1, 2, or 4 bit depth if
9205 % this can be done without loss and a larger bit depth N was not
9206 % requested via the "-define PNG:bit-depth=N" option.
9207 % o If matte channel is present but only one transparent color is
9208 % present, RGB+tRNS is written instead of RGBA
9209 % o Opaque matte channel is removed (or added, if color-type 4 or 6
9210 % was requested when converting an opaque image).
9212 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
9214 static MagickBooleanType WritePNGImage(const ImageInfo *image_info,
9236 assert(image_info != (const ImageInfo *) NULL);
9237 assert(image_info->signature == MagickSignature);
9238 assert(image != (Image *) NULL);
9239 assert(image->signature == MagickSignature);
9240 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
9241 logging=LogMagickEvent(CoderEvent,GetMagickModule(),"enter WritePNGImage()");
9243 Allocate a MngInfo structure.
9245 have_mng_structure=MagickFalse;
9246 mng_info=(MngInfo *) AcquireMagickMemory(sizeof(MngInfo));
9248 if (mng_info == (MngInfo *) NULL)
9249 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
9252 Initialize members of the MngInfo structure.
9254 (void) ResetMagickMemory(mng_info,0,sizeof(MngInfo));
9255 mng_info->image=image;
9256 mng_info->equal_backgrounds=MagickTrue;
9257 have_mng_structure=MagickTrue;
9259 /* See if user has requested a specific PNG subformat */
9261 mng_info->write_png8=LocaleCompare(image_info->magick,"PNG8") == 0;
9262 mng_info->write_png24=LocaleCompare(image_info->magick,"PNG24") == 0;
9263 mng_info->write_png32=LocaleCompare(image_info->magick,"PNG32") == 0;
9265 if (mng_info->write_png8)
9267 mng_info->write_png_colortype = /* 3 */ 4;
9268 mng_info->write_png_depth = 8;
9272 if (mng_info->write_png24)
9274 mng_info->write_png_colortype = /* 2 */ 3;
9275 mng_info->write_png_depth = 8;
9278 if (image->matte == MagickTrue)
9279 (void) SetImageType(image,TrueColorMatteType);
9282 (void) SetImageType(image,TrueColorType);
9284 (void) SyncImage(image);
9287 if (mng_info->write_png32)
9289 mng_info->write_png_colortype = /* 6 */ 7;
9290 mng_info->write_png_depth = 8;
9293 if (image->matte == MagickTrue)
9294 (void) SetImageType(image,TrueColorMatteType);
9297 (void) SetImageType(image,TrueColorType);
9299 (void) SyncImage(image);
9302 value=GetImageOption(image_info,"png:bit-depth");
9304 if (value != (char *) NULL)
9306 if (LocaleCompare(value,"1") == 0)
9307 mng_info->write_png_depth = 1;
9309 else if (LocaleCompare(value,"2") == 0)
9310 mng_info->write_png_depth = 2;
9312 else if (LocaleCompare(value,"4") == 0)
9313 mng_info->write_png_depth = 4;
9315 else if (LocaleCompare(value,"8") == 0)
9316 mng_info->write_png_depth = 8;
9318 else if (LocaleCompare(value,"16") == 0)
9319 mng_info->write_png_depth = 16;
9322 (void) ThrowMagickException(&image->exception,
9323 GetMagickModule(),CoderWarning,
9324 "ignoring invalid defined png:bit-depth",
9327 if (logging != MagickFalse)
9328 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9329 " png:bit-depth=%d was defined.\n",mng_info->write_png_depth);
9332 value=GetImageOption(image_info,"png:color-type");
9334 if (value != (char *) NULL)
9336 /* We must store colortype+1 because 0 is a valid colortype */
9337 if (LocaleCompare(value,"0") == 0)
9338 mng_info->write_png_colortype = 1;
9340 else if (LocaleCompare(value,"2") == 0)
9341 mng_info->write_png_colortype = 3;
9343 else if (LocaleCompare(value,"3") == 0)
9344 mng_info->write_png_colortype = 4;
9346 else if (LocaleCompare(value,"4") == 0)
9347 mng_info->write_png_colortype = 5;
9349 else if (LocaleCompare(value,"6") == 0)
9350 mng_info->write_png_colortype = 7;
9353 (void) ThrowMagickException(&image->exception,
9354 GetMagickModule(),CoderWarning,
9355 "ignoring invalid defined png:color-type",
9358 if (logging != MagickFalse)
9359 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9360 " png:color-type=%d was defined.\n",mng_info->write_png_colortype-1);
9363 /* Check for chunks to be excluded:
9365 * The default is to not exclude any chunks except for any
9366 * listed in the "unused_chunks" array, above.
9368 * Chunks can be listed for exclusion via a "PNG:exclude-chunk"
9369 * define (in the image properties or in the image artifacts)
9370 * or via a mng_info member. For convenience, in addition
9371 * to or instead of a comma-separated list of chunks, the
9372 * "exclude-chunk" string can be simply "all" or "none".
9374 * The exclude-chunk define takes priority over the mng_info.
9376 * A "PNG:include-chunk" define takes priority over both the
9377 * mng_info and the "PNG:exclude-chunk" define. Like the
9378 * "exclude-chunk" string, it can define "all" or "none" as
9379 * well as a comma-separated list.
9381 * Finally, all chunks listed in the "unused_chunks" array are
9382 * automatically excluded, regardless of the other instructions
9385 * if you exclude sRGB but not gAMA (recommended), then sRGB chunk
9386 * will not be written and the gAMA chunk will only be written if it
9387 * is not between .45 and .46, or approximately (1.0/2.2).
9389 * If you exclude tRNS and the image has transparency, the colortype
9390 * is forced to be 4 or 6 (GRAY_ALPHA or RGB_ALPHA).
9392 * The -strip option causes StripImage() to set the png:include-chunk
9393 * artifact to "none,gama".
9396 mng_info->ping_exclude_bKGD=MagickFalse;
9397 mng_info->ping_exclude_cHRM=MagickFalse;
9398 mng_info->ping_exclude_EXIF=MagickFalse; /* hex-encoded EXIF in zTXt */
9399 mng_info->ping_exclude_gAMA=MagickFalse;
9400 mng_info->ping_exclude_cHRM=MagickFalse;
9401 mng_info->ping_exclude_iCCP=MagickFalse;
9402 /* mng_info->ping_exclude_iTXt=MagickFalse; */
9403 mng_info->ping_exclude_oFFs=MagickFalse;
9404 mng_info->ping_exclude_pHYs=MagickFalse;
9405 mng_info->ping_exclude_sRGB=MagickFalse;
9406 mng_info->ping_exclude_tEXt=MagickFalse;
9407 mng_info->ping_exclude_tRNS=MagickFalse;
9408 mng_info->ping_exclude_vpAg=MagickFalse;
9409 mng_info->ping_exclude_zCCP=MagickFalse; /* hex-encoded iCCP in zTXt */
9410 mng_info->ping_exclude_zTXt=MagickFalse;
9412 excluding=MagickFalse;
9414 for (source=0; source<1; source++)
9418 value=GetImageArtifact(image,"png:exclude-chunk");
9421 value=GetImageArtifact(image,"png:exclude-chunks");
9425 value=GetImageOption(image_info,"png:exclude-chunk");
9428 value=GetImageOption(image_info,"png:exclude-chunks");
9437 excluding=MagickTrue;
9439 if (logging != MagickFalse)
9442 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9443 " png:exclude-chunk=%s found in image artifacts.\n", value);
9445 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9446 " png:exclude-chunk=%s found in image properties.\n", value);
9451 for (i=0; i<(int) last; i+=5)
9454 if (LocaleNCompare(value+i,"all",3) == 0)
9456 mng_info->ping_exclude_bKGD=MagickTrue;
9457 mng_info->ping_exclude_cHRM=MagickTrue;
9458 mng_info->ping_exclude_EXIF=MagickTrue;
9459 mng_info->ping_exclude_gAMA=MagickTrue;
9460 mng_info->ping_exclude_iCCP=MagickTrue;
9461 /* mng_info->ping_exclude_iTXt=MagickTrue; */
9462 mng_info->ping_exclude_oFFs=MagickTrue;
9463 mng_info->ping_exclude_pHYs=MagickTrue;
9464 mng_info->ping_exclude_sRGB=MagickTrue;
9465 mng_info->ping_exclude_tEXt=MagickTrue;
9466 mng_info->ping_exclude_tRNS=MagickTrue;
9467 mng_info->ping_exclude_vpAg=MagickTrue;
9468 mng_info->ping_exclude_zCCP=MagickTrue;
9469 mng_info->ping_exclude_zTXt=MagickTrue;
9473 if (LocaleNCompare(value+i,"none",4) == 0)
9475 mng_info->ping_exclude_bKGD=MagickFalse;
9476 mng_info->ping_exclude_cHRM=MagickFalse;
9477 mng_info->ping_exclude_EXIF=MagickFalse;
9478 mng_info->ping_exclude_gAMA=MagickFalse;
9479 mng_info->ping_exclude_iCCP=MagickFalse;
9480 /* mng_info->ping_exclude_iTXt=MagickFalse; */
9481 mng_info->ping_exclude_oFFs=MagickFalse;
9482 mng_info->ping_exclude_pHYs=MagickFalse;
9483 mng_info->ping_exclude_sRGB=MagickFalse;
9484 mng_info->ping_exclude_tEXt=MagickFalse;
9485 mng_info->ping_exclude_tRNS=MagickFalse;
9486 mng_info->ping_exclude_vpAg=MagickFalse;
9487 mng_info->ping_exclude_zCCP=MagickFalse;
9488 mng_info->ping_exclude_zTXt=MagickFalse;
9491 if (LocaleNCompare(value+i,"bkgd",4) == 0)
9492 mng_info->ping_exclude_bKGD=MagickTrue;
9494 if (LocaleNCompare(value+i,"chrm",4) == 0)
9495 mng_info->ping_exclude_cHRM=MagickTrue;
9497 if (LocaleNCompare(value+i,"exif",4) == 0)
9498 mng_info->ping_exclude_EXIF=MagickTrue;
9500 if (LocaleNCompare(value+i,"gama",4) == 0)
9501 mng_info->ping_exclude_gAMA=MagickTrue;
9503 if (LocaleNCompare(value+i,"iccp",4) == 0)
9504 mng_info->ping_exclude_iCCP=MagickTrue;
9507 if (LocaleNCompare(value+i,"itxt",4) == 0)
9508 mng_info->ping_exclude_iTXt=MagickTrue;
9511 if (LocaleNCompare(value+i,"gama",4) == 0)
9512 mng_info->ping_exclude_gAMA=MagickTrue;
9514 if (LocaleNCompare(value+i,"offs",4) == 0)
9515 mng_info->ping_exclude_oFFs=MagickTrue;
9517 if (LocaleNCompare(value+i,"phys",4) == 0)
9518 mng_info->ping_exclude_pHYs=MagickTrue;
9520 if (LocaleNCompare(value+i,"srgb",4) == 0)
9521 mng_info->ping_exclude_sRGB=MagickTrue;
9523 if (LocaleNCompare(value+i,"text",4) == 0)
9524 mng_info->ping_exclude_tEXt=MagickTrue;
9526 if (LocaleNCompare(value+i,"trns",4) == 0)
9527 mng_info->ping_exclude_tRNS=MagickTrue;
9529 if (LocaleNCompare(value+i,"vpag",4) == 0)
9530 mng_info->ping_exclude_vpAg=MagickTrue;
9532 if (LocaleNCompare(value+i,"zccp",4) == 0)
9533 mng_info->ping_exclude_zCCP=MagickTrue;
9535 if (LocaleNCompare(value+i,"ztxt",4) == 0)
9536 mng_info->ping_exclude_zTXt=MagickTrue;
9542 for (source=0; source<1; source++)
9546 value=GetImageArtifact(image,"png:include-chunk");
9549 value=GetImageArtifact(image,"png:include-chunks");
9553 value=GetImageOption(image_info,"png:include-chunk");
9556 value=GetImageOption(image_info,"png:include-chunks");
9564 excluding=MagickTrue;
9566 if (logging != MagickFalse)
9569 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9570 " png:include-chunk=%s found in image artifacts.\n", value);
9572 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9573 " png:include-chunk=%s found in image properties.\n", value);
9578 for (i=0; i<(int) last; i+=5)
9580 if (LocaleNCompare(value+i,"all",3) == 0)
9582 mng_info->ping_exclude_bKGD=MagickFalse;
9583 mng_info->ping_exclude_cHRM=MagickFalse;
9584 mng_info->ping_exclude_EXIF=MagickFalse;
9585 mng_info->ping_exclude_gAMA=MagickFalse;
9586 mng_info->ping_exclude_iCCP=MagickFalse;
9587 /* mng_info->ping_exclude_iTXt=MagickFalse; */
9588 mng_info->ping_exclude_oFFs=MagickFalse;
9589 mng_info->ping_exclude_pHYs=MagickFalse;
9590 mng_info->ping_exclude_sRGB=MagickFalse;
9591 mng_info->ping_exclude_tEXt=MagickFalse;
9592 mng_info->ping_exclude_tRNS=MagickFalse;
9593 mng_info->ping_exclude_vpAg=MagickFalse;
9594 mng_info->ping_exclude_zCCP=MagickFalse;
9595 mng_info->ping_exclude_zTXt=MagickFalse;
9599 if (LocaleNCompare(value+i,"none",4) == 0)
9601 mng_info->ping_exclude_bKGD=MagickTrue;
9602 mng_info->ping_exclude_cHRM=MagickTrue;
9603 mng_info->ping_exclude_EXIF=MagickTrue;
9604 mng_info->ping_exclude_gAMA=MagickTrue;
9605 mng_info->ping_exclude_iCCP=MagickTrue;
9606 /* mng_info->ping_exclude_iTXt=MagickTrue; */
9607 mng_info->ping_exclude_oFFs=MagickTrue;
9608 mng_info->ping_exclude_pHYs=MagickTrue;
9609 mng_info->ping_exclude_sRGB=MagickTrue;
9610 mng_info->ping_exclude_tEXt=MagickTrue;
9611 mng_info->ping_exclude_tRNS=MagickTrue;
9612 mng_info->ping_exclude_vpAg=MagickTrue;
9613 mng_info->ping_exclude_zCCP=MagickTrue;
9614 mng_info->ping_exclude_zTXt=MagickTrue;
9617 if (LocaleNCompare(value+i,"bkgd",4) == 0)
9618 mng_info->ping_exclude_bKGD=MagickFalse;
9620 if (LocaleNCompare(value+i,"chrm",4) == 0)
9621 mng_info->ping_exclude_cHRM=MagickFalse;
9623 if (LocaleNCompare(value+i,"exif",4) == 0)
9624 mng_info->ping_exclude_EXIF=MagickFalse;
9626 if (LocaleNCompare(value+i,"gama",4) == 0)
9627 mng_info->ping_exclude_gAMA=MagickFalse;
9629 if (LocaleNCompare(value+i,"iccp",4) == 0)
9630 mng_info->ping_exclude_iCCP=MagickFalse;
9633 if (LocaleNCompare(value+i,"itxt",4) == 0)
9634 mng_info->ping_exclude_iTXt=MagickFalse;
9637 if (LocaleNCompare(value+i,"gama",4) == 0)
9638 mng_info->ping_exclude_gAMA=MagickFalse;
9640 if (LocaleNCompare(value+i,"offs",4) == 0)
9641 mng_info->ping_exclude_oFFs=MagickFalse;
9643 if (LocaleNCompare(value+i,"phys",4) == 0)
9644 mng_info->ping_exclude_pHYs=MagickFalse;
9646 if (LocaleNCompare(value+i,"srgb",4) == 0)
9647 mng_info->ping_exclude_sRGB=MagickFalse;
9649 if (LocaleNCompare(value+i,"text",4) == 0)
9650 mng_info->ping_exclude_tEXt=MagickFalse;
9652 if (LocaleNCompare(value+i,"trns",4) == 0)
9653 mng_info->ping_exclude_tRNS=MagickFalse;
9655 if (LocaleNCompare(value+i,"vpag",4) == 0)
9656 mng_info->ping_exclude_vpAg=MagickFalse;
9658 if (LocaleNCompare(value+i,"zccp",4) == 0)
9659 mng_info->ping_exclude_zCCP=MagickFalse;
9661 if (LocaleNCompare(value+i,"ztxt",4) == 0)
9662 mng_info->ping_exclude_zTXt=MagickFalse;
9668 if (excluding != MagickFalse && logging != MagickFalse)
9670 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9671 " Chunks to be excluded from the output PNG:");
9672 if (mng_info->ping_exclude_bKGD != MagickFalse)
9673 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9675 if (mng_info->ping_exclude_cHRM != MagickFalse)
9676 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9678 if (mng_info->ping_exclude_EXIF != MagickFalse)
9679 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9681 if (mng_info->ping_exclude_gAMA != MagickFalse)
9682 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9684 if (mng_info->ping_exclude_iCCP != MagickFalse)
9685 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9688 if (mng_info->ping_exclude_iTXt != MagickFalse)
9689 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9692 if (mng_info->ping_exclude_oFFs != MagickFalse)
9693 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9695 if (mng_info->ping_exclude_pHYs != MagickFalse)
9696 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9698 if (mng_info->ping_exclude_sRGB != MagickFalse)
9699 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9701 if (mng_info->ping_exclude_tEXt != MagickFalse)
9702 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9704 if (mng_info->ping_exclude_tRNS != MagickFalse)
9705 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9707 if (mng_info->ping_exclude_vpAg != MagickFalse)
9708 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9710 if (mng_info->ping_exclude_zCCP != MagickFalse)
9711 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9713 if (mng_info->ping_exclude_zTXt != MagickFalse)
9714 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9718 mng_info->need_blob = MagickTrue;
9720 status=WriteOnePNGImage(mng_info,image_info,image);
9722 MngInfoFreeStruct(mng_info,&have_mng_structure);
9724 if (logging != MagickFalse)
9725 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"exit WritePNGImage()");
9730 #if defined(JNG_SUPPORTED)
9732 /* Write one JNG image */
9733 static MagickBooleanType WriteOneJNGImage(MngInfo *mng_info,
9734 const ImageInfo *image_info,Image *image)
9755 jng_alpha_compression_method,
9756 jng_alpha_sample_depth,
9763 logging=LogMagickEvent(CoderEvent,GetMagickModule(),
9764 " enter WriteOneJNGImage()");
9766 blob=(unsigned char *) NULL;
9767 jpeg_image=(Image *) NULL;
9768 jpeg_image_info=(ImageInfo *) NULL;
9771 transparent=image_info->type==GrayscaleMatteType ||
9772 image_info->type==TrueColorMatteType;
9774 jng_alpha_sample_depth=0;
9775 jng_quality=image_info->quality == 0UL ? 75UL : image_info->quality;
9776 jng_alpha_compression_method=0;
9778 if (image->matte != MagickFalse)
9780 /* if any pixels are transparent */
9781 transparent=MagickTrue;
9782 if (image_info->compression==JPEGCompression)
9783 jng_alpha_compression_method=8;
9790 /* Create JPEG blob, image, and image_info */
9791 if (logging != MagickFalse)
9792 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9793 " Creating jpeg_image_info for opacity.");
9795 jpeg_image_info=(ImageInfo *) CloneImageInfo(image_info);
9797 if (jpeg_image_info == (ImageInfo *) NULL)
9798 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
9800 if (logging != MagickFalse)
9801 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9802 " Creating jpeg_image.");
9804 jpeg_image=CloneImage(image,0,0,MagickTrue,&image->exception);
9806 if (jpeg_image == (Image *) NULL)
9807 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
9809 (void) CopyMagickString(jpeg_image->magick,"JPEG",MaxTextExtent);
9810 status=SeparateImageChannel(jpeg_image,OpacityChannel);
9811 status=NegateImage(jpeg_image,MagickFalse);
9812 jpeg_image->matte=MagickFalse;
9814 if (jng_quality >= 1000)
9815 jpeg_image_info->quality=jng_quality/1000;
9818 jpeg_image_info->quality=jng_quality;
9820 jpeg_image_info->type=GrayscaleType;
9821 (void) SetImageType(jpeg_image,GrayscaleType);
9822 (void) AcquireUniqueFilename(jpeg_image->filename);
9823 (void) FormatMagickString(jpeg_image_info->filename,MaxTextExtent,
9824 "%s",jpeg_image->filename);
9827 /* To do: check bit depth of PNG alpha channel */
9829 /* Check if image is grayscale. */
9830 if (image_info->type != TrueColorMatteType && image_info->type !=
9831 TrueColorType && ImageIsGray(image))
9836 if (jng_alpha_compression_method==0)
9841 /* Encode opacity as a grayscale PNG blob */
9842 status=OpenBlob(jpeg_image_info,jpeg_image,WriteBinaryBlobMode,
9844 if (logging != MagickFalse)
9845 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9846 " Creating PNG blob.");
9849 (void) CopyMagickString(jpeg_image_info->magick,"PNG",MaxTextExtent);
9850 (void) CopyMagickString(jpeg_image->magick,"PNG",MaxTextExtent);
9851 jpeg_image_info->interlace=NoInterlace;
9853 blob=ImageToBlob(jpeg_image_info,jpeg_image,&length,
9856 /* Retrieve sample depth used */
9857 value=GetImageProperty(jpeg_image,"png:bit-depth-written");
9858 if (value != (char *) NULL)
9859 jng_alpha_sample_depth= (unsigned int) value[0];
9863 /* Encode opacity as a grayscale JPEG blob */
9865 status=OpenBlob(jpeg_image_info,jpeg_image,WriteBinaryBlobMode,
9868 (void) CopyMagickString(jpeg_image_info->magick,"JPEG",MaxTextExtent);
9869 (void) CopyMagickString(jpeg_image->magick,"JPEG",MaxTextExtent);
9870 jpeg_image_info->interlace=NoInterlace;
9871 if (logging != MagickFalse)
9872 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9874 blob=ImageToBlob(jpeg_image_info,jpeg_image,&length,
9876 jng_alpha_sample_depth=8;
9878 if (logging != MagickFalse)
9879 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9880 " Successfully read jpeg_image into a blob, length=%.20g.",
9884 /* Destroy JPEG image and image_info */
9885 jpeg_image=DestroyImage(jpeg_image);
9886 (void) RelinquishUniqueFileResource(jpeg_image_info->filename);
9887 jpeg_image_info=DestroyImageInfo(jpeg_image_info);
9890 /* Write JHDR chunk */
9891 (void) WriteBlobMSBULong(image,16L); /* chunk data length=16 */
9892 PNGType(chunk,mng_JHDR);
9893 LogPNGChunk(logging,mng_JHDR,16L);
9894 PNGLong(chunk+4,(png_uint_32) image->columns);
9895 PNGLong(chunk+8,(png_uint_32) image->rows);
9896 chunk[12]=jng_color_type;
9897 chunk[13]=8; /* sample depth */
9898 chunk[14]=8; /*jng_image_compression_method */
9899 chunk[15]=(unsigned char) (image_info->interlace == NoInterlace ? 0 : 8);
9900 chunk[16]=jng_alpha_sample_depth;
9901 chunk[17]=jng_alpha_compression_method;
9902 chunk[18]=0; /*jng_alpha_filter_method */
9903 chunk[19]=0; /*jng_alpha_interlace_method */
9904 (void) WriteBlob(image,20,chunk);
9905 (void) WriteBlobMSBULong(image,crc32(0,chunk,20));
9906 if (logging != MagickFalse)
9908 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9909 " JNG width:%15lu",(unsigned long) image->columns);
9911 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9912 " JNG height:%14lu",(unsigned long) image->rows);
9914 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9915 " JNG color type:%10d",jng_color_type);
9917 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9918 " JNG sample depth:%8d",8);
9920 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9921 " JNG compression:%9d",8);
9923 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9924 " JNG interlace:%11d",0);
9926 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9927 " JNG alpha depth:%9d",jng_alpha_sample_depth);
9929 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9930 " JNG alpha compression:%3d",jng_alpha_compression_method);
9932 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9933 " JNG alpha filter:%8d",0);
9935 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9936 " JNG alpha interlace:%5d",0);
9939 /* Write any JNG-chunk-b profiles */
9940 (void) png_write_chunk_from_profile(image,"JNG-chunk-b",logging);
9943 Write leading ancillary chunks
9949 Write JNG bKGD chunk
9960 if (jng_color_type == 8 || jng_color_type == 12)
9964 (void) WriteBlobMSBULong(image,(size_t) (num_bytes-4L));
9965 PNGType(chunk,mng_bKGD);
9966 LogPNGChunk(logging,mng_bKGD,(size_t) (num_bytes-4L));
9967 red=ScaleQuantumToChar(image->background_color.red);
9968 green=ScaleQuantumToChar(image->background_color.green);
9969 blue=ScaleQuantumToChar(image->background_color.blue);
9976 (void) WriteBlob(image,(size_t) num_bytes,chunk);
9977 (void) WriteBlobMSBULong(image,crc32(0,chunk,(uInt) num_bytes));
9980 if ((image->colorspace == sRGBColorspace || image->rendering_intent))
9983 Write JNG sRGB chunk
9985 (void) WriteBlobMSBULong(image,1L);
9986 PNGType(chunk,mng_sRGB);
9987 LogPNGChunk(logging,mng_sRGB,1L);
9989 if (image->rendering_intent != UndefinedIntent)
9990 chunk[4]=(unsigned char)
9991 PNG_RenderingIntent_from_Magick_RenderingIntent(
9992 (image->rendering_intent));
9995 chunk[4]=(unsigned char)
9996 PNG_RenderingIntent_from_Magick_RenderingIntent(
9997 (PerceptualIntent));
9999 (void) WriteBlob(image,5,chunk);
10000 (void) WriteBlobMSBULong(image,crc32(0,chunk,5));
10004 if (image->gamma != 0.0)
10007 Write JNG gAMA chunk
10009 (void) WriteBlobMSBULong(image,4L);
10010 PNGType(chunk,mng_gAMA);
10011 LogPNGChunk(logging,mng_gAMA,4L);
10012 PNGLong(chunk+4,(png_uint_32) (100000*image->gamma+0.5));
10013 (void) WriteBlob(image,8,chunk);
10014 (void) WriteBlobMSBULong(image,crc32(0,chunk,8));
10017 if ((mng_info->equal_chrms == MagickFalse) &&
10018 (image->chromaticity.red_primary.x != 0.0))
10024 Write JNG cHRM chunk
10026 (void) WriteBlobMSBULong(image,32L);
10027 PNGType(chunk,mng_cHRM);
10028 LogPNGChunk(logging,mng_cHRM,32L);
10029 primary=image->chromaticity.white_point;
10030 PNGLong(chunk+4,(png_uint_32) (100000*primary.x+0.5));
10031 PNGLong(chunk+8,(png_uint_32) (100000*primary.y+0.5));
10032 primary=image->chromaticity.red_primary;
10033 PNGLong(chunk+12,(png_uint_32) (100000*primary.x+0.5));
10034 PNGLong(chunk+16,(png_uint_32) (100000*primary.y+0.5));
10035 primary=image->chromaticity.green_primary;
10036 PNGLong(chunk+20,(png_uint_32) (100000*primary.x+0.5));
10037 PNGLong(chunk+24,(png_uint_32) (100000*primary.y+0.5));
10038 primary=image->chromaticity.blue_primary;
10039 PNGLong(chunk+28,(png_uint_32) (100000*primary.x+0.5));
10040 PNGLong(chunk+32,(png_uint_32) (100000*primary.y+0.5));
10041 (void) WriteBlob(image,36,chunk);
10042 (void) WriteBlobMSBULong(image,crc32(0,chunk,36));
10046 if (image->x_resolution && image->y_resolution && !mng_info->equal_physs)
10049 Write JNG pHYs chunk
10051 (void) WriteBlobMSBULong(image,9L);
10052 PNGType(chunk,mng_pHYs);
10053 LogPNGChunk(logging,mng_pHYs,9L);
10054 if (image->units == PixelsPerInchResolution)
10056 PNGLong(chunk+4,(png_uint_32)
10057 (image->x_resolution*100.0/2.54+0.5));
10059 PNGLong(chunk+8,(png_uint_32)
10060 (image->y_resolution*100.0/2.54+0.5));
10067 if (image->units == PixelsPerCentimeterResolution)
10069 PNGLong(chunk+4,(png_uint_32)
10070 (image->x_resolution*100.0+0.5));
10072 PNGLong(chunk+8,(png_uint_32)
10073 (image->y_resolution*100.0+0.5));
10080 PNGLong(chunk+4,(png_uint_32) (image->x_resolution+0.5));
10081 PNGLong(chunk+8,(png_uint_32) (image->y_resolution+0.5));
10085 (void) WriteBlob(image,13,chunk);
10086 (void) WriteBlobMSBULong(image,crc32(0,chunk,13));
10089 if (mng_info->write_mng == 0 && (image->page.x || image->page.y))
10092 Write JNG oFFs chunk
10094 (void) WriteBlobMSBULong(image,9L);
10095 PNGType(chunk,mng_oFFs);
10096 LogPNGChunk(logging,mng_oFFs,9L);
10097 PNGsLong(chunk+4,(ssize_t) (image->page.x));
10098 PNGsLong(chunk+8,(ssize_t) (image->page.y));
10100 (void) WriteBlob(image,13,chunk);
10101 (void) WriteBlobMSBULong(image,crc32(0,chunk,13));
10103 if (mng_info->write_mng == 0 && (image->page.width || image->page.height))
10105 (void) WriteBlobMSBULong(image,9L); /* data length=8 */
10106 PNGType(chunk,mng_vpAg);
10107 LogPNGChunk(logging,mng_vpAg,9L);
10108 PNGLong(chunk+4,(png_uint_32) image->page.width);
10109 PNGLong(chunk+8,(png_uint_32) image->page.height);
10110 chunk[12]=0; /* unit = pixels */
10111 (void) WriteBlob(image,13,chunk);
10112 (void) WriteBlobMSBULong(image,crc32(0,chunk,13));
10118 if (jng_alpha_compression_method==0)
10126 /* Write IDAT chunk header */
10127 if (logging != MagickFalse)
10128 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10129 " Write IDAT chunks from blob, length=%.20g.",(double)
10132 /* Copy IDAT chunks */
10135 for (i=8; i<(ssize_t) length; i+=len+12)
10137 len=(*p<<24)|((*(p+1))<<16)|((*(p+2))<<8)|(*(p+3));
10140 if (*(p)==73 && *(p+1)==68 && *(p+2)==65 && *(p+3)==84) /* IDAT */
10142 /* Found an IDAT chunk. */
10143 (void) WriteBlobMSBULong(image,(size_t) len);
10144 LogPNGChunk(logging,mng_IDAT,(size_t) len);
10145 (void) WriteBlob(image,(size_t) len+4,p);
10146 (void) WriteBlobMSBULong(image,
10147 crc32(0,p,(uInt) len+4));
10152 if (logging != MagickFalse)
10153 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10154 " Skipping %c%c%c%c chunk, length=%.20g.",
10155 *(p),*(p+1),*(p+2),*(p+3),(double) len);
10162 /* Write JDAA chunk header */
10163 if (logging != MagickFalse)
10164 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10165 " Write JDAA chunk, length=%.20g.",(double) length);
10166 (void) WriteBlobMSBULong(image,(size_t) length);
10167 PNGType(chunk,mng_JDAA);
10168 LogPNGChunk(logging,mng_JDAA,length);
10169 /* Write JDAT chunk(s) data */
10170 (void) WriteBlob(image,4,chunk);
10171 (void) WriteBlob(image,length,blob);
10172 (void) WriteBlobMSBULong(image,crc32(crc32(0,chunk,4),blob,
10175 blob=(unsigned char *) RelinquishMagickMemory(blob);
10178 /* Encode image as a JPEG blob */
10179 if (logging != MagickFalse)
10180 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10181 " Creating jpeg_image_info.");
10182 jpeg_image_info=(ImageInfo *) CloneImageInfo(image_info);
10183 if (jpeg_image_info == (ImageInfo *) NULL)
10184 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
10186 if (logging != MagickFalse)
10187 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10188 " Creating jpeg_image.");
10190 jpeg_image=CloneImage(image,0,0,MagickTrue,&image->exception);
10191 if (jpeg_image == (Image *) NULL)
10192 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
10193 (void) CopyMagickString(jpeg_image->magick,"JPEG",MaxTextExtent);
10195 (void) AcquireUniqueFilename(jpeg_image->filename);
10196 (void) FormatMagickString(jpeg_image_info->filename,MaxTextExtent,"%s",
10197 jpeg_image->filename);
10199 status=OpenBlob(jpeg_image_info,jpeg_image,WriteBinaryBlobMode,
10200 &image->exception);
10202 if (logging != MagickFalse)
10203 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10204 " Created jpeg_image, %.20g x %.20g.",(double) jpeg_image->columns,
10205 (double) jpeg_image->rows);
10207 if (jng_color_type == 8 || jng_color_type == 12)
10208 jpeg_image_info->type=GrayscaleType;
10210 jpeg_image_info->quality=jng_quality % 1000;
10211 (void) CopyMagickString(jpeg_image_info->magick,"JPEG",MaxTextExtent);
10212 (void) CopyMagickString(jpeg_image->magick,"JPEG",MaxTextExtent);
10214 if (logging != MagickFalse)
10215 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10216 " Creating blob.");
10218 blob=ImageToBlob(jpeg_image_info,jpeg_image,&length,&image->exception);
10220 if (logging != MagickFalse)
10222 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10223 " Successfully read jpeg_image into a blob, length=%.20g.",
10226 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10227 " Write JDAT chunk, length=%.20g.",(double) length);
10230 /* Write JDAT chunk(s) */
10231 (void) WriteBlobMSBULong(image,(size_t) length);
10232 PNGType(chunk,mng_JDAT);
10233 LogPNGChunk(logging,mng_JDAT,length);
10234 (void) WriteBlob(image,4,chunk);
10235 (void) WriteBlob(image,length,blob);
10236 (void) WriteBlobMSBULong(image,crc32(crc32(0,chunk,4),blob,(uInt) length));
10238 jpeg_image=DestroyImage(jpeg_image);
10239 (void) RelinquishUniqueFileResource(jpeg_image_info->filename);
10240 jpeg_image_info=DestroyImageInfo(jpeg_image_info);
10241 blob=(unsigned char *) RelinquishMagickMemory(blob);
10243 /* Write any JNG-chunk-e profiles */
10244 (void) png_write_chunk_from_profile(image,"JNG-chunk-e",logging);
10246 /* Write IEND chunk */
10247 (void) WriteBlobMSBULong(image,0L);
10248 PNGType(chunk,mng_IEND);
10249 LogPNGChunk(logging,mng_IEND,0);
10250 (void) WriteBlob(image,4,chunk);
10251 (void) WriteBlobMSBULong(image,crc32(0,chunk,4));
10253 if (logging != MagickFalse)
10254 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10255 " exit WriteOneJNGImage()");
10262 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
10266 % W r i t e J N G I m a g e %
10270 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
10272 % WriteJNGImage() writes a JPEG Network Graphics (JNG) image file.
10274 % JNG support written by Glenn Randers-Pehrson, glennrp@image...
10276 % The format of the WriteJNGImage method is:
10278 % MagickBooleanType WriteJNGImage(const ImageInfo *image_info,Image *image)
10280 % A description of each parameter follows:
10282 % o image_info: the image info.
10284 % o image: The image.
10286 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
10288 static MagickBooleanType WriteJNGImage(const ImageInfo *image_info,Image *image)
10291 have_mng_structure,
10301 assert(image_info != (const ImageInfo *) NULL);
10302 assert(image_info->signature == MagickSignature);
10303 assert(image != (Image *) NULL);
10304 assert(image->signature == MagickSignature);
10305 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
10306 logging=LogMagickEvent(CoderEvent,GetMagickModule(),"enter WriteJNGImage()");
10307 status=OpenBlob(image_info,image,WriteBinaryBlobMode,&image->exception);
10308 if (status == MagickFalse)
10312 Allocate a MngInfo structure.
10314 have_mng_structure=MagickFalse;
10315 mng_info=(MngInfo *) AcquireMagickMemory(sizeof(MngInfo));
10316 if (mng_info == (MngInfo *) NULL)
10317 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
10319 Initialize members of the MngInfo structure.
10321 (void) ResetMagickMemory(mng_info,0,sizeof(MngInfo));
10322 mng_info->image=image;
10323 have_mng_structure=MagickTrue;
10325 (void) WriteBlob(image,8,(const unsigned char *) "\213JNG\r\n\032\n");
10327 status=WriteOneJNGImage(mng_info,image_info,image);
10328 (void) CloseBlob(image);
10330 (void) CatchImageException(image);
10331 MngInfoFreeStruct(mng_info,&have_mng_structure);
10332 if (logging != MagickFalse)
10333 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"exit WriteJNGImage()");
10340 static MagickBooleanType WriteMNGImage(const ImageInfo *image_info,Image *image)
10349 have_mng_structure,
10352 volatile MagickBooleanType
10364 #if defined(PNG_WRITE_EMPTY_PLTE_SUPPORTED) || \
10365 defined(PNG_MNG_FEATURES_SUPPORTED)
10368 all_images_are_gray,
10378 volatile unsigned int
10389 #if (PNG_LIBPNG_VER < 10200)
10390 if (image_info->verbose)
10391 printf("Your PNG library (libpng-%s) is rather old.\n",
10392 PNG_LIBPNG_VER_STRING);
10398 assert(image_info != (const ImageInfo *) NULL);
10399 assert(image_info->signature == MagickSignature);
10400 assert(image != (Image *) NULL);
10401 assert(image->signature == MagickSignature);
10402 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
10403 logging=LogMagickEvent(CoderEvent,GetMagickModule(),"enter WriteMNGImage()");
10404 status=OpenBlob(image_info,image,WriteBinaryBlobMode,&image->exception);
10405 if (status == MagickFalse)
10409 Allocate a MngInfo structure.
10411 have_mng_structure=MagickFalse;
10412 mng_info=(MngInfo *) AcquireMagickMemory(sizeof(MngInfo));
10413 if (mng_info == (MngInfo *) NULL)
10414 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
10416 Initialize members of the MngInfo structure.
10418 (void) ResetMagickMemory(mng_info,0,sizeof(MngInfo));
10419 mng_info->image=image;
10420 have_mng_structure=MagickTrue;
10421 write_mng=LocaleCompare(image_info->magick,"MNG") == 0;
10424 * See if user has requested a specific PNG subformat to be used
10425 * for all of the PNGs in the MNG being written, e.g.,
10427 * convert *.png png8:animation.mng
10429 * To do: check -define png:bit_depth and png:color_type as well,
10430 * or perhaps use mng:bit_depth and mng:color_type instead for
10434 mng_info->write_png8=LocaleCompare(image_info->magick,"PNG8") == 0;
10435 mng_info->write_png24=LocaleCompare(image_info->magick,"PNG24") == 0;
10436 mng_info->write_png32=LocaleCompare(image_info->magick,"PNG32") == 0;
10438 write_jng=MagickFalse;
10439 if (image_info->compression == JPEGCompression)
10440 write_jng=MagickTrue;
10442 mng_info->adjoin=image_info->adjoin &&
10443 (GetNextImageInList(image) != (Image *) NULL) && write_mng;
10445 if (logging != MagickFalse)
10447 /* Log some info about the input */
10451 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10452 " Checking input image(s)");
10454 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10455 " Image_info depth: %.20g",(double) image_info->depth);
10457 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10458 " Type: %d",image_info->type);
10461 for (p=image; p != (Image *) NULL; p=GetNextImageInList(p))
10463 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10464 " Scene: %.20g",(double) scene++);
10466 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10467 " Image depth: %.20g",(double) p->depth);
10470 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10474 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10477 if (p->storage_class == PseudoClass)
10478 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10479 " Storage class: PseudoClass");
10482 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10483 " Storage class: DirectClass");
10486 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10487 " Number of colors: %.20g",(double) p->colors);
10490 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10491 " Number of colors: unspecified");
10493 if (mng_info->adjoin == MagickFalse)
10498 use_global_plte=MagickFalse;
10499 all_images_are_gray=MagickFalse;
10500 #ifdef PNG_WRITE_EMPTY_PLTE_SUPPORTED
10501 need_local_plte=MagickTrue;
10503 need_defi=MagickFalse;
10504 need_matte=MagickFalse;
10505 mng_info->framing_mode=1;
10506 mng_info->old_framing_mode=1;
10509 if (image_info->page != (char *) NULL)
10512 Determine image bounding box.
10514 SetGeometry(image,&mng_info->page);
10515 (void) ParseMetaGeometry(image_info->page,&mng_info->page.x,
10516 &mng_info->page.y,&mng_info->page.width,&mng_info->page.height);
10528 mng_info->page=image->page;
10529 need_geom=MagickTrue;
10530 if (mng_info->page.width || mng_info->page.height)
10531 need_geom=MagickFalse;
10533 Check all the scenes.
10535 initial_delay=image->delay;
10536 need_iterations=MagickFalse;
10537 mng_info->equal_chrms=image->chromaticity.red_primary.x != 0.0;
10538 mng_info->equal_physs=MagickTrue,
10539 mng_info->equal_gammas=MagickTrue;
10540 mng_info->equal_srgbs=MagickTrue;
10541 mng_info->equal_backgrounds=MagickTrue;
10543 #if defined(PNG_WRITE_EMPTY_PLTE_SUPPORTED) || \
10544 defined(PNG_MNG_FEATURES_SUPPORTED)
10545 all_images_are_gray=MagickTrue;
10546 mng_info->equal_palettes=MagickFalse;
10547 need_local_plte=MagickFalse;
10549 for (next_image=image; next_image != (Image *) NULL; )
10553 if ((next_image->columns+next_image->page.x) > mng_info->page.width)
10554 mng_info->page.width=next_image->columns+next_image->page.x;
10556 if ((next_image->rows+next_image->page.y) > mng_info->page.height)
10557 mng_info->page.height=next_image->rows+next_image->page.y;
10560 if (next_image->page.x || next_image->page.y)
10561 need_defi=MagickTrue;
10563 if (next_image->matte)
10564 need_matte=MagickTrue;
10566 if ((int) next_image->dispose >= BackgroundDispose)
10567 if (next_image->matte || next_image->page.x || next_image->page.y ||
10568 ((next_image->columns < mng_info->page.width) &&
10569 (next_image->rows < mng_info->page.height)))
10570 mng_info->need_fram=MagickTrue;
10572 if (next_image->iterations)
10573 need_iterations=MagickTrue;
10575 final_delay=next_image->delay;
10577 if (final_delay != initial_delay || final_delay > 1UL*
10578 next_image->ticks_per_second)
10579 mng_info->need_fram=1;
10581 #if defined(PNG_WRITE_EMPTY_PLTE_SUPPORTED) || \
10582 defined(PNG_MNG_FEATURES_SUPPORTED)
10584 check for global palette possibility.
10586 if (image->matte != MagickFalse)
10587 need_local_plte=MagickTrue;
10589 if (need_local_plte == 0)
10591 if (ImageIsGray(image) == MagickFalse)
10592 all_images_are_gray=MagickFalse;
10593 mng_info->equal_palettes=PalettesAreEqual(image,next_image);
10594 if (use_global_plte == 0)
10595 use_global_plte=mng_info->equal_palettes;
10596 need_local_plte=!mng_info->equal_palettes;
10599 if (GetNextImageInList(next_image) != (Image *) NULL)
10601 if (next_image->background_color.red !=
10602 next_image->next->background_color.red ||
10603 next_image->background_color.green !=
10604 next_image->next->background_color.green ||
10605 next_image->background_color.blue !=
10606 next_image->next->background_color.blue)
10607 mng_info->equal_backgrounds=MagickFalse;
10609 if (next_image->gamma != next_image->next->gamma)
10610 mng_info->equal_gammas=MagickFalse;
10612 if (next_image->rendering_intent !=
10613 next_image->next->rendering_intent)
10614 mng_info->equal_srgbs=MagickFalse;
10616 if ((next_image->units != next_image->next->units) ||
10617 (next_image->x_resolution != next_image->next->x_resolution) ||
10618 (next_image->y_resolution != next_image->next->y_resolution))
10619 mng_info->equal_physs=MagickFalse;
10621 if (mng_info->equal_chrms)
10623 if (next_image->chromaticity.red_primary.x !=
10624 next_image->next->chromaticity.red_primary.x ||
10625 next_image->chromaticity.red_primary.y !=
10626 next_image->next->chromaticity.red_primary.y ||
10627 next_image->chromaticity.green_primary.x !=
10628 next_image->next->chromaticity.green_primary.x ||
10629 next_image->chromaticity.green_primary.y !=
10630 next_image->next->chromaticity.green_primary.y ||
10631 next_image->chromaticity.blue_primary.x !=
10632 next_image->next->chromaticity.blue_primary.x ||
10633 next_image->chromaticity.blue_primary.y !=
10634 next_image->next->chromaticity.blue_primary.y ||
10635 next_image->chromaticity.white_point.x !=
10636 next_image->next->chromaticity.white_point.x ||
10637 next_image->chromaticity.white_point.y !=
10638 next_image->next->chromaticity.white_point.y)
10639 mng_info->equal_chrms=MagickFalse;
10643 next_image=GetNextImageInList(next_image);
10645 if (image_count < 2)
10647 mng_info->equal_backgrounds=MagickFalse;
10648 mng_info->equal_chrms=MagickFalse;
10649 mng_info->equal_gammas=MagickFalse;
10650 mng_info->equal_srgbs=MagickFalse;
10651 mng_info->equal_physs=MagickFalse;
10652 use_global_plte=MagickFalse;
10653 #ifdef PNG_WRITE_EMPTY_PLTE_SUPPORTED
10654 need_local_plte=MagickTrue;
10656 need_iterations=MagickFalse;
10659 if (mng_info->need_fram == MagickFalse)
10662 Only certain framing rates 100/n are exactly representable without
10663 the FRAM chunk but we'll allow some slop in VLC files
10665 if (final_delay == 0)
10667 if (need_iterations != MagickFalse)
10670 It's probably a GIF with loop; don't run it *too* fast.
10672 if (mng_info->adjoin)
10675 (void) ThrowMagickException(&image->exception,
10676 GetMagickModule(),CoderWarning,
10677 "input has zero delay between all frames; assuming",
10682 mng_info->ticks_per_second=0;
10684 if (final_delay != 0)
10685 mng_info->ticks_per_second=(png_uint_32) (image->ticks_per_second/final_delay);
10686 if (final_delay > 50)
10687 mng_info->ticks_per_second=2;
10689 if (final_delay > 75)
10690 mng_info->ticks_per_second=1;
10692 if (final_delay > 125)
10693 mng_info->need_fram=MagickTrue;
10695 if (need_defi && final_delay > 2 && (final_delay != 4) &&
10696 (final_delay != 5) && (final_delay != 10) && (final_delay != 20) &&
10697 (final_delay != 25) && (final_delay != 50) && (final_delay !=
10698 1UL*image->ticks_per_second))
10699 mng_info->need_fram=MagickTrue; /* make it exact; cannot be VLC */
10702 if (mng_info->need_fram != MagickFalse)
10703 mng_info->ticks_per_second=1UL*image->ticks_per_second;
10705 If pseudocolor, we should also check to see if all the
10706 palettes are identical and write a global PLTE if they are.
10710 Write the MNG version 1.0 signature and MHDR chunk.
10712 (void) WriteBlob(image,8,(const unsigned char *) "\212MNG\r\n\032\n");
10713 (void) WriteBlobMSBULong(image,28L); /* chunk data length=28 */
10714 PNGType(chunk,mng_MHDR);
10715 LogPNGChunk(logging,mng_MHDR,28L);
10716 PNGLong(chunk+4,(png_uint_32) mng_info->page.width);
10717 PNGLong(chunk+8,(png_uint_32) mng_info->page.height);
10718 PNGLong(chunk+12,mng_info->ticks_per_second);
10719 PNGLong(chunk+16,0L); /* layer count=unknown */
10720 PNGLong(chunk+20,0L); /* frame count=unknown */
10721 PNGLong(chunk+24,0L); /* play time=unknown */
10726 if (need_defi || mng_info->need_fram || use_global_plte)
10727 PNGLong(chunk+28,27L); /* simplicity=LC+JNG */
10730 PNGLong(chunk+28,25L); /* simplicity=VLC+JNG */
10735 if (need_defi || mng_info->need_fram || use_global_plte)
10736 PNGLong(chunk+28,19L); /* simplicity=LC+JNG, no transparency */
10739 PNGLong(chunk+28,17L); /* simplicity=VLC+JNG, no transparency */
10747 if (need_defi || mng_info->need_fram || use_global_plte)
10748 PNGLong(chunk+28,11L); /* simplicity=LC */
10751 PNGLong(chunk+28,9L); /* simplicity=VLC */
10756 if (need_defi || mng_info->need_fram || use_global_plte)
10757 PNGLong(chunk+28,3L); /* simplicity=LC, no transparency */
10760 PNGLong(chunk+28,1L); /* simplicity=VLC, no transparency */
10763 (void) WriteBlob(image,32,chunk);
10764 (void) WriteBlobMSBULong(image,crc32(0,chunk,32));
10765 option=GetImageOption(image_info,"mng:need-cacheoff");
10766 if (option != (const char *) NULL)
10772 Write "nEED CACHEOFF" to turn playback caching off for streaming MNG.
10774 PNGType(chunk,mng_nEED);
10775 length=CopyMagickString((char *) chunk+4,"CACHEOFF",20);
10776 (void) WriteBlobMSBULong(image,(size_t) length);
10777 LogPNGChunk(logging,mng_nEED,(size_t) length);
10779 (void) WriteBlob(image,length,chunk);
10780 (void) WriteBlobMSBULong(image,crc32(0,chunk,(uInt) length));
10782 if ((GetPreviousImageInList(image) == (Image *) NULL) &&
10783 (GetNextImageInList(image) != (Image *) NULL) &&
10784 (image->iterations != 1))
10787 Write MNG TERM chunk
10789 (void) WriteBlobMSBULong(image,10L); /* data length=10 */
10790 PNGType(chunk,mng_TERM);
10791 LogPNGChunk(logging,mng_TERM,10L);
10792 chunk[4]=3; /* repeat animation */
10793 chunk[5]=0; /* show last frame when done */
10794 PNGLong(chunk+6,(png_uint_32) (mng_info->ticks_per_second*
10795 final_delay/MagickMax(image->ticks_per_second,1)));
10797 if (image->iterations == 0)
10798 PNGLong(chunk+10,PNG_UINT_31_MAX);
10801 PNGLong(chunk+10,(png_uint_32) image->iterations);
10803 if (logging != MagickFalse)
10805 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10806 " TERM delay: %.20g",(double) (mng_info->ticks_per_second*
10807 final_delay/MagickMax(image->ticks_per_second,1)));
10809 if (image->iterations == 0)
10810 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10811 " TERM iterations: %.20g",(double) PNG_UINT_31_MAX);
10814 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10815 " Image iterations: %.20g",(double) image->iterations);
10817 (void) WriteBlob(image,14,chunk);
10818 (void) WriteBlobMSBULong(image,crc32(0,chunk,14));
10821 To do: check for cHRM+gAMA == sRGB, and write sRGB instead.
10823 if ((image->colorspace == sRGBColorspace || image->rendering_intent) &&
10824 mng_info->equal_srgbs)
10827 Write MNG sRGB chunk
10829 (void) WriteBlobMSBULong(image,1L);
10830 PNGType(chunk,mng_sRGB);
10831 LogPNGChunk(logging,mng_sRGB,1L);
10833 if (image->rendering_intent != UndefinedIntent)
10834 chunk[4]=(unsigned char)
10835 PNG_RenderingIntent_from_Magick_RenderingIntent(
10836 (image->rendering_intent));
10839 chunk[4]=(unsigned char)
10840 PNG_RenderingIntent_from_Magick_RenderingIntent(
10841 (PerceptualIntent));
10843 (void) WriteBlob(image,5,chunk);
10844 (void) WriteBlobMSBULong(image,crc32(0,chunk,5));
10845 mng_info->have_write_global_srgb=MagickTrue;
10850 if (image->gamma && mng_info->equal_gammas)
10853 Write MNG gAMA chunk
10855 (void) WriteBlobMSBULong(image,4L);
10856 PNGType(chunk,mng_gAMA);
10857 LogPNGChunk(logging,mng_gAMA,4L);
10858 PNGLong(chunk+4,(png_uint_32) (100000*image->gamma+0.5));
10859 (void) WriteBlob(image,8,chunk);
10860 (void) WriteBlobMSBULong(image,crc32(0,chunk,8));
10861 mng_info->have_write_global_gama=MagickTrue;
10863 if (mng_info->equal_chrms)
10869 Write MNG cHRM chunk
10871 (void) WriteBlobMSBULong(image,32L);
10872 PNGType(chunk,mng_cHRM);
10873 LogPNGChunk(logging,mng_cHRM,32L);
10874 primary=image->chromaticity.white_point;
10875 PNGLong(chunk+4,(png_uint_32) (100000*primary.x+0.5));
10876 PNGLong(chunk+8,(png_uint_32) (100000*primary.y+0.5));
10877 primary=image->chromaticity.red_primary;
10878 PNGLong(chunk+12,(png_uint_32) (100000*primary.x+0.5));
10879 PNGLong(chunk+16,(png_uint_32) (100000*primary.y+0.5));
10880 primary=image->chromaticity.green_primary;
10881 PNGLong(chunk+20,(png_uint_32) (100000*primary.x+0.5));
10882 PNGLong(chunk+24,(png_uint_32) (100000*primary.y+0.5));
10883 primary=image->chromaticity.blue_primary;
10884 PNGLong(chunk+28,(png_uint_32) (100000*primary.x+0.5));
10885 PNGLong(chunk+32,(png_uint_32) (100000*primary.y+0.5));
10886 (void) WriteBlob(image,36,chunk);
10887 (void) WriteBlobMSBULong(image,crc32(0,chunk,36));
10888 mng_info->have_write_global_chrm=MagickTrue;
10891 if (image->x_resolution && image->y_resolution && mng_info->equal_physs)
10894 Write MNG pHYs chunk
10896 (void) WriteBlobMSBULong(image,9L);
10897 PNGType(chunk,mng_pHYs);
10898 LogPNGChunk(logging,mng_pHYs,9L);
10900 if (image->units == PixelsPerInchResolution)
10902 PNGLong(chunk+4,(png_uint_32)
10903 (image->x_resolution*100.0/2.54+0.5));
10905 PNGLong(chunk+8,(png_uint_32)
10906 (image->y_resolution*100.0/2.54+0.5));
10913 if (image->units == PixelsPerCentimeterResolution)
10915 PNGLong(chunk+4,(png_uint_32)
10916 (image->x_resolution*100.0+0.5));
10918 PNGLong(chunk+8,(png_uint_32)
10919 (image->y_resolution*100.0+0.5));
10926 PNGLong(chunk+4,(png_uint_32) (image->x_resolution+0.5));
10927 PNGLong(chunk+8,(png_uint_32) (image->y_resolution+0.5));
10931 (void) WriteBlob(image,13,chunk);
10932 (void) WriteBlobMSBULong(image,crc32(0,chunk,13));
10935 Write MNG BACK chunk and global bKGD chunk, if the image is transparent
10936 or does not cover the entire frame.
10938 if (write_mng && (image->matte || image->page.x > 0 ||
10939 image->page.y > 0 || (image->page.width &&
10940 (image->page.width+image->page.x < mng_info->page.width))
10941 || (image->page.height && (image->page.height+image->page.y
10942 < mng_info->page.height))))
10944 (void) WriteBlobMSBULong(image,6L);
10945 PNGType(chunk,mng_BACK);
10946 LogPNGChunk(logging,mng_BACK,6L);
10947 red=ScaleQuantumToShort(image->background_color.red);
10948 green=ScaleQuantumToShort(image->background_color.green);
10949 blue=ScaleQuantumToShort(image->background_color.blue);
10950 PNGShort(chunk+4,red);
10951 PNGShort(chunk+6,green);
10952 PNGShort(chunk+8,blue);
10953 (void) WriteBlob(image,10,chunk);
10954 (void) WriteBlobMSBULong(image,crc32(0,chunk,10));
10955 if (mng_info->equal_backgrounds)
10957 (void) WriteBlobMSBULong(image,6L);
10958 PNGType(chunk,mng_bKGD);
10959 LogPNGChunk(logging,mng_bKGD,6L);
10960 (void) WriteBlob(image,10,chunk);
10961 (void) WriteBlobMSBULong(image,crc32(0,chunk,10));
10965 #ifdef PNG_WRITE_EMPTY_PLTE_SUPPORTED
10966 if ((need_local_plte == MagickFalse) &&
10967 (image->storage_class == PseudoClass) &&
10968 (all_images_are_gray == MagickFalse))
10974 Write MNG PLTE chunk
10976 data_length=3*image->colors;
10977 (void) WriteBlobMSBULong(image,data_length);
10978 PNGType(chunk,mng_PLTE);
10979 LogPNGChunk(logging,mng_PLTE,data_length);
10981 for (i=0; i < (ssize_t) image->colors; i++)
10983 chunk[4+i*3]=ScaleQuantumToChar(image->colormap[i].red) & 0xff;
10984 chunk[5+i*3]=ScaleQuantumToChar(image->colormap[i].green) & 0xff;
10985 chunk[6+i*3]=ScaleQuantumToChar(image->colormap[i].blue) & 0xff;
10988 (void) WriteBlob(image,data_length+4,chunk);
10989 (void) WriteBlobMSBULong(image,crc32(0,chunk,(uInt) (data_length+4)));
10990 mng_info->have_write_global_plte=MagickTrue;
10996 #if defined(PNG_WRITE_EMPTY_PLTE_SUPPORTED) || \
10997 defined(PNG_MNG_FEATURES_SUPPORTED)
10998 mng_info->equal_palettes=MagickFalse;
11002 if (mng_info->adjoin)
11004 #if defined(PNG_WRITE_EMPTY_PLTE_SUPPORTED) || \
11005 defined(PNG_MNG_FEATURES_SUPPORTED)
11007 If we aren't using a global palette for the entire MNG, check to
11008 see if we can use one for two or more consecutive images.
11010 if (need_local_plte && use_global_plte && !all_images_are_gray)
11012 if (mng_info->IsPalette)
11015 When equal_palettes is true, this image has the same palette
11016 as the previous PseudoClass image
11018 mng_info->have_write_global_plte=mng_info->equal_palettes;
11019 mng_info->equal_palettes=PalettesAreEqual(image,image->next);
11020 if (mng_info->equal_palettes && !mng_info->have_write_global_plte)
11023 Write MNG PLTE chunk
11028 data_length=3*image->colors;
11029 (void) WriteBlobMSBULong(image,data_length);
11030 PNGType(chunk,mng_PLTE);
11031 LogPNGChunk(logging,mng_PLTE,data_length);
11033 for (i=0; i < (ssize_t) image->colors; i++)
11035 chunk[4+i*3]=ScaleQuantumToChar(image->colormap[i].red);
11036 chunk[5+i*3]=ScaleQuantumToChar(image->colormap[i].green);
11037 chunk[6+i*3]=ScaleQuantumToChar(image->colormap[i].blue);
11040 (void) WriteBlob(image,data_length+4,chunk);
11041 (void) WriteBlobMSBULong(image,crc32(0,chunk,
11042 (uInt) (data_length+4)));
11043 mng_info->have_write_global_plte=MagickTrue;
11047 mng_info->have_write_global_plte=MagickFalse;
11058 previous_x=mng_info->page.x;
11059 previous_y=mng_info->page.y;
11066 mng_info->page=image->page;
11067 if ((mng_info->page.x != previous_x) ||
11068 (mng_info->page.y != previous_y))
11070 (void) WriteBlobMSBULong(image,12L); /* data length=12 */
11071 PNGType(chunk,mng_DEFI);
11072 LogPNGChunk(logging,mng_DEFI,12L);
11073 chunk[4]=0; /* object 0 MSB */
11074 chunk[5]=0; /* object 0 LSB */
11075 chunk[6]=0; /* visible */
11076 chunk[7]=0; /* abstract */
11077 PNGLong(chunk+8,(png_uint_32) mng_info->page.x);
11078 PNGLong(chunk+12,(png_uint_32) mng_info->page.y);
11079 (void) WriteBlob(image,16,chunk);
11080 (void) WriteBlobMSBULong(image,crc32(0,chunk,16));
11085 mng_info->write_mng=write_mng;
11087 if ((int) image->dispose >= 3)
11088 mng_info->framing_mode=3;
11090 if (mng_info->need_fram && mng_info->adjoin &&
11091 ((image->delay != mng_info->delay) ||
11092 (mng_info->framing_mode != mng_info->old_framing_mode)))
11094 if (image->delay == mng_info->delay)
11097 Write a MNG FRAM chunk with the new framing mode.
11099 (void) WriteBlobMSBULong(image,1L); /* data length=1 */
11100 PNGType(chunk,mng_FRAM);
11101 LogPNGChunk(logging,mng_FRAM,1L);
11102 chunk[4]=(unsigned char) mng_info->framing_mode;
11103 (void) WriteBlob(image,5,chunk);
11104 (void) WriteBlobMSBULong(image,crc32(0,chunk,5));
11109 Write a MNG FRAM chunk with the delay.
11111 (void) WriteBlobMSBULong(image,10L); /* data length=10 */
11112 PNGType(chunk,mng_FRAM);
11113 LogPNGChunk(logging,mng_FRAM,10L);
11114 chunk[4]=(unsigned char) mng_info->framing_mode;
11115 chunk[5]=0; /* frame name separator (no name) */
11116 chunk[6]=2; /* flag for changing default delay */
11117 chunk[7]=0; /* flag for changing frame timeout */
11118 chunk[8]=0; /* flag for changing frame clipping */
11119 chunk[9]=0; /* flag for changing frame sync_id */
11120 PNGLong(chunk+10,(png_uint_32)
11121 ((mng_info->ticks_per_second*
11122 image->delay)/MagickMax(image->ticks_per_second,1)));
11123 (void) WriteBlob(image,14,chunk);
11124 (void) WriteBlobMSBULong(image,crc32(0,chunk,14));
11125 mng_info->delay=(png_uint_32) image->delay;
11127 mng_info->old_framing_mode=mng_info->framing_mode;
11130 #if defined(JNG_SUPPORTED)
11131 if (image_info->compression == JPEGCompression)
11136 if (logging != MagickFalse)
11137 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11138 " Writing JNG object.");
11139 /* To do: specify the desired alpha compression method. */
11140 write_info=CloneImageInfo(image_info);
11141 write_info->compression=UndefinedCompression;
11142 status=WriteOneJNGImage(mng_info,write_info,image);
11143 write_info=DestroyImageInfo(write_info);
11148 if (logging != MagickFalse)
11149 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11150 " Writing PNG object.");
11152 mng_info->need_blob = MagickFalse;
11154 /* We don't want any ancillary chunks written */
11155 mng_info->ping_exclude_bKGD=MagickTrue;
11156 mng_info->ping_exclude_cHRM=MagickTrue;
11157 mng_info->ping_exclude_EXIF=MagickTrue;
11158 mng_info->ping_exclude_gAMA=MagickTrue;
11159 mng_info->ping_exclude_cHRM=MagickTrue;
11160 mng_info->ping_exclude_iCCP=MagickTrue;
11161 /* mng_info->ping_exclude_iTXt=MagickTrue; */
11162 mng_info->ping_exclude_oFFs=MagickTrue;
11163 mng_info->ping_exclude_pHYs=MagickTrue;
11164 mng_info->ping_exclude_sRGB=MagickTrue;
11165 mng_info->ping_exclude_tEXt=MagickTrue;
11166 mng_info->ping_exclude_tRNS=MagickTrue;
11167 mng_info->ping_exclude_vpAg=MagickTrue;
11168 mng_info->ping_exclude_zCCP=MagickTrue;
11169 mng_info->ping_exclude_zTXt=MagickTrue;
11171 status=WriteOnePNGImage(mng_info,image_info,image);
11174 if (status == MagickFalse)
11176 MngInfoFreeStruct(mng_info,&have_mng_structure);
11177 (void) CloseBlob(image);
11178 return(MagickFalse);
11180 (void) CatchImageException(image);
11181 if (GetNextImageInList(image) == (Image *) NULL)
11183 image=SyncNextImageInList(image);
11184 status=SetImageProgress(image,SaveImagesTag,scene++,
11185 GetImageListLength(image));
11187 if (status == MagickFalse)
11190 } while (mng_info->adjoin);
11194 while (GetPreviousImageInList(image) != (Image *) NULL)
11195 image=GetPreviousImageInList(image);
11197 Write the MEND chunk.
11199 (void) WriteBlobMSBULong(image,0x00000000L);
11200 PNGType(chunk,mng_MEND);
11201 LogPNGChunk(logging,mng_MEND,0L);
11202 (void) WriteBlob(image,4,chunk);
11203 (void) WriteBlobMSBULong(image,crc32(0,chunk,4));
11206 Relinquish resources.
11208 (void) CloseBlob(image);
11209 MngInfoFreeStruct(mng_info,&have_mng_structure);
11211 if (logging != MagickFalse)
11212 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"exit WriteMNGImage()");
11214 return(MagickTrue);
11216 #else /* PNG_LIBPNG_VER > 10011 */
11218 static MagickBooleanType WritePNGImage(const ImageInfo *image_info,Image *image)
11221 printf("Your PNG library is too old: You have libpng-%s\n",
11222 PNG_LIBPNG_VER_STRING);
11224 ThrowBinaryException(CoderError,"PNG library is too old",
11225 image_info->filename);
11228 static MagickBooleanType WriteMNGImage(const ImageInfo *image_info,Image *image)
11230 return(WritePNGImage(image_info,image));
11232 #endif /* PNG_LIBPNG_VER > 10011 */