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 BUILD_PNG_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 *ping_semaphore = (SemaphoreInfo *) NULL;
141 This temporary until I set up malloc'ed object attributes array.
142 Recompile with MNG_MAX_OBJECTS=65536L to avoid this limit but
145 #define MNG_MAX_OBJECTS 256
148 If this not defined, spec is interpreted strictly. If it is
149 defined, an attempt will be made to recover from some errors,
151 o global PLTE too short
156 Don't try to define PNG_MNG_FEATURES_SUPPORTED here. Make sure
157 it's defined in libpng/pngconf.h, version 1.0.9 or later. It won't work
158 with earlier versions of libpng. From libpng-1.0.3a to libpng-1.0.8,
159 PNG_READ|WRITE_EMPTY_PLTE were used but those have been deprecated in
160 libpng in favor of PNG_MNG_FEATURES_SUPPORTED, so we set them here.
161 PNG_MNG_FEATURES_SUPPORTED is disabled by default in libpng-1.0.9 and
162 will be enabled by default in libpng-1.2.0.
164 #ifdef PNG_MNG_FEATURES_SUPPORTED
165 # ifndef PNG_READ_EMPTY_PLTE_SUPPORTED
166 # define PNG_READ_EMPTY_PLTE_SUPPORTED
168 # ifndef PNG_WRITE_EMPTY_PLTE_SUPPORTED
169 # define PNG_WRITE_EMPTY_PLTE_SUPPORTED
174 Maximum valid size_t in PNG/MNG chunks is (2^31)-1
175 This macro is only defined in libpng-1.0.3 and later.
176 Previously it was PNG_MAX_UINT but that was deprecated in libpng-1.2.6
178 #ifndef PNG_UINT_31_MAX
179 #define PNG_UINT_31_MAX (png_uint_32) 0x7fffffffL
183 Constant strings for known chunk types. If you need to add a chunk,
184 add a string holding the name here. To make the code more
185 portable, we use ASCII numbers like this, not characters.
188 static png_byte FARDATA mng_MHDR[5]={ 77, 72, 68, 82, (png_byte) '\0'};
189 static png_byte FARDATA mng_BACK[5]={ 66, 65, 67, 75, (png_byte) '\0'};
190 static png_byte FARDATA mng_BASI[5]={ 66, 65, 83, 73, (png_byte) '\0'};
191 static png_byte FARDATA mng_CLIP[5]={ 67, 76, 73, 80, (png_byte) '\0'};
192 static png_byte FARDATA mng_CLON[5]={ 67, 76, 79, 78, (png_byte) '\0'};
193 static png_byte FARDATA mng_DEFI[5]={ 68, 69, 70, 73, (png_byte) '\0'};
194 static png_byte FARDATA mng_DHDR[5]={ 68, 72, 68, 82, (png_byte) '\0'};
195 static png_byte FARDATA mng_DISC[5]={ 68, 73, 83, 67, (png_byte) '\0'};
196 static png_byte FARDATA mng_ENDL[5]={ 69, 78, 68, 76, (png_byte) '\0'};
197 static png_byte FARDATA mng_FRAM[5]={ 70, 82, 65, 77, (png_byte) '\0'};
198 static png_byte FARDATA mng_IEND[5]={ 73, 69, 78, 68, (png_byte) '\0'};
199 static png_byte FARDATA mng_IHDR[5]={ 73, 72, 68, 82, (png_byte) '\0'};
200 static png_byte FARDATA mng_JHDR[5]={ 74, 72, 68, 82, (png_byte) '\0'};
201 static png_byte FARDATA mng_LOOP[5]={ 76, 79, 79, 80, (png_byte) '\0'};
202 static png_byte FARDATA mng_MAGN[5]={ 77, 65, 71, 78, (png_byte) '\0'};
203 static png_byte FARDATA mng_MEND[5]={ 77, 69, 78, 68, (png_byte) '\0'};
204 static png_byte FARDATA mng_MOVE[5]={ 77, 79, 86, 69, (png_byte) '\0'};
205 static png_byte FARDATA mng_PAST[5]={ 80, 65, 83, 84, (png_byte) '\0'};
206 static png_byte FARDATA mng_PLTE[5]={ 80, 76, 84, 69, (png_byte) '\0'};
207 static png_byte FARDATA mng_SAVE[5]={ 83, 65, 86, 69, (png_byte) '\0'};
208 static png_byte FARDATA mng_SEEK[5]={ 83, 69, 69, 75, (png_byte) '\0'};
209 static png_byte FARDATA mng_SHOW[5]={ 83, 72, 79, 87, (png_byte) '\0'};
210 static png_byte FARDATA mng_TERM[5]={ 84, 69, 82, 77, (png_byte) '\0'};
211 static png_byte FARDATA mng_bKGD[5]={ 98, 75, 71, 68, (png_byte) '\0'};
212 static png_byte FARDATA mng_cHRM[5]={ 99, 72, 82, 77, (png_byte) '\0'};
213 static png_byte FARDATA mng_gAMA[5]={103, 65, 77, 65, (png_byte) '\0'};
214 static png_byte FARDATA mng_iCCP[5]={105, 67, 67, 80, (png_byte) '\0'};
215 static png_byte FARDATA mng_nEED[5]={110, 69, 69, 68, (png_byte) '\0'};
216 static png_byte FARDATA mng_pHYg[5]={112, 72, 89, 103, (png_byte) '\0'};
217 static png_byte FARDATA mng_vpAg[5]={118, 112, 65, 103, (png_byte) '\0'};
218 static png_byte FARDATA mng_pHYs[5]={112, 72, 89, 115, (png_byte) '\0'};
219 static png_byte FARDATA mng_sBIT[5]={115, 66, 73, 84, (png_byte) '\0'};
220 static png_byte FARDATA mng_sRGB[5]={115, 82, 71, 66, (png_byte) '\0'};
221 static png_byte FARDATA mng_tRNS[5]={116, 82, 78, 83, (png_byte) '\0'};
223 #if defined(JNG_SUPPORTED)
224 static png_byte FARDATA mng_IDAT[5]={ 73, 68, 65, 84, (png_byte) '\0'};
225 static png_byte FARDATA mng_JDAT[5]={ 74, 68, 65, 84, (png_byte) '\0'};
226 static png_byte FARDATA mng_JDAA[5]={ 74, 68, 65, 65, (png_byte) '\0'};
227 static png_byte FARDATA mng_JdAA[5]={ 74, 100, 65, 65, (png_byte) '\0'};
228 static png_byte FARDATA mng_JSEP[5]={ 74, 83, 69, 80, (png_byte) '\0'};
229 static png_byte FARDATA mng_oFFs[5]={111, 70, 70, 115, (png_byte) '\0'};
233 Other known chunks that are not yet supported by ImageMagick:
234 static png_byte FARDATA mng_hIST[5]={104, 73, 83, 84, (png_byte) '\0'};
235 static png_byte FARDATA mng_iCCP[5]={105, 67, 67, 80, (png_byte) '\0'};
236 static png_byte FARDATA mng_iTXt[5]={105, 84, 88, 116, (png_byte) '\0'};
237 static png_byte FARDATA mng_sPLT[5]={115, 80, 76, 84, (png_byte) '\0'};
238 static png_byte FARDATA mng_sTER[5]={115, 84, 69, 82, (png_byte) '\0'};
239 static png_byte FARDATA mng_tEXt[5]={116, 69, 88, 116, (png_byte) '\0'};
240 static png_byte FARDATA mng_tIME[5]={116, 73, 77, 69, (png_byte) '\0'};
241 static png_byte FARDATA mng_zTXt[5]={122, 84, 88, 116, (png_byte) '\0'};
244 typedef struct _MngBox
253 typedef struct _MngPair
260 #ifdef MNG_OBJECT_BUFFERS
261 typedef struct _MngBuffer
293 typedef struct _MngInfo
296 #ifdef MNG_OBJECT_BUFFERS
298 *ob[MNG_MAX_OBJECTS];
309 #ifndef PNG_READ_EMPTY_PLTE_SUPPORTED
310 bytes_in_read_buffer,
316 #if defined(PNG_WRITE_EMPTY_PLTE_SUPPORTED) || \
317 defined(PNG_MNG_FEATURES_SUPPORTED)
329 have_saved_bkgd_index,
330 have_write_global_chrm,
331 have_write_global_gama,
332 have_write_global_plte,
333 have_write_global_srgb,
347 x_off[MNG_MAX_OBJECTS],
348 y_off[MNG_MAX_OBJECTS];
354 object_clip[MNG_MAX_OBJECTS];
357 /* These flags could be combined into one byte */
358 exists[MNG_MAX_OBJECTS],
359 frozen[MNG_MAX_OBJECTS],
361 invisible[MNG_MAX_OBJECTS],
362 viewable[MNG_MAX_OBJECTS];
374 #ifndef PNG_READ_EMPTY_PLTE_SUPPORTED
392 global_x_pixels_per_unit,
393 global_y_pixels_per_unit,
403 global_phys_unit_type,
422 #ifdef MNG_BASI_SUPPORTED
430 basi_compression_method,
432 basi_interlace_method,
455 /* Added at version 6.6.6-7 */
462 /* ping_exclude_iTXt, */
469 ping_exclude_zCCP, /* hex-encoded iCCP */
476 Forward declarations.
478 static MagickBooleanType
479 WritePNGImage(const ImageInfo *,Image *);
481 static MagickBooleanType
482 WriteMNGImage(const ImageInfo *,Image *);
484 #if defined(JNG_SUPPORTED)
485 static MagickBooleanType
486 WriteJNGImage(const ImageInfo *,Image *);
489 #if PNG_LIBPNG_VER > 10011
491 #if (MAGICKCORE_QUANTUM_DEPTH >= 16)
492 static MagickBooleanType
493 LosslessReduceDepthOK(Image *image)
496 ok_to_reduce=MagickFalse;
498 /* Reduce bit depth if it can be reduced losslessly from 16 to 8.
499 * Note that the method GetImageDepth doesn't check background
500 * and doesn't handle PseudoClass specially. Also it uses
501 * multiplication and division by 257 instead of shifting, so
505 if (image->depth == 16)
512 (((((size_t) image->background_color.red >> 8) & 0xff)
513 == ((size_t) image->background_color.red & 0xff)) &&
514 ((((size_t) image->background_color.green >> 8) & 0xff)
515 == ((size_t) image->background_color.green & 0xff)) &&
516 ((((size_t) image->background_color.blue >> 8) & 0xff)
517 == ((size_t) image->background_color.blue & 0xff))) ? MagickTrue :
520 if (ok_to_reduce != MagickFalse && image->storage_class == PseudoClass)
524 for (indx=0; indx < (ssize_t) image->colors; indx++)
526 ok_to_reduce=(((((size_t) image->colormap[indx].red >>
528 == ((size_t) image->colormap[indx].red & 0xff)) &&
529 ((((size_t) image->colormap[indx].green >> 8) & 0xff)
530 == ((size_t) image->colormap[indx].green & 0xff)) &&
531 ((((size_t) image->colormap[indx].blue >> 8) & 0xff)
532 == ((size_t) image->colormap[indx].blue & 0xff)) &&
533 (image->matte == MagickFalse ||
534 (((size_t) image->colormap[indx].opacity >> 8) & 0xff)
535 == ((size_t) image->colormap[indx].opacity & 0xff))) ?
536 MagickTrue : MagickFalse;
537 if (ok_to_reduce == MagickFalse)
542 if ((ok_to_reduce != MagickFalse) &&
543 (image->storage_class != PseudoClass))
551 for (y=0; y < (ssize_t) image->rows; y++)
553 p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception);
555 if (p == (const PixelPacket *) NULL)
557 ok_to_reduce = MagickFalse;
561 for (x=(ssize_t) image->columns-1; x >= 0; x--)
564 (((size_t) p->red >> 8) & 0xff) ==
565 ((size_t) p->red & 0xff)) &&
566 ((((size_t) p->green >> 8) & 0xff) ==
567 ((size_t) p->green & 0xff)) &&
568 ((((size_t) p->blue >> 8) & 0xff) ==
569 ((size_t) p->blue & 0xff)) &&
570 (((image->matte == MagickFalse ||
571 (((size_t) p->opacity >> 8) & 0xff) ==
572 ((size_t) p->opacity & 0xff))))) ? MagickTrue : MagickFalse;
574 if (ok_to_reduce == MagickFalse)
584 if (ok_to_reduce != MagickFalse)
586 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
587 " OK to reduce PNG bit depth to 8 without loss of info");
591 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
592 " Not OK to reduce PNG bit depth to 8 without loss of info");
598 #endif /* MAGICKCORE_QUANTUM_DEPTH >= 16 */
601 Magick_RenderingIntent_to_PNG_RenderingIntent(const RenderingIntent intent)
605 case PerceptualIntent:
611 case SaturationIntent:
622 static RenderingIntent
623 Magick_RenderingIntent_from_PNG_RenderingIntent(const int ping_intent)
628 return PerceptualIntent;
631 return RelativeIntent;
634 return SaturationIntent;
637 return AbsoluteIntent;
640 return UndefinedIntent;
644 static inline ssize_t MagickMax(const ssize_t x,const ssize_t y)
652 static inline ssize_t MagickMin(const ssize_t x,const ssize_t y)
662 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
666 % I m a g e I s G r a y %
670 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
672 % Like IsGrayImage except does not change DirectClass to PseudoClass %
674 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
676 static MagickBooleanType ImageIsGray(Image *image)
678 register const PixelPacket
686 assert(image != (Image *) NULL);
687 assert(image->signature == MagickSignature);
688 if (image->debug != MagickFalse)
689 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
691 if (image->storage_class == PseudoClass)
693 for (i=0; i < (ssize_t) image->colors; i++)
694 if (IsGray(image->colormap+i) == MagickFalse)
698 for (y=0; y < (ssize_t) image->rows; y++)
700 p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception);
701 if (p == (const PixelPacket *) NULL)
703 for (x=(ssize_t) image->columns-1; x >= 0; x--)
705 if (IsGray(p) == MagickFalse)
714 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
718 % I m a g e I s M o n o c h r o m e %
722 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
724 % Like IsMonochromeImage except does not change DirectClass to PseudoClass %
725 % and is more accurate. %
727 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
729 static MagickBooleanType ImageIsMonochrome(Image *image)
731 register const PixelPacket
739 assert(image != (Image *) NULL);
740 assert(image->signature == MagickSignature);
741 if (image->debug != MagickFalse)
742 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
743 if (image->storage_class == PseudoClass)
745 for (i=0; i < (ssize_t) image->colors; i++)
747 if ((IsGray(image->colormap+i) == MagickFalse) ||
748 ((image->colormap[i].red != 0) &&
749 (image->colormap[i].red != (Quantum) QuantumRange)))
754 for (y=0; y < (ssize_t) image->rows; y++)
756 p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception);
757 if (p == (const PixelPacket *) NULL)
759 for (x=(ssize_t) image->columns-1; x >= 0; x--)
761 if ((p->red != 0) && (p->red != (Quantum) QuantumRange))
764 if (IsGray(p) == MagickFalse)
767 if ((p->opacity != OpaqueOpacity) &&
768 (p->opacity != (Quantum) TransparentOpacity))
776 #endif /* PNG_LIBPNG_VER > 10011 */
777 #endif /* MAGICKCORE_PNG_DELEGATE */
780 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
788 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
790 % IsMNG() returns MagickTrue if the image format type, identified by the
791 % magick string, is MNG.
793 % The format of the IsMNG method is:
795 % MagickBooleanType IsMNG(const unsigned char *magick,const size_t length)
797 % A description of each parameter follows:
799 % o magick: compare image format pattern against these bytes.
801 % o length: Specifies the length of the magick string.
805 static MagickBooleanType IsMNG(const unsigned char *magick,const size_t length)
810 if (memcmp(magick,"\212MNG\r\n\032\n",8) == 0)
817 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
825 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
827 % IsJNG() returns MagickTrue if the image format type, identified by the
828 % magick string, is JNG.
830 % The format of the IsJNG method is:
832 % MagickBooleanType IsJNG(const unsigned char *magick,const size_t length)
834 % A description of each parameter follows:
836 % o magick: compare image format pattern against these bytes.
838 % o length: Specifies the length of the magick string.
842 static MagickBooleanType IsJNG(const unsigned char *magick,const size_t length)
847 if (memcmp(magick,"\213JNG\r\n\032\n",8) == 0)
854 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
862 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
864 % IsPNG() returns MagickTrue if the image format type, identified by the
865 % magick string, is PNG.
867 % The format of the IsPNG method is:
869 % MagickBooleanType IsPNG(const unsigned char *magick,const size_t length)
871 % A description of each parameter follows:
873 % o magick: compare image format pattern against these bytes.
875 % o length: Specifies the length of the magick string.
878 static MagickBooleanType IsPNG(const unsigned char *magick,const size_t length)
883 if (memcmp(magick,"\211PNG\r\n\032\n",8) == 0)
889 #if defined(MAGICKCORE_PNG_DELEGATE)
890 #if defined(__cplusplus) || defined(c_plusplus)
894 #if (PNG_LIBPNG_VER > 10011)
895 static size_t WriteBlobMSBULong(Image *image,const size_t value)
900 assert(image != (Image *) NULL);
901 assert(image->signature == MagickSignature);
902 buffer[0]=(unsigned char) (value >> 24);
903 buffer[1]=(unsigned char) (value >> 16);
904 buffer[2]=(unsigned char) (value >> 8);
905 buffer[3]=(unsigned char) value;
906 return((size_t) WriteBlob(image,4,buffer));
909 static void PNGLong(png_bytep p,png_uint_32 value)
911 *p++=(png_byte) ((value >> 24) & 0xff);
912 *p++=(png_byte) ((value >> 16) & 0xff);
913 *p++=(png_byte) ((value >> 8) & 0xff);
914 *p++=(png_byte) (value & 0xff);
917 #if defined(JNG_SUPPORTED)
918 static void PNGsLong(png_bytep p,png_int_32 value)
920 *p++=(png_byte) ((value >> 24) & 0xff);
921 *p++=(png_byte) ((value >> 16) & 0xff);
922 *p++=(png_byte) ((value >> 8) & 0xff);
923 *p++=(png_byte) (value & 0xff);
927 static void PNGShort(png_bytep p,png_uint_16 value)
929 *p++=(png_byte) ((value >> 8) & 0xff);
930 *p++=(png_byte) (value & 0xff);
933 static void PNGType(png_bytep p,png_bytep type)
935 (void) CopyMagickMemory(p,type,4*sizeof(png_byte));
938 static void LogPNGChunk(MagickBooleanType logging, png_bytep type,
941 if (logging != MagickFalse)
942 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
943 " Writing %c%c%c%c chunk, length: %.20g",
944 type[0],type[1],type[2],type[3],(double) length);
946 #endif /* PNG_LIBPNG_VER > 10011 */
948 #if defined(__cplusplus) || defined(c_plusplus)
952 #if PNG_LIBPNG_VER > 10011
954 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
958 % R e a d P N G I m a g e %
962 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
964 % ReadPNGImage() reads a Portable Network Graphics (PNG) or
965 % Multiple-image Network Graphics (MNG) image file and returns it. It
966 % allocates the memory necessary for the new Image structure and returns a
967 % pointer to the new image or set of images.
969 % MNG support written by Glenn Randers-Pehrson, glennrp@image...
971 % The format of the ReadPNGImage method is:
973 % Image *ReadPNGImage(const ImageInfo *image_info,ExceptionInfo *exception)
975 % A description of each parameter follows:
977 % o image_info: the image info.
979 % o exception: return any errors or warnings in this structure.
981 % To do, more or less in chronological order (as of version 5.5.2,
982 % November 26, 2002 -- glennrp -- see also "To do" under WriteMNGImage):
984 % Get 16-bit cheap transparency working.
986 % (At this point, PNG decoding is supposed to be in full MNG-LC compliance)
988 % Preserve all unknown and not-yet-handled known chunks found in input
989 % PNG file and copy them into output PNG files according to the PNG
992 % (At this point, PNG encoding should be in full MNG compliance)
994 % Provide options for choice of background to use when the MNG BACK
995 % chunk is not present or is not mandatory (i.e., leave transparent,
996 % user specified, MNG BACK, PNG bKGD)
998 % Implement LOOP/ENDL [done, but could do discretionary loops more
999 % efficiently by linking in the duplicate frames.].
1001 % Decode and act on the MHDR simplicity profile (offer option to reject
1002 % files or attempt to process them anyway when the profile isn't LC or VLC).
1004 % Upgrade to full MNG without Delta-PNG.
1006 % o BACK [done a while ago except for background image ID]
1007 % o MOVE [done 15 May 1999]
1008 % o CLIP [done 15 May 1999]
1009 % o DISC [done 19 May 1999]
1010 % o SAVE [partially done 19 May 1999 (marks objects frozen)]
1011 % o SEEK [partially done 19 May 1999 (discard function only)]
1015 % o MNG-level tEXt/iTXt/zTXt
1020 % o iTXt (wait for libpng implementation).
1022 % Use the scene signature to discover when an identical scene is
1023 % being reused, and just point to the original image->exception instead
1024 % of storing another set of pixels. This not specific to MNG
1025 % but could be applied generally.
1027 % Upgrade to full MNG with Delta-PNG.
1029 % JNG tEXt/iTXt/zTXt
1031 % We will not attempt to read files containing the CgBI chunk.
1032 % They are really Xcode files meant for display on the iPhone.
1033 % These are not valid PNG files and it is impossible to recover
1034 % the orginal PNG from files that have been converted to Xcode-PNG,
1035 % since irretrievable loss of color data has occurred due to the
1036 % use of premultiplied alpha.
1039 #if defined(__cplusplus) || defined(c_plusplus)
1044 This the function that does the actual reading of data. It is
1045 the same as the one supplied in libpng, except that it receives the
1046 datastream from the ReadBlob() function instead of standard input.
1048 static void png_get_data(png_structp png_ptr,png_bytep data,png_size_t length)
1053 image=(Image *) png_get_io_ptr(png_ptr);
1059 check=(png_size_t) ReadBlob(image,(size_t) length,data);
1060 if (check != length)
1065 (void) FormatMagickString(msg,MaxTextExtent,
1066 "Expected %.20g bytes; found %.20g bytes",(double) length,
1068 png_warning(png_ptr,msg);
1069 png_error(png_ptr,"Read Exception");
1074 #if !defined(PNG_READ_EMPTY_PLTE_SUPPORTED) && \
1075 !defined(PNG_MNG_FEATURES_SUPPORTED)
1076 /* We use mng_get_data() instead of png_get_data() if we have a libpng
1077 * older than libpng-1.0.3a, which was the first to allow the empty
1078 * PLTE, or a newer libpng in which PNG_MNG_FEATURES_SUPPORTED was
1079 * ifdef'ed out. Earlier versions would crash if the bKGD chunk was
1080 * encountered after an empty PLTE, so we have to look ahead for bKGD
1081 * chunks and remove them from the datastream that is passed to libpng,
1082 * and store their contents for later use.
1084 static void mng_get_data(png_structp png_ptr,png_bytep data,png_size_t length)
1099 mng_info=(MngInfo *) png_get_io_ptr(png_ptr);
1100 image=(Image *) mng_info->image;
1101 while (mng_info->bytes_in_read_buffer && length)
1103 data[i]=mng_info->read_buffer[i];
1104 mng_info->bytes_in_read_buffer--;
1110 check=(png_size_t) ReadBlob(image,(size_t) length,(char *) data);
1112 if (check != length)
1113 png_error(png_ptr,"Read Exception");
1117 if ((data[0] == 0) && (data[1] == 0) && (data[2] == 0) &&
1120 check=(png_size_t) ReadBlob(image,(size_t) length,
1121 (char *) mng_info->read_buffer);
1122 mng_info->read_buffer[4]=0;
1123 mng_info->bytes_in_read_buffer=4;
1124 if (memcmp(mng_info->read_buffer,mng_PLTE,4) == 0)
1125 mng_info->found_empty_plte=MagickTrue;
1126 if (memcmp(mng_info->read_buffer,mng_IEND,4) == 0)
1128 mng_info->found_empty_plte=MagickFalse;
1129 mng_info->have_saved_bkgd_index=MagickFalse;
1133 if ((data[0] == 0) && (data[1] == 0) && (data[2] == 0) &&
1136 check=(png_size_t) ReadBlob(image,(size_t) length,
1137 (char *) mng_info->read_buffer);
1138 mng_info->read_buffer[4]=0;
1139 mng_info->bytes_in_read_buffer=4;
1140 if (memcmp(mng_info->read_buffer,mng_bKGD,4) == 0)
1141 if (mng_info->found_empty_plte)
1144 Skip the bKGD data byte and CRC.
1147 ReadBlob(image,5,(char *) mng_info->read_buffer);
1148 check=(png_size_t) ReadBlob(image,(size_t) length,
1149 (char *) mng_info->read_buffer);
1150 mng_info->saved_bkgd_index=mng_info->read_buffer[0];
1151 mng_info->have_saved_bkgd_index=MagickTrue;
1152 mng_info->bytes_in_read_buffer=0;
1160 static void png_put_data(png_structp png_ptr,png_bytep data,png_size_t length)
1165 image=(Image *) png_get_io_ptr(png_ptr);
1171 check=(png_size_t) WriteBlob(image,(size_t) length,data);
1173 if (check != length)
1174 png_error(png_ptr,"WriteBlob Failed");
1178 static void png_flush_data(png_structp png_ptr)
1183 #ifdef PNG_WRITE_EMPTY_PLTE_SUPPORTED
1184 static int PalettesAreEqual(Image *a,Image *b)
1189 if ((a == (Image *) NULL) || (b == (Image *) NULL))
1190 return((int) MagickFalse);
1192 if (a->storage_class != PseudoClass || b->storage_class != PseudoClass)
1193 return((int) MagickFalse);
1195 if (a->colors != b->colors)
1196 return((int) MagickFalse);
1198 for (i=0; i < (ssize_t) a->colors; i++)
1200 if ((a->colormap[i].red != b->colormap[i].red) ||
1201 (a->colormap[i].green != b->colormap[i].green) ||
1202 (a->colormap[i].blue != b->colormap[i].blue))
1203 return((int) MagickFalse);
1206 return((int) MagickTrue);
1210 static void MngInfoDiscardObject(MngInfo *mng_info,int i)
1212 if (i && (i < MNG_MAX_OBJECTS) && (mng_info != (MngInfo *) NULL) &&
1213 mng_info->exists[i] && !mng_info->frozen[i])
1215 #ifdef MNG_OBJECT_BUFFERS
1216 if (mng_info->ob[i] != (MngBuffer *) NULL)
1218 if (mng_info->ob[i]->reference_count > 0)
1219 mng_info->ob[i]->reference_count--;
1221 if (mng_info->ob[i]->reference_count == 0)
1223 if (mng_info->ob[i]->image != (Image *) NULL)
1224 mng_info->ob[i]->image=DestroyImage(mng_info->ob[i]->image);
1226 mng_info->ob[i]=DestroyString(mng_info->ob[i]);
1229 mng_info->ob[i]=(MngBuffer *) NULL;
1231 mng_info->exists[i]=MagickFalse;
1232 mng_info->invisible[i]=MagickFalse;
1233 mng_info->viewable[i]=MagickFalse;
1234 mng_info->frozen[i]=MagickFalse;
1235 mng_info->x_off[i]=0;
1236 mng_info->y_off[i]=0;
1237 mng_info->object_clip[i].left=0;
1238 mng_info->object_clip[i].right=(ssize_t) PNG_UINT_31_MAX;
1239 mng_info->object_clip[i].top=0;
1240 mng_info->object_clip[i].bottom=(ssize_t) PNG_UINT_31_MAX;
1244 static void MngInfoFreeStruct(MngInfo *mng_info,
1245 MagickBooleanType *have_mng_structure)
1247 if (*have_mng_structure != MagickFalse && (mng_info != (MngInfo *) NULL))
1252 for (i=1; i < MNG_MAX_OBJECTS; i++)
1253 MngInfoDiscardObject(mng_info,i);
1255 if (mng_info->global_plte != (png_colorp) NULL)
1256 mng_info->global_plte=(png_colorp)
1257 RelinquishMagickMemory(mng_info->global_plte);
1259 mng_info=(MngInfo *) RelinquishMagickMemory(mng_info);
1260 *have_mng_structure=MagickFalse;
1264 static MngBox mng_minimum_box(MngBox box1,MngBox box2)
1270 if (box.left < box2.left)
1273 if (box.top < box2.top)
1276 if (box.right > box2.right)
1277 box.right=box2.right;
1279 if (box.bottom > box2.bottom)
1280 box.bottom=box2.bottom;
1285 static MngBox mng_read_box(MngBox previous_box,char delta_type,unsigned char *p)
1291 Read clipping boundaries from DEFI, CLIP, FRAM, or PAST chunk.
1293 box.left=(ssize_t) ((p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]);
1294 box.right=(ssize_t) ((p[4] << 24) | (p[5] << 16) | (p[6] << 8) | p[7]);
1295 box.top=(ssize_t) ((p[8] << 24) | (p[9] << 16) | (p[10] << 8) | p[11]);
1296 box.bottom=(ssize_t) ((p[12] << 24) | (p[13] << 16) | (p[14] << 8) | p[15]);
1297 if (delta_type != 0)
1299 box.left+=previous_box.left;
1300 box.right+=previous_box.right;
1301 box.top+=previous_box.top;
1302 box.bottom+=previous_box.bottom;
1308 static MngPair mng_read_pair(MngPair previous_pair,int delta_type,
1314 Read two ssize_ts from CLON, MOVE or PAST chunk
1316 pair.a=(long) ((p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]);
1317 pair.b=(long) ((p[4] << 24) | (p[5] << 16) | (p[6] << 8) | p[7]);
1319 if (delta_type != 0)
1321 pair.a+=previous_pair.a;
1322 pair.b+=previous_pair.b;
1328 static long mng_get_long(unsigned char *p)
1330 return((long) ((p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]));
1333 static void MagickPNGErrorHandler(png_struct *ping,png_const_charp message)
1338 image=(Image *) png_get_error_ptr(ping);
1340 if (image->debug != MagickFalse)
1341 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1342 " libpng-%s error: %s", PNG_LIBPNG_VER_STRING,message);
1344 (void) ThrowMagickException(&image->exception,GetMagickModule(),CoderError,
1345 message,"`%s'",image->filename);
1347 #if (PNG_LIBPNG_VER < 10500)
1348 longjmp(ping->jmpbuf,1);
1350 png_longjmp(ping,1);
1354 static void MagickPNGWarningHandler(png_struct *ping,png_const_charp message)
1359 if (LocaleCompare(message, "Missing PLTE before tRNS") == 0)
1360 png_error(ping, message);
1362 image=(Image *) png_get_error_ptr(ping);
1363 if (image->debug != MagickFalse)
1364 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1365 " libpng-%s warning: %s", PNG_LIBPNG_VER_STRING,message);
1367 (void) ThrowMagickException(&image->exception,GetMagickModule(),CoderWarning,
1368 message,"`%s'",image->filename);
1371 #ifdef PNG_USER_MEM_SUPPORTED
1372 static png_voidp Magick_png_malloc(png_structp png_ptr,png_uint_32 size)
1374 #if (PNG_LIBPNG_VER < 10011)
1379 ret=((png_voidp) AcquireMagickMemory((size_t) size));
1382 png_error("Insufficient memory.");
1387 return((png_voidp) AcquireMagickMemory((size_t) size));
1392 Free a pointer. It is removed from the list at the same time.
1394 static png_free_ptr Magick_png_free(png_structp png_ptr,png_voidp ptr)
1397 ptr=RelinquishMagickMemory(ptr);
1398 return((png_free_ptr) NULL);
1402 #if defined(__cplusplus) || defined(c_plusplus)
1407 Magick_png_read_raw_profile(Image *image, const ImageInfo *image_info,
1408 png_textp text,int ii)
1413 register unsigned char
1427 unhex[103]={0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,
1428 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,
1429 0,0,0,0,0,0,0,0,0,1, 2,3,4,5,6,7,8,9,0,0,
1430 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,
1431 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,10,11,12,
1435 /* look for newline */
1439 /* look for length */
1440 while (*sp == '\0' || *sp == ' ' || *sp == '\n')
1443 length=(png_uint_32) StringToLong(sp);
1445 while (*sp != ' ' && *sp != '\n')
1448 /* allocate space */
1451 (void) ThrowMagickException(&image->exception,GetMagickModule(),
1452 CoderWarning,"UnableToCopyProfile","`%s'","invalid profile length");
1453 return(MagickFalse);
1456 profile=AcquireStringInfo(length);
1458 if (profile == (StringInfo *) NULL)
1460 (void) ThrowMagickException(&image->exception,GetMagickModule(),
1461 ResourceLimitError,"MemoryAllocationFailed","`%s'",
1462 "unable to copy profile");
1463 return(MagickFalse);
1466 /* copy profile, skipping white space and column 1 "=" signs */
1467 dp=GetStringInfoDatum(profile);
1470 for (i=0; i < (ssize_t) nibbles; i++)
1472 while (*sp < '0' || (*sp > '9' && *sp < 'a') || *sp > 'f')
1476 (void) ThrowMagickException(&image->exception,GetMagickModule(),
1477 CoderWarning,"UnableToCopyProfile","`%s'","ran out of data");
1478 profile=DestroyStringInfo(profile);
1479 return(MagickFalse);
1485 *dp=(unsigned char) (16*unhex[(int) *sp++]);
1488 (*dp++)+=unhex[(int) *sp++];
1491 We have already read "Raw profile type.
1493 (void) SetImageProfile(image,&text[ii].key[17],profile);
1494 profile=DestroyStringInfo(profile);
1496 if (image_info->verbose)
1497 (void) printf(" Found a generic profile, type %s\n",&text[ii].key[17]);
1502 #if defined(PNG_UNKNOWN_CHUNKS_SUPPORTED)
1503 static int read_vpag_chunk_callback(png_struct *ping, png_unknown_chunkp chunk)
1509 /* The unknown chunk structure contains the chunk data:
1514 Note that libpng has already taken care of the CRC handling.
1518 if (chunk->name[0] != 118 || chunk->name[1] != 112 ||
1519 chunk->name[2] != 65 ||chunk-> name[3] != 103)
1520 return(0); /* Did not recognize */
1522 /* recognized vpAg */
1524 if (chunk->size != 9)
1525 return(-1); /* Error return */
1527 if (chunk->data[8] != 0)
1528 return(0); /* ImageMagick requires pixel units */
1530 image=(Image *) png_get_user_chunk_ptr(ping);
1532 image->page.width=(size_t) ((chunk->data[0] << 24) |
1533 (chunk->data[1] << 16) | (chunk->data[2] << 8) | chunk->data[3]);
1535 image->page.height=(size_t) ((chunk->data[4] << 24) |
1536 (chunk->data[5] << 16) | (chunk->data[6] << 8) | chunk->data[7]);
1538 /* Return one of the following: */
1539 /* return(-n); chunk had an error */
1540 /* return(0); did not recognize */
1541 /* return(n); success */
1549 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1553 % R e a d O n e P N G I m a g e %
1557 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1559 % ReadOnePNGImage() reads a Portable Network Graphics (PNG) image file
1560 % (minus the 8-byte signature) and returns it. It allocates the memory
1561 % necessary for the new Image structure and returns a pointer to the new
1564 % The format of the ReadOnePNGImage method is:
1566 % Image *ReadOnePNGImage(MngInfo *mng_info, const ImageInfo *image_info,
1567 % ExceptionInfo *exception)
1569 % A description of each parameter follows:
1571 % o mng_info: Specifies a pointer to a MngInfo structure.
1573 % o image_info: the image info.
1575 % o exception: return any errors or warnings in this structure.
1578 static Image *ReadOnePNGImage(MngInfo *mng_info,
1579 const ImageInfo *image_info, ExceptionInfo *exception)
1581 /* Read one PNG image */
1592 ping_interlace_method,
1593 ping_compression_method,
1635 register unsigned char
1638 register IndexPacket
1645 register PixelPacket
1652 #if defined(PNG_UNKNOWN_CHUNKS_SUPPORTED)
1653 png_byte unused_chunks[]=
1655 104, 73, 83, 84, (png_byte) '\0', /* hIST */
1656 105, 84, 88, 116, (png_byte) '\0', /* iTXt */
1657 112, 67, 65, 76, (png_byte) '\0', /* pCAL */
1658 115, 67, 65, 76, (png_byte) '\0', /* sCAL */
1659 115, 80, 76, 84, (png_byte) '\0', /* sPLT */
1660 116, 73, 77, 69, (png_byte) '\0', /* tIME */
1664 logging=LogMagickEvent(CoderEvent,GetMagickModule(),
1665 " enter ReadOnePNGImage()");
1667 #if defined(PNG_SETJMP_NOT_THREAD_SAFE)
1668 LockSemaphoreInfo(ping_semaphore);
1671 #if (PNG_LIBPNG_VER < 10200)
1672 if (image_info->verbose)
1673 printf("Your PNG library (libpng-%s) is rather old.\n",
1674 PNG_LIBPNG_VER_STRING);
1677 #if (PNG_LIBPNG_VER >= 10400)
1678 # ifndef PNG_TRANSFORM_GRAY_TO_RGB /* Added at libpng-1.4.0beta67 */
1679 if (image_info->verbose)
1681 printf("Your PNG library (libpng-%s) is an old beta version.\n",
1682 PNG_LIBPNG_VER_STRING);
1683 printf("Please update it.\n");
1689 quantum_info = (QuantumInfo *) NULL;
1690 image=mng_info->image;
1692 if (logging != MagickFalse)
1693 (void)LogMagickEvent(CoderEvent,GetMagickModule(),
1694 " image->matte=%d",(int) image->matte);
1696 /* Set to an out-of-range color unless tRNS chunk is present */
1697 transparent_color.red=65537;
1698 transparent_color.green=65537;
1699 transparent_color.blue=65537;
1700 transparent_color.opacity=65537;
1703 Allocate the PNG structures
1705 #ifdef PNG_USER_MEM_SUPPORTED
1706 ping=png_create_read_struct_2(PNG_LIBPNG_VER_STRING, image,
1707 MagickPNGErrorHandler,MagickPNGWarningHandler, NULL,
1708 (png_malloc_ptr) Magick_png_malloc,(png_free_ptr) Magick_png_free);
1710 ping=png_create_read_struct(PNG_LIBPNG_VER_STRING,image,
1711 MagickPNGErrorHandler,MagickPNGWarningHandler);
1713 if (ping == (png_struct *) NULL)
1714 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1716 ping_info=png_create_info_struct(ping);
1718 if (ping_info == (png_info *) NULL)
1720 png_destroy_read_struct(&ping,(png_info **) NULL,(png_info **) NULL);
1721 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1724 end_info=png_create_info_struct(ping);
1726 if (end_info == (png_info *) NULL)
1728 png_destroy_read_struct(&ping,&ping_info,(png_info **) NULL);
1729 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1732 ping_pixels=(unsigned char *) NULL;
1734 if (setjmp(png_jmpbuf(ping)))
1737 PNG image is corrupt.
1739 png_destroy_read_struct(&ping,&ping_info,&end_info);
1740 #if defined(PNG_SETJMP_NOT_THREAD_SAFE)
1741 UnlockSemaphoreInfo(ping_semaphore);
1743 if (logging != MagickFalse)
1744 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1745 " exit ReadOnePNGImage() with error.");
1747 if (image != (Image *) NULL)
1749 InheritException(exception,&image->exception);
1753 return(GetFirstImageInList(image));
1756 Prepare PNG for reading.
1759 mng_info->image_found++;
1760 png_set_sig_bytes(ping,8);
1762 if (LocaleCompare(image_info->magick,"MNG") == 0)
1764 #if defined(PNG_MNG_FEATURES_SUPPORTED)
1765 (void) png_permit_mng_features(ping,PNG_ALL_MNG_FEATURES);
1766 png_set_read_fn(ping,image,png_get_data);
1768 #if defined(PNG_READ_EMPTY_PLTE_SUPPORTED)
1769 png_permit_empty_plte(ping,MagickTrue);
1770 png_set_read_fn(ping,image,png_get_data);
1772 mng_info->image=image;
1773 mng_info->bytes_in_read_buffer=0;
1774 mng_info->found_empty_plte=MagickFalse;
1775 mng_info->have_saved_bkgd_index=MagickFalse;
1776 png_set_read_fn(ping,mng_info,mng_get_data);
1782 png_set_read_fn(ping,image,png_get_data);
1784 #if defined(PNG_UNKNOWN_CHUNKS_SUPPORTED)
1785 /* Ignore unused chunks and all unknown chunks except for vpAg */
1786 png_set_keep_unknown_chunks(ping, 1, NULL, 0);
1787 png_set_keep_unknown_chunks(ping, 2, mng_vpAg, 1);
1788 png_set_keep_unknown_chunks(ping, 1, unused_chunks,
1789 (int)sizeof(unused_chunks)/5);
1790 /* Callback for other unknown chunks */
1791 png_set_read_user_chunk_fn(ping, image, read_vpag_chunk_callback);
1794 #if (PNG_LIBPNG_VER < 10400)
1795 # if defined(PNG_USE_PNGGCCRD) && defined(PNG_ASSEMBLER_CODE_SUPPORTED) && \
1796 (PNG_LIBPNG_VER >= 10200) && (PNG_LIBPNG_VER < 10220) && defined(__i386__)
1797 /* Disable thread-unsafe features of pnggccrd */
1798 if (png_access_version_number() >= 10200)
1800 png_uint_32 mmx_disable_mask=0;
1801 png_uint_32 asm_flags;
1803 mmx_disable_mask |= ( PNG_ASM_FLAG_MMX_READ_COMBINE_ROW \
1804 | PNG_ASM_FLAG_MMX_READ_FILTER_SUB \
1805 | PNG_ASM_FLAG_MMX_READ_FILTER_AVG \
1806 | PNG_ASM_FLAG_MMX_READ_FILTER_PAETH );
1807 asm_flags=png_get_asm_flags(ping);
1808 png_set_asm_flags(ping, asm_flags & ~mmx_disable_mask);
1813 png_read_info(ping,ping_info);
1815 png_get_IHDR(ping,ping_info,&ping_width,&ping_height,
1816 &ping_bit_depth,&ping_color_type,
1817 &ping_interlace_method,&ping_compression_method,
1818 &ping_filter_method);
1820 (void) png_get_tRNS(ping, ping_info, &ping_trans_alpha, &ping_num_trans,
1823 (void) png_get_bKGD(ping, ping_info, &ping_background);
1825 if (ping_bit_depth < 8)
1827 if (((int) ping_color_type == PNG_COLOR_TYPE_PALETTE))
1829 png_set_packing(ping);
1834 image->depth=ping_bit_depth;
1835 image->depth=GetImageQuantumDepth(image,MagickFalse);
1836 image->interlace=ping_interlace_method != 0 ? PNGInterlace : NoInterlace;
1837 if (logging != MagickFalse)
1839 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1840 " PNG width: %.20g, height: %.20g",
1841 (double) ping_width, (double) ping_height);
1843 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1844 " PNG color_type: %d, bit_depth: %d",
1845 ping_color_type, ping_bit_depth);
1847 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1848 " PNG compression_method: %d",
1849 ping_compression_method);
1851 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1852 " PNG interlace_method: %d, filter_method: %d",
1853 ping_interlace_method,ping_filter_method);
1856 #ifdef PNG_READ_iCCP_SUPPORTED
1857 if (png_get_valid(ping,ping_info,PNG_INFO_iCCP))
1862 #if (PNG_LIBPNG_VER < 10500)
1876 (void) png_get_iCCP(ping,ping_info,&name,(int *) &compression,&info,
1879 if (profile_length != 0)
1884 if (logging != MagickFalse)
1885 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1886 " Reading PNG iCCP chunk.");
1887 profile=AcquireStringInfo(profile_length);
1888 SetStringInfoDatum(profile,(const unsigned char *) info);
1889 (void) SetImageProfile(image,"icc",profile);
1890 profile=DestroyStringInfo(profile);
1894 #if defined(PNG_READ_sRGB_SUPPORTED)
1899 if (mng_info->have_global_srgb)
1900 image->rendering_intent=Magick_RenderingIntent_from_PNG_RenderingIntent
1901 (mng_info->global_srgb_intent);
1903 if (png_get_sRGB(ping,ping_info,&intent))
1905 image->rendering_intent=Magick_RenderingIntent_from_PNG_RenderingIntent
1908 if (logging != MagickFalse)
1909 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1910 " Reading PNG sRGB chunk: rendering_intent: %d",intent);
1918 if (!png_get_gAMA(ping,ping_info,&file_gamma))
1919 if (mng_info->have_global_gama)
1920 png_set_gAMA(ping,ping_info,mng_info->global_gamma);
1922 if (png_get_gAMA(ping,ping_info,&file_gamma))
1924 image->gamma=(float) file_gamma;
1925 if (logging != MagickFalse)
1926 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1927 " Reading PNG gAMA chunk: gamma: %f",file_gamma);
1930 if (!png_get_valid(ping,ping_info,PNG_INFO_cHRM))
1932 if (mng_info->have_global_chrm != MagickFalse)
1934 (void) png_set_cHRM(ping,ping_info,
1935 mng_info->global_chrm.white_point.x,
1936 mng_info->global_chrm.white_point.y,
1937 mng_info->global_chrm.red_primary.x,
1938 mng_info->global_chrm.red_primary.y,
1939 mng_info->global_chrm.green_primary.x,
1940 mng_info->global_chrm.green_primary.y,
1941 mng_info->global_chrm.blue_primary.x,
1942 mng_info->global_chrm.blue_primary.y);
1946 if (png_get_valid(ping,ping_info,PNG_INFO_cHRM))
1948 (void) png_get_cHRM(ping,ping_info,
1949 &image->chromaticity.white_point.x,
1950 &image->chromaticity.white_point.y,
1951 &image->chromaticity.red_primary.x,
1952 &image->chromaticity.red_primary.y,
1953 &image->chromaticity.green_primary.x,
1954 &image->chromaticity.green_primary.y,
1955 &image->chromaticity.blue_primary.x,
1956 &image->chromaticity.blue_primary.y);
1958 if (logging != MagickFalse)
1959 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1960 " Reading PNG cHRM chunk.");
1963 if (image->rendering_intent != UndefinedIntent)
1965 png_set_sRGB(ping,ping_info,
1966 Magick_RenderingIntent_to_PNG_RenderingIntent
1967 (image->rendering_intent));
1968 png_set_gAMA(ping,ping_info,0.45455f);
1969 png_set_cHRM(ping,ping_info,
1970 0.6400f, 0.3300f, 0.3000f, 0.6000f,
1971 0.1500f, 0.0600f, 0.3127f, 0.3290f);
1973 #if defined(PNG_oFFs_SUPPORTED)
1974 if (png_get_valid(ping,ping_info,PNG_INFO_oFFs))
1976 image->page.x=png_get_x_offset_pixels(ping, ping_info);
1977 image->page.y=png_get_y_offset_pixels(ping, ping_info);
1979 if (logging != MagickFalse)
1980 if (image->page.x || image->page.y)
1981 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1982 " Reading PNG oFFs chunk: x: %.20g, y: %.20g.",(double)
1983 image->page.x,(double) image->page.y);
1986 #if defined(PNG_pHYs_SUPPORTED)
1987 if (!png_get_valid(ping,ping_info,PNG_INFO_pHYs))
1989 if (mng_info->have_global_phys)
1991 png_set_pHYs(ping,ping_info,
1992 mng_info->global_x_pixels_per_unit,
1993 mng_info->global_y_pixels_per_unit,
1994 mng_info->global_phys_unit_type);
1998 if (png_get_valid(ping,ping_info,PNG_INFO_pHYs))
2008 Set image resolution.
2010 (void) png_get_pHYs(ping,ping_info,&x_resolution,&y_resolution,
2012 image->x_resolution=(double) x_resolution;
2013 image->y_resolution=(double) y_resolution;
2015 if (unit_type == PNG_RESOLUTION_METER)
2017 image->units=PixelsPerCentimeterResolution;
2018 image->x_resolution=(double) x_resolution/100.0;
2019 image->y_resolution=(double) y_resolution/100.0;
2022 if (logging != MagickFalse)
2023 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2024 " Reading PNG pHYs chunk: xres: %.20g, yres: %.20g, units: %d.",
2025 (double) x_resolution,(double) y_resolution,unit_type);
2028 if (png_get_valid(ping,ping_info,PNG_INFO_PLTE))
2036 (void) png_get_PLTE(ping,ping_info,&palette,&number_colors);
2038 if ((number_colors == 0) &&
2039 ((int) ping_color_type == PNG_COLOR_TYPE_PALETTE))
2041 if (mng_info->global_plte_length)
2043 png_set_PLTE(ping,ping_info,mng_info->global_plte,
2044 (int) mng_info->global_plte_length);
2046 if (!png_get_valid(ping,ping_info,PNG_INFO_tRNS))
2047 if (mng_info->global_trns_length)
2049 if (mng_info->global_trns_length >
2050 mng_info->global_plte_length)
2051 (void) ThrowMagickException(&image->exception,
2052 GetMagickModule(),CoderError,
2053 "global tRNS has more entries than global PLTE",
2054 "`%s'",image_info->filename);
2055 png_set_tRNS(ping,ping_info,mng_info->global_trns,
2056 (int) mng_info->global_trns_length,NULL);
2058 #if defined(PNG_READ_bKGD_SUPPORTED)
2060 #ifndef PNG_READ_EMPTY_PLTE_SUPPORTED
2061 mng_info->have_saved_bkgd_index ||
2063 png_get_valid(ping,ping_info,PNG_INFO_bKGD))
2068 #ifndef PNG_READ_EMPTY_PLTE_SUPPORTED
2069 if (mng_info->have_saved_bkgd_index)
2070 background.index=mng_info->saved_bkgd_index;
2072 if (png_get_valid(ping, ping_info, PNG_INFO_bKGD))
2073 background.index=ping_background->index;
2075 background.red=(png_uint_16)
2076 mng_info->global_plte[background.index].red;
2078 background.green=(png_uint_16)
2079 mng_info->global_plte[background.index].green;
2081 background.blue=(png_uint_16)
2082 mng_info->global_plte[background.index].blue;
2084 png_set_bKGD(ping,ping_info,&background);
2089 (void) ThrowMagickException(&image->exception,GetMagickModule(),
2090 CoderError,"No global PLTE in file","`%s'",
2091 image_info->filename);
2095 #if defined(PNG_READ_bKGD_SUPPORTED)
2096 if (mng_info->have_global_bkgd &&
2097 (!png_get_valid(ping,ping_info,PNG_INFO_bKGD)))
2098 image->background_color=mng_info->mng_global_bkgd;
2100 if (png_get_valid(ping,ping_info,PNG_INFO_bKGD))
2103 Set image background color.
2105 if (logging != MagickFalse)
2106 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2107 " Reading PNG bKGD chunk.");
2109 if (ping_bit_depth == MAGICKCORE_QUANTUM_DEPTH)
2111 image->background_color.red=ping_background->red;
2112 image->background_color.green=ping_background->green;
2113 image->background_color.blue=ping_background->blue;
2116 else /* Scale background components to 16-bit */
2121 if (logging != MagickFalse)
2122 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2123 " raw ping_background=(%d,%d,%d).",ping_background->red,
2124 ping_background->green,ping_background->blue);
2128 if (ping_bit_depth == 1)
2131 else if (ping_bit_depth == 2)
2134 else if (ping_bit_depth == 4)
2137 if (ping_bit_depth <= 8)
2140 ping_background->red *= bkgd_scale;
2141 ping_background->green *= bkgd_scale;
2142 ping_background->blue *= bkgd_scale;
2144 if (logging != MagickFalse)
2146 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2147 " bkgd_scale=%d.",bkgd_scale);
2149 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2150 " ping_background=(%d,%d,%d).",ping_background->red,
2151 ping_background->green,ping_background->blue);
2154 image->background_color.red=
2155 ScaleShortToQuantum(ping_background->red);
2157 image->background_color.green=
2158 ScaleShortToQuantum(ping_background->green);
2160 image->background_color.blue=
2161 ScaleShortToQuantum(ping_background->blue);
2163 image->background_color.opacity=OpaqueOpacity;
2165 if (logging != MagickFalse)
2166 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2167 " image->background_color=(%.20g,%.20g,%.20g).",
2168 (double) image->background_color.red,
2169 (double) image->background_color.green,
2170 (double) image->background_color.blue);
2175 if (png_get_valid(ping,ping_info,PNG_INFO_tRNS))
2178 Image has a tRNS chunk.
2186 if (logging != MagickFalse)
2187 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2188 " Reading PNG tRNS chunk.");
2190 max_sample = (int) ((one << ping_bit_depth) - 1);
2192 if ((ping_color_type == PNG_COLOR_TYPE_GRAY &&
2193 (int)ping_trans_color->gray > max_sample) ||
2194 (ping_color_type == PNG_COLOR_TYPE_RGB &&
2195 ((int)ping_trans_color->red > max_sample ||
2196 (int)ping_trans_color->green > max_sample ||
2197 (int)ping_trans_color->blue > max_sample)))
2199 if (logging != MagickFalse)
2200 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2201 " Ignoring PNG tRNS chunk with out-of-range sample.");
2202 png_free_data(ping, ping_info, PNG_FREE_TRNS, 0);
2203 png_set_invalid(ping,ping_info,PNG_INFO_tRNS);
2204 image->matte=MagickFalse;
2211 scale_to_short = 65535L/((1UL << ping_bit_depth)-1);
2213 /* Scale transparent_color to short */
2214 transparent_color.red= scale_to_short*ping_trans_color->red;
2215 transparent_color.green= scale_to_short*ping_trans_color->green;
2216 transparent_color.blue= scale_to_short*ping_trans_color->blue;
2217 transparent_color.opacity= scale_to_short*ping_trans_color->gray;
2219 if (ping_color_type == PNG_COLOR_TYPE_GRAY)
2221 if (logging != MagickFalse)
2223 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2224 " Raw tRNS graylevel is %d.",ping_trans_color->gray);
2226 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2227 " scaled graylevel is %d.",transparent_color.opacity);
2229 transparent_color.red=transparent_color.opacity;
2230 transparent_color.green=transparent_color.opacity;
2231 transparent_color.blue=transparent_color.opacity;
2235 #if defined(PNG_READ_sBIT_SUPPORTED)
2236 if (mng_info->have_global_sbit)
2238 if (!png_get_valid(ping,ping_info,PNG_INFO_sBIT))
2239 png_set_sBIT(ping,ping_info,&mng_info->global_sbit);
2242 num_passes=png_set_interlace_handling(ping);
2244 png_read_update_info(ping,ping_info);
2246 ping_rowbytes=png_get_rowbytes(ping,ping_info);
2249 Initialize image structure.
2251 mng_info->image_box.left=0;
2252 mng_info->image_box.right=(ssize_t) ping_width;
2253 mng_info->image_box.top=0;
2254 mng_info->image_box.bottom=(ssize_t) ping_height;
2255 if (mng_info->mng_type == 0)
2257 mng_info->mng_width=ping_width;
2258 mng_info->mng_height=ping_height;
2259 mng_info->frame=mng_info->image_box;
2260 mng_info->clip=mng_info->image_box;
2265 image->page.y=mng_info->y_off[mng_info->object_id];
2268 image->compression=ZipCompression;
2269 image->columns=ping_width;
2270 image->rows=ping_height;
2271 if (((int) ping_color_type == PNG_COLOR_TYPE_PALETTE) ||
2272 ((int) ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA) ||
2273 ((int) ping_color_type == PNG_COLOR_TYPE_GRAY))
2278 image->storage_class=PseudoClass;
2280 image->colors=one << ping_bit_depth;
2281 #if (MAGICKCORE_QUANTUM_DEPTH == 8)
2282 if (image->colors > 256)
2285 if (image->colors > 65536L)
2286 image->colors=65536L;
2288 if ((int) ping_color_type == PNG_COLOR_TYPE_PALETTE)
2296 (void) png_get_PLTE(ping,ping_info,&palette,&number_colors);
2297 image->colors=(size_t) number_colors;
2299 if (logging != MagickFalse)
2300 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2301 " Reading PNG PLTE chunk: number_colors: %d.",number_colors);
2305 if (image->storage_class == PseudoClass)
2308 Initialize image colormap.
2310 if (AcquireImageColormap(image,image->colors) == MagickFalse)
2311 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
2313 if ((int) ping_color_type == PNG_COLOR_TYPE_PALETTE)
2321 (void) png_get_PLTE(ping,ping_info,&palette,&number_colors);
2323 for (i=0; i < (ssize_t) image->colors; i++)
2325 image->colormap[i].red=ScaleCharToQuantum(palette[i].red);
2326 image->colormap[i].green=ScaleCharToQuantum(palette[i].green);
2327 image->colormap[i].blue=ScaleCharToQuantum(palette[i].blue);
2336 scale=(QuantumRange/((1UL << ping_bit_depth)-1));
2341 for (i=0; i < (ssize_t) image->colors; i++)
2343 image->colormap[i].red=(Quantum) (i*scale);
2344 image->colormap[i].green=(Quantum) (i*scale);
2345 image->colormap[i].blue=(Quantum) (i*scale);
2350 Read image scanlines.
2352 if (image->delay != 0)
2353 mng_info->scenes_found++;
2355 if ((mng_info->mng_type == 0 && (image->ping != MagickFalse)) || (
2356 (image_info->number_scenes != 0) && (mng_info->scenes_found > (ssize_t)
2357 (image_info->first_scene+image_info->number_scenes))))
2359 if (logging != MagickFalse)
2360 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2361 " Skipping PNG image data for scene %.20g",(double)
2362 mng_info->scenes_found-1);
2363 png_destroy_read_struct(&ping,&ping_info,&end_info);
2364 #if defined(PNG_SETJMP_NOT_THREAD_SAFE)
2365 UnlockSemaphoreInfo(ping_semaphore);
2367 if (logging != MagickFalse)
2368 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2369 " exit ReadOnePNGImage().");
2374 if (logging != MagickFalse)
2375 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2376 " Reading PNG IDAT chunk(s)");
2379 ping_pixels=(unsigned char *) AcquireQuantumMemory(image->rows,
2380 ping_rowbytes*sizeof(*ping_pixels));
2383 ping_pixels=(unsigned char *) AcquireQuantumMemory(ping_rowbytes,
2384 sizeof(*ping_pixels));
2386 if (ping_pixels == (unsigned char *) NULL)
2387 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
2389 if (logging != MagickFalse)
2390 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2391 " Converting PNG pixels to pixel packets");
2393 Convert PNG pixels to pixel packets.
2395 if (setjmp(png_jmpbuf(ping)))
2398 PNG image is corrupt.
2400 png_destroy_read_struct(&ping,&ping_info,&end_info);
2401 #if defined(PNG_SETJMP_NOT_THREAD_SAFE)
2402 UnlockSemaphoreInfo(ping_semaphore);
2404 if (quantum_info != (QuantumInfo *) NULL)
2405 quantum_info = DestroyQuantumInfo(quantum_info);
2407 if (ping_pixels != (unsigned char *) NULL)
2408 ping_pixels=(unsigned char *) RelinquishMagickMemory(ping_pixels);
2410 if (logging != MagickFalse)
2411 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2412 " exit ReadOnePNGImage() with error.");
2414 if (image != (Image *) NULL)
2416 InheritException(exception,&image->exception);
2420 return(GetFirstImageInList(image));
2423 quantum_info=AcquireQuantumInfo(image_info,image);
2425 if (quantum_info == (QuantumInfo *) NULL)
2426 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
2431 found_transparent_pixel;
2433 found_transparent_pixel=MagickFalse;
2435 if (image->storage_class == DirectClass)
2437 for (pass=0; pass < num_passes; pass++)
2440 Convert image to DirectClass pixel packets.
2442 #if (MAGICKCORE_QUANTUM_DEPTH == 8)
2446 depth=(ssize_t) ping_bit_depth;
2448 image->matte=(((int) ping_color_type == PNG_COLOR_TYPE_RGB_ALPHA) ||
2449 ((int) ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA) ||
2450 (png_get_valid(ping,ping_info,PNG_INFO_tRNS))) ?
2451 MagickTrue : MagickFalse;
2453 for (y=0; y < (ssize_t) image->rows; y++)
2456 row_offset=ping_rowbytes*y;
2461 png_read_row(ping,ping_pixels+row_offset,NULL);
2462 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
2464 if (q == (PixelPacket *) NULL)
2467 #if (0 && (MAGICKCORE_QUANTUM_DEPTH == 8) && !defined(MAGICKCORE_HDRI_SUPPORT))
2468 /* code deleted from version 6.6.6-8 */
2469 #else /* (MAGICKCORE_QUANTUM_DEPTH != 8) */
2471 if ((int) ping_color_type == PNG_COLOR_TYPE_GRAY)
2472 (void) ImportQuantumPixels(image,(CacheView *) NULL,quantum_info,
2473 GrayQuantum,ping_pixels+row_offset,exception);
2475 else if ((int) ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
2476 (void) ImportQuantumPixels(image,(CacheView *) NULL,quantum_info,
2477 GrayAlphaQuantum,ping_pixels+row_offset,exception);
2479 else if ((int) ping_color_type == PNG_COLOR_TYPE_RGB_ALPHA)
2480 (void) ImportQuantumPixels(image,(CacheView *) NULL,quantum_info,
2481 RGBAQuantum,ping_pixels+row_offset,exception);
2483 else if ((int) ping_color_type == PNG_COLOR_TYPE_PALETTE)
2484 (void) ImportQuantumPixels(image,(CacheView *) NULL,quantum_info,
2485 IndexQuantum,ping_pixels+row_offset,exception);
2487 else /* ping_color_type == PNG_COLOR_TYPE_RGB */
2488 (void) ImportQuantumPixels(image,(CacheView *) NULL,quantum_info,
2489 RGBQuantum,ping_pixels+row_offset,exception);
2491 if (found_transparent_pixel == MagickFalse)
2493 /* Is there a transparent pixel in the row? */
2494 if (y== 0 && logging != MagickFalse)
2495 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2496 " Looking for cheap transparent pixel");
2498 for (x=(ssize_t) image->columns-1; x >= 0; x--)
2500 if ((ping_color_type == PNG_COLOR_TYPE_RGBA ||
2501 ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA) &&
2502 (q->opacity != OpaqueOpacity))
2504 if (logging != MagickFalse)
2505 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2508 found_transparent_pixel = MagickTrue;
2511 if ((ping_color_type == PNG_COLOR_TYPE_RGB ||
2512 ping_color_type == PNG_COLOR_TYPE_GRAY) &&
2513 (ScaleQuantumToShort(q->red) == transparent_color.red &&
2514 ScaleQuantumToShort(q->green) == transparent_color.green &&
2515 ScaleQuantumToShort(q->blue) == transparent_color.blue))
2517 if (logging != MagickFalse)
2518 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2520 found_transparent_pixel = MagickTrue;
2527 if ((image->previous == (Image *) NULL) && (num_passes == 1))
2529 status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
2532 if (status == MagickFalse)
2535 if (SyncAuthenticPixels(image,exception) == MagickFalse)
2539 if ((image->previous == (Image *) NULL) && (num_passes != 1))
2541 status=SetImageProgress(image,LoadImageTag,pass,num_passes);
2542 if (status == MagickFalse)
2548 else /* image->storage_class != DirectClass */
2550 for (pass=0; pass < num_passes; pass++)
2559 Convert grayscale image to PseudoClass pixel packets.
2561 image->matte=ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA ?
2562 MagickTrue : MagickFalse;
2564 quantum_scanline=(Quantum *) AcquireQuantumMemory(image->columns,
2565 (image->matte ? 2 : 1)*sizeof(*quantum_scanline));
2567 if (quantum_scanline == (Quantum *) NULL)
2568 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
2570 for (y=0; y < (ssize_t) image->rows; y++)
2573 row_offset=ping_rowbytes*y;
2578 png_read_row(ping,ping_pixels+row_offset,NULL);
2579 q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
2581 if (q == (PixelPacket *) NULL)
2584 indexes=GetAuthenticIndexQueue(image);
2585 p=ping_pixels+row_offset;
2588 switch (ping_bit_depth)
2595 for (x=(ssize_t) image->columns-7; x > 0; x-=8)
2597 for (bit=7; bit >= 0; bit--)
2598 *r++=(Quantum) ((*p) & (0x01 << bit) ? 0x01 : 0x00);
2602 if ((image->columns % 8) != 0)
2604 for (bit=7; bit >= (ssize_t) (8-(image->columns % 8)); bit--)
2605 *r++=(Quantum) ((*p) & (0x01 << bit) ? 0x01 : 0x00);
2613 for (x=(ssize_t) image->columns-3; x > 0; x-=4)
2615 *r++=(*p >> 6) & 0x03;
2616 *r++=(*p >> 4) & 0x03;
2617 *r++=(*p >> 2) & 0x03;
2621 if ((image->columns % 4) != 0)
2623 for (i=3; i >= (ssize_t) (4-(image->columns % 4)); i--)
2624 *r++=(Quantum) ((*p >> (i*2)) & 0x03);
2632 for (x=(ssize_t) image->columns-1; x > 0; x-=2)
2634 *r++=(*p >> 4) & 0x0f;
2638 if ((image->columns % 2) != 0)
2639 *r++=(*p++ >> 4) & 0x0f;
2646 if (ping_color_type == 4)
2647 for (x=(ssize_t) image->columns-1; x >= 0; x--)
2650 /* In image.h, OpaqueOpacity is 0
2651 * TransparentOpacity is QuantumRange
2652 * In a PNG datastream, Opaque is QuantumRange
2653 * and Transparent is 0.
2655 q->opacity=ScaleCharToQuantum((unsigned char) (255-(*p++)));
2656 if (q->opacity != OpaqueOpacity)
2657 found_transparent_pixel = MagickTrue;
2662 for (x=(ssize_t) image->columns-1; x >= 0; x--)
2670 for (x=(ssize_t) image->columns-1; x >= 0; x--)
2672 #if (MAGICKCORE_QUANTUM_DEPTH == 16)
2676 if (image->colors > 256)
2684 *r=(Quantum) quantum;
2687 if (ping_color_type == 4)
2689 quantum=((*p++) << 8);
2691 q->opacity=(Quantum) (QuantumRange-quantum);
2692 if (q->opacity != OpaqueOpacity)
2693 found_transparent_pixel = MagickTrue;
2697 #if (MAGICKCORE_QUANTUM_DEPTH == 32)
2701 if (image->colors > 256)
2712 if (ping_color_type == 4)
2714 q->opacity=(*p << 8) | *(p+1);
2716 q->opacity=(Quantum) GetAlphaPixelComponent(q);
2717 if (q->opacity != OpaqueOpacity)
2718 found_transparent_pixel = MagickTrue;
2723 #else /* MAGICKCORE_QUANTUM_DEPTH == 8 */
2725 p++; /* strip low byte */
2727 if (ping_color_type == 4)
2729 q->opacity=(Quantum) (QuantumRange-(*p++));
2730 if (q->opacity != OpaqueOpacity)
2731 found_transparent_pixel = MagickTrue;
2746 Transfer image scanline.
2750 for (x=0; x < (ssize_t) image->columns; x++)
2751 indexes[x]=(IndexPacket) (*r++);
2753 if (SyncAuthenticPixels(image,exception) == MagickFalse)
2756 if ((image->previous == (Image *) NULL) && (num_passes == 1))
2758 status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
2761 if (status == MagickFalse)
2766 if ((image->previous == (Image *) NULL) && (num_passes != 1))
2768 status=SetImageProgress(image,LoadImageTag,pass,num_passes);
2770 if (status == MagickFalse)
2774 quantum_scanline=(Quantum *) RelinquishMagickMemory(quantum_scanline);
2777 image->matte=found_transparent_pixel;
2779 if (logging != MagickFalse)
2781 if (found_transparent_pixel != MagickFalse)
2782 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2783 " Found transparent pixel");
2786 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2787 " No transparent pixel was found");
2789 ping_color_type&=0x03;
2794 if (quantum_info != (QuantumInfo *) NULL)
2795 quantum_info=DestroyQuantumInfo(quantum_info);
2797 if (image->storage_class == PseudoClass)
2803 image->matte=MagickFalse;
2804 (void) SyncImage(image);
2808 png_read_end(ping,ping_info);
2810 if (image_info->number_scenes != 0 && mng_info->scenes_found-1 <
2811 (ssize_t) image_info->first_scene && image->delay != 0)
2813 png_destroy_read_struct(&ping,&ping_info,&end_info);
2814 ping_pixels=(unsigned char *) RelinquishMagickMemory(ping_pixels);
2816 (void) SetImageBackgroundColor(image);
2817 #if defined(PNG_SETJMP_NOT_THREAD_SAFE)
2818 UnlockSemaphoreInfo(ping_semaphore);
2820 if (logging != MagickFalse)
2821 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2822 " exit ReadOnePNGImage() early.");
2826 if (png_get_valid(ping,ping_info,PNG_INFO_tRNS))
2832 Image has a transparent background.
2834 storage_class=image->storage_class;
2835 image->matte=MagickTrue;
2837 /* Balfour fix from imagemagick discourse server, 5 Feb 2010 */
2839 if (storage_class == PseudoClass)
2841 if ((int) ping_color_type == PNG_COLOR_TYPE_PALETTE)
2843 for (x=0; x < ping_num_trans; x++)
2845 image->colormap[x].opacity =
2846 ScaleCharToQuantum((unsigned char)(255-ping_trans_alpha[x]));
2850 else if (ping_color_type == PNG_COLOR_TYPE_GRAY)
2852 for (x=0; x < (int) image->colors; x++)
2854 if (ScaleQuantumToShort(image->colormap[x].red) ==
2855 transparent_color.opacity)
2857 image->colormap[x].opacity = (Quantum) TransparentOpacity;
2861 (void) SyncImage(image);
2864 #if 1 /* Should have already been done above, but glennrp problem P10
2869 for (y=0; y < (ssize_t) image->rows; y++)
2871 image->storage_class=storage_class;
2872 q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
2874 if (q == (PixelPacket *) NULL)
2877 indexes=GetAuthenticIndexQueue(image);
2879 /* Caution: on a Q8 build, this does not distinguish between
2880 * 16-bit colors that differ only in the low byte
2882 for (x=(ssize_t) image->columns-1; x >= 0; x--)
2884 if (ScaleQuantumToShort(q->red) == transparent_color.red &&
2885 ScaleQuantumToShort(q->green) == transparent_color.green &&
2886 ScaleQuantumToShort(q->blue) == transparent_color.blue)
2888 q->opacity=(Quantum) TransparentOpacity;
2891 #if 0 /* I have not found a case where this is needed. */
2894 q->opacity=(Quantum) OpaqueOpacity;
2901 if (SyncAuthenticPixels(image,exception) == MagickFalse)
2907 image->storage_class=DirectClass;
2910 if ((ping_color_type == PNG_COLOR_TYPE_GRAY) ||
2911 (ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA))
2912 image->colorspace=GRAYColorspace;
2914 if (png_get_text(ping,ping_info,&text,&num_text) != 0)
2915 for (i=0; i < (ssize_t) num_text; i++)
2917 /* Check for a profile */
2919 if (logging != MagickFalse)
2920 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2921 " Reading PNG text chunk");
2923 if (memcmp(text[i].key, "Raw profile type ",17) == 0)
2924 (void) Magick_png_read_raw_profile(image,image_info,text,(int) i);
2931 length=text[i].text_length;
2932 value=(char *) AcquireQuantumMemory(length+MaxTextExtent,
2934 if (value == (char *) NULL)
2936 (void) ThrowMagickException(&image->exception,GetMagickModule(),
2937 ResourceLimitError,"MemoryAllocationFailed","`%s'",
2942 (void) ConcatenateMagickString(value,text[i].text,length+2);
2943 (void) SetImageProperty(image,text[i].key,value);
2945 if (logging != MagickFalse)
2946 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2947 " Keyword: %s",text[i].key);
2949 value=DestroyString(value);
2953 #ifdef MNG_OBJECT_BUFFERS
2955 Store the object if necessary.
2957 if (object_id && !mng_info->frozen[object_id])
2959 if (mng_info->ob[object_id] == (MngBuffer *) NULL)
2962 create a new object buffer.
2964 mng_info->ob[object_id]=(MngBuffer *)
2965 AcquireMagickMemory(sizeof(MngBuffer));
2967 if (mng_info->ob[object_id] != (MngBuffer *) NULL)
2969 mng_info->ob[object_id]->image=(Image *) NULL;
2970 mng_info->ob[object_id]->reference_count=1;
2974 if ((mng_info->ob[object_id] == (MngBuffer *) NULL) ||
2975 mng_info->ob[object_id]->frozen)
2977 if (mng_info->ob[object_id] == (MngBuffer *) NULL)
2978 (void) ThrowMagickException(&image->exception,GetMagickModule(),
2979 ResourceLimitError,"MemoryAllocationFailed","`%s'",
2982 if (mng_info->ob[object_id]->frozen)
2983 (void) ThrowMagickException(&image->exception,GetMagickModule(),
2984 ResourceLimitError,"Cannot overwrite frozen MNG object buffer",
2985 "`%s'",image->filename);
2991 if (mng_info->ob[object_id]->image != (Image *) NULL)
2992 mng_info->ob[object_id]->image=DestroyImage
2993 (mng_info->ob[object_id]->image);
2995 mng_info->ob[object_id]->image=CloneImage(image,0,0,MagickTrue,
2998 if (mng_info->ob[object_id]->image != (Image *) NULL)
2999 mng_info->ob[object_id]->image->file=(FILE *) NULL;
3002 (void) ThrowMagickException(&image->exception,GetMagickModule(),
3003 ResourceLimitError,"Cloning image for object buffer failed",
3004 "`%s'",image->filename);
3006 if (ping_width > 250000L || ping_height > 250000L)
3007 png_error(ping,"PNG Image dimensions are too large.");
3009 mng_info->ob[object_id]->width=ping_width;
3010 mng_info->ob[object_id]->height=ping_height;
3011 mng_info->ob[object_id]->color_type=ping_color_type;
3012 mng_info->ob[object_id]->sample_depth=ping_bit_depth;
3013 mng_info->ob[object_id]->interlace_method=ping_interlace_method;
3014 mng_info->ob[object_id]->compression_method=
3015 ping_compression_method;
3016 mng_info->ob[object_id]->filter_method=ping_filter_method;
3018 if (png_get_valid(ping,ping_info,PNG_INFO_PLTE))
3027 Copy the PLTE to the object buffer.
3029 png_get_PLTE(ping,ping_info,&plte,&number_colors);
3030 mng_info->ob[object_id]->plte_length=number_colors;
3032 for (i=0; i < number_colors; i++)
3034 mng_info->ob[object_id]->plte[i]=plte[i];
3039 mng_info->ob[object_id]->plte_length=0;
3044 Relinquish resources.
3046 png_destroy_read_struct(&ping,&ping_info,&end_info);
3048 ping_pixels=(unsigned char *) RelinquishMagickMemory(ping_pixels);
3049 #if defined(PNG_SETJMP_NOT_THREAD_SAFE)
3050 UnlockSemaphoreInfo(ping_semaphore);
3053 if (logging != MagickFalse)
3054 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3055 " exit ReadOnePNGImage()");
3059 /* end of reading one PNG image */
3062 static Image *ReadPNGImage(const ImageInfo *image_info,ExceptionInfo *exception)
3077 magic_number[MaxTextExtent];
3085 assert(image_info != (const ImageInfo *) NULL);
3086 assert(image_info->signature == MagickSignature);
3088 if (image_info->debug != MagickFalse)
3089 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
3090 image_info->filename);
3092 assert(exception != (ExceptionInfo *) NULL);
3093 assert(exception->signature == MagickSignature);
3094 logging=LogMagickEvent(CoderEvent,GetMagickModule(),"enter ReadPNGImage()");
3095 image=AcquireImage(image_info);
3096 mng_info=(MngInfo *) NULL;
3097 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
3099 if (status == MagickFalse)
3100 ThrowReaderException(FileOpenError,"UnableToOpenFile");
3103 Verify PNG signature.
3105 count=ReadBlob(image,8,(unsigned char *) magic_number);
3107 if (memcmp(magic_number,"\211PNG\r\n\032\n",8) != 0)
3108 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
3111 Allocate a MngInfo structure.
3113 have_mng_structure=MagickFalse;
3114 mng_info=(MngInfo *) AcquireMagickMemory(sizeof(MngInfo));
3116 if (mng_info == (MngInfo *) NULL)
3117 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
3120 Initialize members of the MngInfo structure.
3122 (void) ResetMagickMemory(mng_info,0,sizeof(MngInfo));
3123 mng_info->image=image;
3124 have_mng_structure=MagickTrue;
3127 image=ReadOnePNGImage(mng_info,image_info,exception);
3128 MngInfoFreeStruct(mng_info,&have_mng_structure);
3130 if (image == (Image *) NULL)
3132 if (previous != (Image *) NULL)
3134 if (previous->signature != MagickSignature)
3135 ThrowReaderException(CorruptImageError,"CorruptImage");
3137 (void) CloseBlob(previous);
3138 (void) DestroyImageList(previous);
3141 if (logging != MagickFalse)
3142 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3143 "exit ReadPNGImage() with error");
3145 return((Image *) NULL);
3148 (void) CloseBlob(image);
3150 if ((image->columns == 0) || (image->rows == 0))
3152 if (logging != MagickFalse)
3153 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3154 "exit ReadPNGImage() with error.");
3156 ThrowReaderException(CorruptImageError,"CorruptImage");
3159 if (LocaleCompare(image_info->magick,"PNG8") == 0)
3161 (void) SetImageType(image,PaletteType);
3163 if (image->matte != MagickFalse)
3165 /* To do: Reduce to binary transparency */
3169 if (LocaleCompare(image_info->magick,"PNG24") == 0)
3171 (void) SetImageType(image,TrueColorType);
3172 image->matte=MagickFalse;
3175 if (LocaleCompare(image_info->magick,"PNG32") == 0)
3176 (void) SetImageType(image,TrueColorMatteType);
3178 if (logging != MagickFalse)
3179 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"exit ReadPNGImage()");
3186 #if defined(JNG_SUPPORTED)
3188 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3192 % R e a d O n e J N G I m a g e %
3196 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3198 % ReadOneJNGImage() reads a JPEG Network Graphics (JNG) image file
3199 % (minus the 8-byte signature) and returns it. It allocates the memory
3200 % necessary for the new Image structure and returns a pointer to the new
3203 % JNG support written by Glenn Randers-Pehrson, glennrp@image...
3205 % The format of the ReadOneJNGImage method is:
3207 % Image *ReadOneJNGImage(MngInfo *mng_info, const ImageInfo *image_info,
3208 % ExceptionInfo *exception)
3210 % A description of each parameter follows:
3212 % o mng_info: Specifies a pointer to a MngInfo structure.
3214 % o image_info: the image info.
3216 % o exception: return any errors or warnings in this structure.
3219 static Image *ReadOneJNGImage(MngInfo *mng_info,
3220 const ImageInfo *image_info, ExceptionInfo *exception)
3247 jng_image_sample_depth,
3248 jng_image_compression_method,
3249 jng_image_interlace_method,
3250 jng_alpha_sample_depth,
3251 jng_alpha_compression_method,
3252 jng_alpha_filter_method,
3253 jng_alpha_interlace_method;
3255 register const PixelPacket
3262 register PixelPacket
3265 register unsigned char
3276 jng_alpha_compression_method=0;
3277 jng_alpha_sample_depth=8;
3281 alpha_image=(Image *) NULL;
3282 color_image=(Image *) NULL;
3283 alpha_image_info=(ImageInfo *) NULL;
3284 color_image_info=(ImageInfo *) NULL;
3286 logging=LogMagickEvent(CoderEvent,GetMagickModule(),
3287 " enter ReadOneJNGImage()");
3289 image=mng_info->image;
3291 if (GetAuthenticPixelQueue(image) != (PixelPacket *) NULL)
3294 Allocate next image structure.
3296 if (logging != MagickFalse)
3297 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3298 " AcquireNextImage()");
3300 AcquireNextImage(image_info,image);
3302 if (GetNextImageInList(image) == (Image *) NULL)
3303 return((Image *) NULL);
3305 image=SyncNextImageInList(image);
3307 mng_info->image=image;
3310 Signature bytes have already been read.
3313 read_JSEP=MagickFalse;
3314 reading_idat=MagickFalse;
3315 skip_to_iend=MagickFalse;
3319 type[MaxTextExtent];
3328 Read a new JNG chunk.
3330 status=SetImageProgress(image,LoadImagesTag,TellBlob(image),
3331 2*GetBlobSize(image));
3333 if (status == MagickFalse)
3337 (void) ConcatenateMagickString(type,"errr",MaxTextExtent);
3338 length=ReadBlobMSBLong(image);
3339 count=(unsigned int) ReadBlob(image,4,(unsigned char *) type);
3341 if (logging != MagickFalse)
3342 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3343 " Reading JNG chunk type %c%c%c%c, length: %.20g",
3344 type[0],type[1],type[2],type[3],(double) length);
3346 if (length > PNG_UINT_31_MAX || count == 0)
3347 ThrowReaderException(CorruptImageError,"CorruptImage");
3350 chunk=(unsigned char *) NULL;
3354 chunk=(unsigned char *) AcquireQuantumMemory(length,sizeof(*chunk));
3356 if (chunk == (unsigned char *) NULL)
3357 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
3359 for (i=0; i < (ssize_t) length; i++)
3360 chunk[i]=(unsigned char) ReadBlobByte(image);
3365 (void) ReadBlobMSBLong(image); /* read crc word */
3370 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
3375 if (memcmp(type,mng_JHDR,4) == 0)
3379 jng_width=(size_t) ((p[0] << 24) | (p[1] << 16) |
3380 (p[2] << 8) | p[3]);
3381 jng_height=(size_t) ((p[4] << 24) | (p[5] << 16) |
3382 (p[6] << 8) | p[7]);
3383 jng_color_type=p[8];
3384 jng_image_sample_depth=p[9];
3385 jng_image_compression_method=p[10];
3386 jng_image_interlace_method=p[11];
3388 image->interlace=jng_image_interlace_method != 0 ? PNGInterlace :
3391 jng_alpha_sample_depth=p[12];
3392 jng_alpha_compression_method=p[13];
3393 jng_alpha_filter_method=p[14];
3394 jng_alpha_interlace_method=p[15];
3396 if (logging != MagickFalse)
3398 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3399 " jng_width: %16lu",(unsigned long) jng_width);
3401 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3402 " jng_width: %16lu",(unsigned long) jng_height);
3404 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3405 " jng_color_type: %16d",jng_color_type);
3407 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3408 " jng_image_sample_depth: %3d",
3409 jng_image_sample_depth);
3411 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3412 " jng_image_compression_method:%3d",
3413 jng_image_compression_method);
3415 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3416 " jng_image_interlace_method: %3d",
3417 jng_image_interlace_method);
3419 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3420 " jng_alpha_sample_depth: %3d",
3421 jng_alpha_sample_depth);
3423 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3424 " jng_alpha_compression_method:%3d",
3425 jng_alpha_compression_method);
3427 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3428 " jng_alpha_filter_method: %3d",
3429 jng_alpha_filter_method);
3431 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3432 " jng_alpha_interlace_method: %3d",
3433 jng_alpha_interlace_method);
3438 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
3444 if ((reading_idat == MagickFalse) && (read_JSEP == MagickFalse) &&
3445 ((memcmp(type,mng_JDAT,4) == 0) || (memcmp(type,mng_JdAA,4) == 0) ||
3446 (memcmp(type,mng_IDAT,4) == 0) || (memcmp(type,mng_JDAA,4) == 0)))
3449 o create color_image
3450 o open color_blob, attached to color_image
3451 o if (color type has alpha)
3452 open alpha_blob, attached to alpha_image
3455 color_image_info=(ImageInfo *)AcquireMagickMemory(sizeof(ImageInfo));
3457 if (color_image_info == (ImageInfo *) NULL)
3458 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
3460 GetImageInfo(color_image_info);
3461 color_image=AcquireImage(color_image_info);
3463 if (color_image == (Image *) NULL)
3464 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
3466 if (logging != MagickFalse)
3467 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3468 " Creating color_blob.");
3470 (void) AcquireUniqueFilename(color_image->filename);
3471 status=OpenBlob(color_image_info,color_image,WriteBinaryBlobMode,
3474 if (status == MagickFalse)
3475 return((Image *) NULL);
3477 if ((image_info->ping == MagickFalse) && (jng_color_type >= 12))
3479 alpha_image_info=(ImageInfo *)
3480 AcquireMagickMemory(sizeof(ImageInfo));
3482 if (alpha_image_info == (ImageInfo *) NULL)
3483 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
3485 GetImageInfo(alpha_image_info);
3486 alpha_image=AcquireImage(alpha_image_info);
3488 if (alpha_image == (Image *) NULL)
3490 alpha_image=DestroyImage(alpha_image);
3491 ThrowReaderException(ResourceLimitError,
3492 "MemoryAllocationFailed");
3495 if (logging != MagickFalse)
3496 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3497 " Creating alpha_blob.");
3499 (void) AcquireUniqueFilename(alpha_image->filename);
3500 status=OpenBlob(alpha_image_info,alpha_image,WriteBinaryBlobMode,
3503 if (status == MagickFalse)
3504 return((Image *) NULL);
3506 if (jng_alpha_compression_method == 0)
3511 if (logging != MagickFalse)
3512 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3513 " Writing IHDR chunk to alpha_blob.");
3515 (void) WriteBlob(alpha_image,8,(const unsigned char *)
3516 "\211PNG\r\n\032\n");
3518 (void) WriteBlobMSBULong(alpha_image,13L);
3519 PNGType(data,mng_IHDR);
3520 LogPNGChunk(logging,mng_IHDR,13L);
3521 PNGLong(data+4,jng_width);
3522 PNGLong(data+8,jng_height);
3523 data[12]=jng_alpha_sample_depth;
3524 data[13]=0; /* color_type gray */
3525 data[14]=0; /* compression method 0 */
3526 data[15]=0; /* filter_method 0 */
3527 data[16]=0; /* interlace_method 0 */
3528 (void) WriteBlob(alpha_image,17,data);
3529 (void) WriteBlobMSBULong(alpha_image,crc32(0,data,17));
3532 reading_idat=MagickTrue;
3535 if (memcmp(type,mng_JDAT,4) == 0)
3537 /* Copy chunk to color_image->blob */
3539 if (logging != MagickFalse)
3540 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3541 " Copying JDAT chunk data to color_blob.");
3543 (void) WriteBlob(color_image,length,chunk);
3546 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
3551 if (memcmp(type,mng_IDAT,4) == 0)
3556 /* Copy IDAT header and chunk data to alpha_image->blob */
3558 if (image_info->ping == MagickFalse)
3560 if (logging != MagickFalse)
3561 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3562 " Copying IDAT chunk data to alpha_blob.");
3564 (void) WriteBlobMSBULong(alpha_image,(size_t) length);
3565 PNGType(data,mng_IDAT);
3566 LogPNGChunk(logging,mng_IDAT,length);
3567 (void) WriteBlob(alpha_image,4,data);
3568 (void) WriteBlob(alpha_image,length,chunk);
3569 (void) WriteBlobMSBULong(alpha_image,
3570 crc32(crc32(0,data,4),chunk,(uInt) length));
3574 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
3579 if ((memcmp(type,mng_JDAA,4) == 0) || (memcmp(type,mng_JdAA,4) == 0))
3581 /* Copy chunk data to alpha_image->blob */
3583 if (image_info->ping == MagickFalse)
3585 if (logging != MagickFalse)
3586 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3587 " Copying JDAA chunk data to alpha_blob.");
3589 (void) WriteBlob(alpha_image,length,chunk);
3593 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
3598 if (memcmp(type,mng_JSEP,4) == 0)
3600 read_JSEP=MagickTrue;
3603 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
3608 if (memcmp(type,mng_bKGD,4) == 0)
3612 image->background_color.red=ScaleCharToQuantum(p[1]);
3613 image->background_color.green=image->background_color.red;
3614 image->background_color.blue=image->background_color.red;
3619 image->background_color.red=ScaleCharToQuantum(p[1]);
3620 image->background_color.green=ScaleCharToQuantum(p[3]);
3621 image->background_color.blue=ScaleCharToQuantum(p[5]);
3624 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
3628 if (memcmp(type,mng_gAMA,4) == 0)
3631 image->gamma=((float) mng_get_long(p))*0.00001;
3633 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
3637 if (memcmp(type,mng_cHRM,4) == 0)
3641 image->chromaticity.white_point.x=0.00001*mng_get_long(p);
3642 image->chromaticity.white_point.y=0.00001*mng_get_long(&p[4]);
3643 image->chromaticity.red_primary.x=0.00001*mng_get_long(&p[8]);
3644 image->chromaticity.red_primary.y=0.00001*mng_get_long(&p[12]);
3645 image->chromaticity.green_primary.x=0.00001*mng_get_long(&p[16]);
3646 image->chromaticity.green_primary.y=0.00001*mng_get_long(&p[20]);
3647 image->chromaticity.blue_primary.x=0.00001*mng_get_long(&p[24]);
3648 image->chromaticity.blue_primary.y=0.00001*mng_get_long(&p[28]);
3651 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
3655 if (memcmp(type,mng_sRGB,4) == 0)
3659 image->rendering_intent=
3660 Magick_RenderingIntent_from_PNG_RenderingIntent(p[0]);
3661 image->gamma=0.45455f;
3662 image->chromaticity.red_primary.x=0.6400f;
3663 image->chromaticity.red_primary.y=0.3300f;
3664 image->chromaticity.green_primary.x=0.3000f;
3665 image->chromaticity.green_primary.y=0.6000f;
3666 image->chromaticity.blue_primary.x=0.1500f;
3667 image->chromaticity.blue_primary.y=0.0600f;
3668 image->chromaticity.white_point.x=0.3127f;
3669 image->chromaticity.white_point.y=0.3290f;
3672 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
3676 if (memcmp(type,mng_oFFs,4) == 0)
3680 image->page.x=mng_get_long(p);
3681 image->page.y=mng_get_long(&p[4]);
3683 if ((int) p[8] != 0)
3685 image->page.x/=10000;
3686 image->page.y/=10000;
3691 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
3696 if (memcmp(type,mng_pHYs,4) == 0)
3700 image->x_resolution=(double) mng_get_long(p);
3701 image->y_resolution=(double) mng_get_long(&p[4]);
3702 if ((int) p[8] == PNG_RESOLUTION_METER)
3704 image->units=PixelsPerCentimeterResolution;
3705 image->x_resolution=image->x_resolution/100.0f;
3706 image->y_resolution=image->y_resolution/100.0f;
3710 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
3715 if (memcmp(type,mng_iCCP,4) == 0)
3719 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
3726 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
3728 if (memcmp(type,mng_IEND,4))
3738 Finish up reading image data:
3740 o read main image from color_blob.
3744 o if (color_type has alpha)
3745 if alpha_encoding is PNG
3746 read secondary image from alpha_blob via ReadPNG
3747 if alpha_encoding is JPEG
3748 read secondary image from alpha_blob via ReadJPEG
3752 o copy intensity of secondary image into
3753 opacity samples of main image.
3755 o destroy the secondary image.
3758 (void) CloseBlob(color_image);
3760 if (logging != MagickFalse)
3761 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3762 " Reading jng_image from color_blob.");
3764 (void) FormatMagickString(color_image_info->filename,MaxTextExtent,"%s",
3765 color_image->filename);
3767 color_image_info->ping=MagickFalse; /* To do: avoid this */
3768 jng_image=ReadImage(color_image_info,exception);
3770 if (jng_image == (Image *) NULL)
3771 return((Image *) NULL);
3773 (void) RelinquishUniqueFileResource(color_image->filename);
3774 color_image=DestroyImage(color_image);
3775 color_image_info=DestroyImageInfo(color_image_info);
3777 if (jng_image == (Image *) NULL)
3778 return((Image *) NULL);
3780 if (logging != MagickFalse)
3781 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3782 " Copying jng_image pixels to main image.");
3784 image->rows=jng_height;
3785 image->columns=jng_width;
3786 length=image->columns*sizeof(PixelPacket);
3788 for (y=0; y < (ssize_t) image->rows; y++)
3790 s=GetVirtualPixels(jng_image,0,y,image->columns,1,&image->exception);
3791 q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
3792 (void) CopyMagickMemory(q,s,length);
3794 if (SyncAuthenticPixels(image,exception) == MagickFalse)
3798 jng_image=DestroyImage(jng_image);
3800 if (image_info->ping == MagickFalse)
3802 if (jng_color_type >= 12)
3804 if (jng_alpha_compression_method == 0)
3808 (void) WriteBlobMSBULong(alpha_image,0x00000000L);
3809 PNGType(data,mng_IEND);
3810 LogPNGChunk(logging,mng_IEND,0L);
3811 (void) WriteBlob(alpha_image,4,data);
3812 (void) WriteBlobMSBULong(alpha_image,crc32(0,data,4));
3815 (void) CloseBlob(alpha_image);
3817 if (logging != MagickFalse)
3818 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3819 " Reading opacity from alpha_blob.");
3821 (void) FormatMagickString(alpha_image_info->filename,MaxTextExtent,
3822 "%s",alpha_image->filename);
3824 jng_image=ReadImage(alpha_image_info,exception);
3826 if (jng_image != (Image *) NULL)
3827 for (y=0; y < (ssize_t) image->rows; y++)
3829 s=GetVirtualPixels(jng_image,0,y,image->columns,1,
3831 q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
3833 if (image->matte != MagickFalse)
3834 for (x=(ssize_t) image->columns; x != 0; x--,q++,s++)
3835 q->opacity=(Quantum) QuantumRange-s->red;
3838 for (x=(ssize_t) image->columns; x != 0; x--,q++,s++)
3840 q->opacity=(Quantum) QuantumRange-s->red;
3841 if (q->opacity != OpaqueOpacity)
3842 image->matte=MagickTrue;
3845 if (SyncAuthenticPixels(image,exception) == MagickFalse)
3848 (void) RelinquishUniqueFileResource(alpha_image->filename);
3849 alpha_image=DestroyImage(alpha_image);
3850 alpha_image_info=DestroyImageInfo(alpha_image_info);
3851 if (jng_image != (Image *) NULL)
3852 jng_image=DestroyImage(jng_image);
3856 /* Read the JNG image. */
3858 if (mng_info->mng_type == 0)
3860 mng_info->mng_width=jng_width;
3861 mng_info->mng_height=jng_height;
3864 if (image->page.width == 0 && image->page.height == 0)
3866 image->page.width=jng_width;
3867 image->page.height=jng_height;
3870 if (image->page.x == 0 && image->page.y == 0)
3872 image->page.x=mng_info->x_off[mng_info->object_id];
3873 image->page.y=mng_info->y_off[mng_info->object_id];
3878 image->page.y=mng_info->y_off[mng_info->object_id];
3881 mng_info->image_found++;
3882 status=SetImageProgress(image,LoadImagesTag,2*TellBlob(image),
3883 2*GetBlobSize(image));
3885 if (logging != MagickFalse)
3886 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3887 " exit ReadOneJNGImage()");
3893 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3897 % R e a d J N G I m a g e %
3901 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3903 % ReadJNGImage() reads a JPEG Network Graphics (JNG) image file
3904 % (including the 8-byte signature) and returns it. It allocates the memory
3905 % necessary for the new Image structure and returns a pointer to the new
3908 % JNG support written by Glenn Randers-Pehrson, glennrp@image...
3910 % The format of the ReadJNGImage method is:
3912 % Image *ReadJNGImage(const ImageInfo *image_info, ExceptionInfo
3915 % A description of each parameter follows:
3917 % o image_info: the image info.
3919 % o exception: return any errors or warnings in this structure.
3923 static Image *ReadJNGImage(const ImageInfo *image_info,ExceptionInfo *exception)
3938 magic_number[MaxTextExtent];
3946 assert(image_info != (const ImageInfo *) NULL);
3947 assert(image_info->signature == MagickSignature);
3948 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image_info->filename);
3949 assert(exception != (ExceptionInfo *) NULL);
3950 assert(exception->signature == MagickSignature);
3951 logging=LogMagickEvent(CoderEvent,GetMagickModule(),"enter ReadJNGImage()");
3952 image=AcquireImage(image_info);
3953 mng_info=(MngInfo *) NULL;
3954 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
3956 if (status == MagickFalse)
3957 return((Image *) NULL);
3959 if (LocaleCompare(image_info->magick,"JNG") != 0)
3960 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
3962 /* Verify JNG signature. */
3964 count=(size_t) ReadBlob(image,8,(unsigned char *) magic_number);
3966 if (memcmp(magic_number,"\213JNG\r\n\032\n",8) != 0)
3967 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
3969 /* Allocate a MngInfo structure. */
3971 have_mng_structure=MagickFalse;
3972 mng_info=(MngInfo *) AcquireMagickMemory(sizeof(*mng_info));
3974 if (mng_info == (MngInfo *) NULL)
3975 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
3977 /* Initialize members of the MngInfo structure. */
3979 (void) ResetMagickMemory(mng_info,0,sizeof(MngInfo));
3980 have_mng_structure=MagickTrue;
3982 mng_info->image=image;
3984 image=ReadOneJNGImage(mng_info,image_info,exception);
3985 MngInfoFreeStruct(mng_info,&have_mng_structure);
3987 if (image == (Image *) NULL)
3989 if (IsImageObject(previous) != MagickFalse)
3991 (void) CloseBlob(previous);
3992 (void) DestroyImageList(previous);
3995 if (logging != MagickFalse)
3996 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3997 "exit ReadJNGImage() with error");
3999 return((Image *) NULL);
4001 (void) CloseBlob(image);
4003 if (image->columns == 0 || image->rows == 0)
4005 if (logging != MagickFalse)
4006 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4007 "exit ReadJNGImage() with error");
4009 ThrowReaderException(CorruptImageError,"CorruptImage");
4012 if (logging != MagickFalse)
4013 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"exit ReadJNGImage()");
4019 static Image *ReadMNGImage(const ImageInfo *image_info,ExceptionInfo *exception)
4022 page_geometry[MaxTextExtent];
4055 #if defined(MNG_INSERT_LAYERS)
4057 mng_background_color;
4060 register unsigned char
4075 #if defined(MNG_INSERT_LAYERS)
4080 volatile unsigned int
4081 #ifdef MNG_OBJECT_BUFFERS
4082 mng_background_object=0,
4084 mng_type=0; /* 0: PNG or JNG; 1: MNG; 2: MNG-LC; 3: MNG-VLC */
4087 default_frame_timeout,
4089 #if defined(MNG_INSERT_LAYERS)
4095 /* These delays are all measured in image ticks_per_second,
4096 * not in MNG ticks_per_second
4099 default_frame_delay,
4103 #if defined(MNG_INSERT_LAYERS)
4112 previous_fb.bottom=0;
4114 previous_fb.right=0;
4116 default_fb.bottom=0;
4120 /* Open image file. */
4122 assert(image_info != (const ImageInfo *) NULL);
4123 assert(image_info->signature == MagickSignature);
4124 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image_info->filename);
4125 assert(exception != (ExceptionInfo *) NULL);
4126 assert(exception->signature == MagickSignature);
4127 logging=LogMagickEvent(CoderEvent,GetMagickModule(),"enter ReadMNGImage()");
4128 image=AcquireImage(image_info);
4129 mng_info=(MngInfo *) NULL;
4130 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
4132 if (status == MagickFalse)
4133 return((Image *) NULL);
4135 first_mng_object=MagickFalse;
4137 have_mng_structure=MagickFalse;
4139 /* Allocate a MngInfo structure. */
4141 mng_info=(MngInfo *) AcquireMagickMemory(sizeof(MngInfo));
4143 if (mng_info == (MngInfo *) NULL)
4144 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
4146 /* Initialize members of the MngInfo structure. */
4148 (void) ResetMagickMemory(mng_info,0,sizeof(MngInfo));
4149 mng_info->image=image;
4150 have_mng_structure=MagickTrue;
4152 if (LocaleCompare(image_info->magick,"MNG") == 0)
4155 magic_number[MaxTextExtent];
4157 /* Verify MNG signature. */
4158 count=(size_t) ReadBlob(image,8,(unsigned char *) magic_number);
4159 if (memcmp(magic_number,"\212MNG\r\n\032\n",8) != 0)
4160 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
4162 /* Initialize some nonzero members of the MngInfo structure. */
4163 for (i=0; i < MNG_MAX_OBJECTS; i++)
4165 mng_info->object_clip[i].right=(ssize_t) PNG_UINT_31_MAX;
4166 mng_info->object_clip[i].bottom=(ssize_t) PNG_UINT_31_MAX;
4168 mng_info->exists[0]=MagickTrue;
4171 first_mng_object=MagickTrue;
4173 #if defined(MNG_INSERT_LAYERS)
4174 insert_layers=MagickFalse; /* should be False when converting or mogrifying */
4176 default_frame_delay=0;
4177 default_frame_timeout=0;
4180 mng_info->ticks_per_second=1UL*image->ticks_per_second;
4182 skip_to_iend=MagickFalse;
4183 term_chunk_found=MagickFalse;
4184 mng_info->framing_mode=1;
4185 #if defined(MNG_INSERT_LAYERS)
4186 mandatory_back=MagickFalse;
4188 #if defined(MNG_INSERT_LAYERS)
4189 mng_background_color=image->background_color;
4191 default_fb=mng_info->frame;
4192 previous_fb=mng_info->frame;
4196 type[MaxTextExtent];
4198 if (LocaleCompare(image_info->magick,"MNG") == 0)
4207 (void) ConcatenateMagickString(type,"errr",MaxTextExtent);
4208 length=ReadBlobMSBLong(image);
4209 count=(size_t) ReadBlob(image,4,(unsigned char *) type);
4211 if (logging != MagickFalse)
4212 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4213 " Reading MNG chunk type %c%c%c%c, length: %.20g",
4214 type[0],type[1],type[2],type[3],(double) length);
4216 if (length > PNG_UINT_31_MAX)
4220 ThrowReaderException(CorruptImageError,"CorruptImage");
4223 chunk=(unsigned char *) NULL;
4227 chunk=(unsigned char *) AcquireQuantumMemory(length,sizeof(*chunk));
4229 if (chunk == (unsigned char *) NULL)
4230 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
4232 for (i=0; i < (ssize_t) length; i++)
4233 chunk[i]=(unsigned char) ReadBlobByte(image);
4238 (void) ReadBlobMSBLong(image); /* read crc word */
4240 #if !defined(JNG_SUPPORTED)
4241 if (memcmp(type,mng_JHDR,4) == 0)
4243 skip_to_iend=MagickTrue;
4245 if (mng_info->jhdr_warning == 0)
4246 (void) ThrowMagickException(&image->exception,GetMagickModule(),
4247 CoderError,"JNGCompressNotSupported","`%s'",image->filename);
4249 mng_info->jhdr_warning++;
4252 if (memcmp(type,mng_DHDR,4) == 0)
4254 skip_to_iend=MagickTrue;
4256 if (mng_info->dhdr_warning == 0)
4257 (void) ThrowMagickException(&image->exception,GetMagickModule(),
4258 CoderError,"DeltaPNGNotSupported","`%s'",image->filename);
4260 mng_info->dhdr_warning++;
4262 if (memcmp(type,mng_MEND,4) == 0)
4267 if (memcmp(type,mng_IEND,4) == 0)
4268 skip_to_iend=MagickFalse;
4271 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4273 if (logging != MagickFalse)
4274 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4280 if (memcmp(type,mng_MHDR,4) == 0)
4282 mng_info->mng_width=(size_t) ((p[0] << 24) | (p[1] << 16) |
4283 (p[2] << 8) | p[3]);
4285 mng_info->mng_height=(size_t) ((p[4] << 24) | (p[5] << 16) |
4286 (p[6] << 8) | p[7]);
4288 if (logging != MagickFalse)
4290 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4291 " MNG width: %.20g",(double) mng_info->mng_width);
4292 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4293 " MNG height: %.20g",(double) mng_info->mng_height);
4297 mng_info->ticks_per_second=(size_t) mng_get_long(p);
4299 if (mng_info->ticks_per_second == 0)
4300 default_frame_delay=0;
4303 default_frame_delay=1UL*image->ticks_per_second/
4304 mng_info->ticks_per_second;
4306 frame_delay=default_frame_delay;
4312 simplicity=(size_t) mng_get_long(p);
4315 mng_type=1; /* Full MNG */
4317 if ((simplicity != 0) && ((simplicity | 11) == 11))
4318 mng_type=2; /* LC */
4320 if ((simplicity != 0) && ((simplicity | 9) == 9))
4321 mng_type=3; /* VLC */
4323 #if defined(MNG_INSERT_LAYERS)
4325 insert_layers=MagickTrue;
4327 if (GetAuthenticPixelQueue(image) != (PixelPacket *) NULL)
4329 /* Allocate next image structure. */
4330 AcquireNextImage(image_info,image);
4332 if (GetNextImageInList(image) == (Image *) NULL)
4333 return((Image *) NULL);
4335 image=SyncNextImageInList(image);
4336 mng_info->image=image;
4339 if ((mng_info->mng_width > 65535L) ||
4340 (mng_info->mng_height > 65535L))
4341 ThrowReaderException(ImageError,"WidthOrHeightExceedsLimit");
4343 (void) FormatMagickString(page_geometry,MaxTextExtent,
4344 "%.20gx%.20g+0+0",(double) mng_info->mng_width,(double)
4345 mng_info->mng_height);
4347 mng_info->frame.left=0;
4348 mng_info->frame.right=(ssize_t) mng_info->mng_width;
4349 mng_info->frame.top=0;
4350 mng_info->frame.bottom=(ssize_t) mng_info->mng_height;
4351 mng_info->clip=default_fb=previous_fb=mng_info->frame;
4353 for (i=0; i < MNG_MAX_OBJECTS; i++)
4354 mng_info->object_clip[i]=mng_info->frame;
4356 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4360 if (memcmp(type,mng_TERM,4) == 0)
4371 final_delay=(png_uint_32) mng_get_long(&p[2]);
4372 mng_iterations=(png_uint_32) mng_get_long(&p[6]);
4374 if (mng_iterations == PNG_UINT_31_MAX)
4377 image->iterations=mng_iterations;
4378 term_chunk_found=MagickTrue;
4381 if (logging != MagickFalse)
4383 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4384 " repeat=%d",repeat);
4386 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4387 " final_delay=%.20g",(double) final_delay);
4389 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4390 " image->iterations=%.20g",(double) image->iterations);
4393 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4396 if (memcmp(type,mng_DEFI,4) == 0)
4399 (void) ThrowMagickException(&image->exception,GetMagickModule(),
4400 CoderError,"DEFI chunk found in MNG-VLC datastream","`%s'",
4403 object_id=(p[0] << 8) | p[1];
4405 if (mng_type == 2 && object_id != 0)
4406 (void) ThrowMagickException(&image->exception,GetMagickModule(),
4407 CoderError,"Nonzero object_id in MNG-LC datastream","`%s'",
4410 if (object_id > MNG_MAX_OBJECTS)
4413 Instead ofsuing a warning we should allocate a larger
4414 MngInfo structure and continue.
4416 (void) ThrowMagickException(&image->exception,GetMagickModule(),
4417 CoderError,"object id too large","`%s'",image->filename);
4418 object_id=MNG_MAX_OBJECTS;
4421 if (mng_info->exists[object_id])
4422 if (mng_info->frozen[object_id])
4424 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4425 (void) ThrowMagickException(&image->exception,
4426 GetMagickModule(),CoderError,
4427 "DEFI cannot redefine a frozen MNG object","`%s'",
4432 mng_info->exists[object_id]=MagickTrue;
4435 mng_info->invisible[object_id]=p[2];
4438 Extract object offset info.
4442 mng_info->x_off[object_id]=(ssize_t) ((p[4] << 24) |
4443 (p[5] << 16) | (p[6] << 8) | p[7]);
4445 mng_info->y_off[object_id]=(ssize_t) ((p[8] << 24) |
4446 (p[9] << 16) | (p[10] << 8) | p[11]);
4448 if (logging != MagickFalse)
4450 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4451 " x_off[%d]: %.20g",object_id,(double)
4452 mng_info->x_off[object_id]);
4454 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4455 " y_off[%d]: %.20g",object_id,(double)
4456 mng_info->y_off[object_id]);
4461 Extract object clipping info.
4464 mng_info->object_clip[object_id]=mng_read_box(mng_info->frame,0,
4467 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4470 if (memcmp(type,mng_bKGD,4) == 0)
4472 mng_info->have_global_bkgd=MagickFalse;
4476 mng_info->mng_global_bkgd.red=
4477 ScaleShortToQuantum((unsigned short) ((p[0] << 8) | p[1]));
4479 mng_info->mng_global_bkgd.green=
4480 ScaleShortToQuantum((unsigned short) ((p[2] << 8) | p[3]));
4482 mng_info->mng_global_bkgd.blue=
4483 ScaleShortToQuantum((unsigned short) ((p[4] << 8) | p[5]));
4485 mng_info->have_global_bkgd=MagickTrue;
4488 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4491 if (memcmp(type,mng_BACK,4) == 0)
4493 #if defined(MNG_INSERT_LAYERS)
4495 mandatory_back=p[6];
4500 if (mandatory_back && length > 5)
4502 mng_background_color.red=
4503 ScaleShortToQuantum((unsigned short) ((p[0] << 8) | p[1]));
4505 mng_background_color.green=
4506 ScaleShortToQuantum((unsigned short) ((p[2] << 8) | p[3]));
4508 mng_background_color.blue=
4509 ScaleShortToQuantum((unsigned short) ((p[4] << 8) | p[5]));
4511 mng_background_color.opacity=OpaqueOpacity;
4514 #ifdef MNG_OBJECT_BUFFERS
4516 mng_background_object=(p[7] << 8) | p[8];
4519 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4523 if (memcmp(type,mng_PLTE,4) == 0)
4525 /* Read global PLTE. */
4527 if (length && (length < 769))
4529 if (mng_info->global_plte == (png_colorp) NULL)
4530 mng_info->global_plte=(png_colorp) AcquireQuantumMemory(256,
4531 sizeof(*mng_info->global_plte));
4533 for (i=0; i < (ssize_t) (length/3); i++)
4535 mng_info->global_plte[i].red=p[3*i];
4536 mng_info->global_plte[i].green=p[3*i+1];
4537 mng_info->global_plte[i].blue=p[3*i+2];
4540 mng_info->global_plte_length=(unsigned int) (length/3);
4543 for ( ; i < 256; i++)
4545 mng_info->global_plte[i].red=i;
4546 mng_info->global_plte[i].green=i;
4547 mng_info->global_plte[i].blue=i;
4551 mng_info->global_plte_length=256;
4554 mng_info->global_plte_length=0;
4556 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4560 if (memcmp(type,mng_tRNS,4) == 0)
4562 /* read global tRNS */
4565 for (i=0; i < (ssize_t) length; i++)
4566 mng_info->global_trns[i]=p[i];
4569 for ( ; i < 256; i++)
4570 mng_info->global_trns[i]=255;
4572 mng_info->global_trns_length=(unsigned int) length;
4573 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4576 if (memcmp(type,mng_gAMA,4) == 0)
4583 igamma=mng_get_long(p);
4584 mng_info->global_gamma=((float) igamma)*0.00001;
4585 mng_info->have_global_gama=MagickTrue;
4589 mng_info->have_global_gama=MagickFalse;
4591 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4595 if (memcmp(type,mng_cHRM,4) == 0)
4597 /* Read global cHRM */
4601 mng_info->global_chrm.white_point.x=0.00001*mng_get_long(p);
4602 mng_info->global_chrm.white_point.y=0.00001*mng_get_long(&p[4]);
4603 mng_info->global_chrm.red_primary.x=0.00001*mng_get_long(&p[8]);
4604 mng_info->global_chrm.red_primary.y=0.00001*
4605 mng_get_long(&p[12]);
4606 mng_info->global_chrm.green_primary.x=0.00001*
4607 mng_get_long(&p[16]);
4608 mng_info->global_chrm.green_primary.y=0.00001*
4609 mng_get_long(&p[20]);
4610 mng_info->global_chrm.blue_primary.x=0.00001*
4611 mng_get_long(&p[24]);
4612 mng_info->global_chrm.blue_primary.y=0.00001*
4613 mng_get_long(&p[28]);
4614 mng_info->have_global_chrm=MagickTrue;
4617 mng_info->have_global_chrm=MagickFalse;
4619 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4623 if (memcmp(type,mng_sRGB,4) == 0)
4630 mng_info->global_srgb_intent=
4631 Magick_RenderingIntent_from_PNG_RenderingIntent(p[0]);
4632 mng_info->have_global_srgb=MagickTrue;
4635 mng_info->have_global_srgb=MagickFalse;
4637 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4641 if (memcmp(type,mng_iCCP,4) == 0)
4649 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4654 if (memcmp(type,mng_FRAM,4) == 0)
4657 (void) ThrowMagickException(&image->exception,GetMagickModule(),
4658 CoderError,"FRAM chunk found in MNG-VLC datastream","`%s'",
4661 if ((mng_info->framing_mode == 2) || (mng_info->framing_mode == 4))
4662 image->delay=frame_delay;
4664 frame_delay=default_frame_delay;
4665 frame_timeout=default_frame_timeout;
4670 mng_info->framing_mode=p[0];
4672 if (logging != MagickFalse)
4673 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4674 " Framing_mode=%d",mng_info->framing_mode);
4678 /* Note the delay and frame clipping boundaries. */
4680 p++; /* framing mode */
4682 while (*p && ((p-chunk) < (ssize_t) length))
4683 p++; /* frame name */
4685 p++; /* frame name terminator */
4687 if ((p-chunk) < (ssize_t) (length-4))
4694 change_delay=(*p++);
4695 change_timeout=(*p++);
4696 change_clipping=(*p++);
4697 p++; /* change_sync */
4701 frame_delay=1UL*image->ticks_per_second*
4704 if (mng_info->ticks_per_second != 0)
4705 frame_delay/=mng_info->ticks_per_second;
4708 frame_delay=PNG_UINT_31_MAX;
4710 if (change_delay == 2)
4711 default_frame_delay=frame_delay;
4715 if (logging != MagickFalse)
4716 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4717 " Framing_delay=%.20g",(double) frame_delay);
4722 frame_timeout=1UL*image->ticks_per_second*
4725 if (mng_info->ticks_per_second != 0)
4726 frame_timeout/=mng_info->ticks_per_second;
4729 frame_timeout=PNG_UINT_31_MAX;
4731 if (change_delay == 2)
4732 default_frame_timeout=frame_timeout;
4736 if (logging != MagickFalse)
4737 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4738 " Framing_timeout=%.20g",(double) frame_timeout);
4741 if (change_clipping)
4743 fb=mng_read_box(previous_fb,(char) p[0],&p[1]);
4747 if (logging != MagickFalse)
4748 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4749 " Frame_clip: L=%.20g R=%.20g T=%.20g B=%.20g",
4750 (double) fb.left,(double) fb.right,(double) fb.top,
4751 (double) fb.bottom);
4753 if (change_clipping == 2)
4759 mng_info->clip=mng_minimum_box(fb,mng_info->frame);
4761 subframe_width=(size_t) (mng_info->clip.right
4762 -mng_info->clip.left);
4764 subframe_height=(size_t) (mng_info->clip.bottom
4765 -mng_info->clip.top);
4767 Insert a background layer behind the frame if framing_mode is 4.
4769 #if defined(MNG_INSERT_LAYERS)
4770 if (logging != MagickFalse)
4771 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4772 " subframe_width=%.20g, subframe_height=%.20g",(double)
4773 subframe_width,(double) subframe_height);
4775 if (insert_layers && (mng_info->framing_mode == 4) &&
4776 (subframe_width) && (subframe_height))
4778 /* Allocate next image structure. */
4779 if (GetAuthenticPixelQueue(image) != (PixelPacket *) NULL)
4781 AcquireNextImage(image_info,image);
4783 if (GetNextImageInList(image) == (Image *) NULL)
4785 image=DestroyImageList(image);
4786 MngInfoFreeStruct(mng_info,&have_mng_structure);
4787 return((Image *) NULL);
4790 image=SyncNextImageInList(image);
4793 mng_info->image=image;
4795 if (term_chunk_found)
4797 image->start_loop=MagickTrue;
4798 image->iterations=mng_iterations;
4799 term_chunk_found=MagickFalse;
4803 image->start_loop=MagickFalse;
4805 image->columns=subframe_width;
4806 image->rows=subframe_height;
4807 image->page.width=subframe_width;
4808 image->page.height=subframe_height;
4809 image->page.x=mng_info->clip.left;
4810 image->page.y=mng_info->clip.top;
4811 image->background_color=mng_background_color;
4812 image->matte=MagickFalse;
4814 (void) SetImageBackgroundColor(image);
4816 if (logging != MagickFalse)
4817 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4818 " Insert backgd layer, L=%.20g, R=%.20g T=%.20g, B=%.20g",
4819 (double) mng_info->clip.left,(double) mng_info->clip.right,
4820 (double) mng_info->clip.top,(double) mng_info->clip.bottom);
4823 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4826 if (memcmp(type,mng_CLIP,4) == 0)
4835 first_object=(p[0] << 8) | p[1];
4836 last_object=(p[2] << 8) | p[3];
4838 for (i=(int) first_object; i <= (int) last_object; i++)
4840 if (mng_info->exists[i] && !mng_info->frozen[i])
4845 box=mng_info->object_clip[i];
4846 mng_info->object_clip[i]=mng_read_box(box,(char) p[4],&p[5]);
4850 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4853 if (memcmp(type,mng_SAVE,4) == 0)
4855 for (i=1; i < MNG_MAX_OBJECTS; i++)
4856 if (mng_info->exists[i])
4858 mng_info->frozen[i]=MagickTrue;
4859 #ifdef MNG_OBJECT_BUFFERS
4860 if (mng_info->ob[i] != (MngBuffer *) NULL)
4861 mng_info->ob[i]->frozen=MagickTrue;
4866 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4871 if ((memcmp(type,mng_DISC,4) == 0) || (memcmp(type,mng_SEEK,4) == 0))
4873 /* Read DISC or SEEK. */
4875 if ((length == 0) || !memcmp(type,mng_SEEK,4))
4877 for (i=1; i < MNG_MAX_OBJECTS; i++)
4878 MngInfoDiscardObject(mng_info,i);
4886 for (j=0; j < (ssize_t) length; j+=2)
4888 i=p[j] << 8 | p[j+1];
4889 MngInfoDiscardObject(mng_info,i);
4894 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4899 if (memcmp(type,mng_MOVE,4) == 0)
4907 first_object=(p[0] << 8) | p[1];
4908 last_object=(p[2] << 8) | p[3];
4909 for (i=(ssize_t) first_object; i <= (ssize_t) last_object; i++)
4911 if (mng_info->exists[i] && !mng_info->frozen[i])
4919 old_pair.a=mng_info->x_off[i];
4920 old_pair.b=mng_info->y_off[i];
4921 new_pair=mng_read_pair(old_pair,(int) p[4],&p[5]);
4922 mng_info->x_off[i]=new_pair.a;
4923 mng_info->y_off[i]=new_pair.b;
4927 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4931 if (memcmp(type,mng_LOOP,4) == 0)
4933 ssize_t loop_iters=1;
4934 loop_level=chunk[0];
4935 mng_info->loop_active[loop_level]=1; /* mark loop active */
4937 /* Record starting point. */
4938 loop_iters=mng_get_long(&chunk[1]);
4940 if (logging != MagickFalse)
4941 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4942 " LOOP level %.20g has %.20g iterations ",(double) loop_level,
4943 (double) loop_iters);
4945 if (loop_iters == 0)
4946 skipping_loop=loop_level;
4950 mng_info->loop_jump[loop_level]=TellBlob(image);
4951 mng_info->loop_count[loop_level]=loop_iters;
4954 mng_info->loop_iteration[loop_level]=0;
4955 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4959 if (memcmp(type,mng_ENDL,4) == 0)
4961 loop_level=chunk[0];
4963 if (skipping_loop > 0)
4965 if (skipping_loop == loop_level)
4968 Found end of zero-iteration loop.
4971 mng_info->loop_active[loop_level]=0;
4977 if (mng_info->loop_active[loop_level] == 1)
4979 mng_info->loop_count[loop_level]--;
4980 mng_info->loop_iteration[loop_level]++;
4982 if (logging != MagickFalse)
4983 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4984 " ENDL: LOOP level %.20g has %.20g remaining iters ",
4985 (double) loop_level,(double)
4986 mng_info->loop_count[loop_level]);
4988 if (mng_info->loop_count[loop_level] != 0)
4990 offset=SeekBlob(image,mng_info->loop_jump[loop_level],
4994 ThrowReaderException(CorruptImageError,
4995 "ImproperImageHeader");
5006 mng_info->loop_active[loop_level]=0;
5008 for (i=0; i < loop_level; i++)
5009 if (mng_info->loop_active[i] == 1)
5010 last_level=(short) i;
5011 loop_level=last_level;
5016 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5020 if (memcmp(type,mng_CLON,4) == 0)
5022 if (mng_info->clon_warning == 0)
5023 (void) ThrowMagickException(&image->exception,GetMagickModule(),
5024 CoderError,"CLON is not implemented yet","`%s'",
5027 mng_info->clon_warning++;
5030 if (memcmp(type,mng_MAGN,4) == 0)
5045 magn_first=(p[0] << 8) | p[1];
5051 magn_last=(p[2] << 8) | p[3];
5054 magn_last=magn_first;
5055 #ifndef MNG_OBJECT_BUFFERS
5056 if (magn_first || magn_last)
5057 if (mng_info->magn_warning == 0)
5059 (void) ThrowMagickException(&image->exception,
5060 GetMagickModule(),CoderError,
5061 "MAGN is not implemented yet for nonzero objects",
5062 "`%s'",image->filename);
5064 mng_info->magn_warning++;
5074 magn_mx=(p[5] << 8) | p[6];
5083 magn_my=(p[7] << 8) | p[8];
5092 magn_ml=(p[9] << 8) | p[10];
5101 magn_mr=(p[11] << 8) | p[12];
5110 magn_mt=(p[13] << 8) | p[14];
5119 magn_mb=(p[15] << 8) | p[16];
5131 magn_methy=magn_methx;
5134 if (magn_methx > 5 || magn_methy > 5)
5135 if (mng_info->magn_warning == 0)
5137 (void) ThrowMagickException(&image->exception,
5138 GetMagickModule(),CoderError,
5139 "Unknown MAGN method in MNG datastream","`%s'",
5142 mng_info->magn_warning++;
5144 #ifdef MNG_OBJECT_BUFFERS
5145 /* Magnify existing objects in the range magn_first to magn_last */
5147 if (magn_first == 0 || magn_last == 0)
5149 /* Save the magnification factors for object 0 */
5150 mng_info->magn_mb=magn_mb;
5151 mng_info->magn_ml=magn_ml;
5152 mng_info->magn_mr=magn_mr;
5153 mng_info->magn_mt=magn_mt;
5154 mng_info->magn_mx=magn_mx;
5155 mng_info->magn_my=magn_my;
5156 mng_info->magn_methx=magn_methx;
5157 mng_info->magn_methy=magn_methy;
5161 if (memcmp(type,mng_PAST,4) == 0)
5163 if (mng_info->past_warning == 0)
5164 (void) ThrowMagickException(&image->exception,GetMagickModule(),
5165 CoderError,"PAST is not implemented yet","`%s'",
5168 mng_info->past_warning++;
5171 if (memcmp(type,mng_SHOW,4) == 0)
5173 if (mng_info->show_warning == 0)
5174 (void) ThrowMagickException(&image->exception,GetMagickModule(),
5175 CoderError,"SHOW is not implemented yet","`%s'",
5178 mng_info->show_warning++;
5181 if (memcmp(type,mng_sBIT,4) == 0)
5184 mng_info->have_global_sbit=MagickFalse;
5188 mng_info->global_sbit.gray=p[0];
5189 mng_info->global_sbit.red=p[0];
5190 mng_info->global_sbit.green=p[1];
5191 mng_info->global_sbit.blue=p[2];
5192 mng_info->global_sbit.alpha=p[3];
5193 mng_info->have_global_sbit=MagickTrue;
5196 if (memcmp(type,mng_pHYs,4) == 0)
5200 mng_info->global_x_pixels_per_unit=
5201 (size_t) mng_get_long(p);
5202 mng_info->global_y_pixels_per_unit=
5203 (size_t) mng_get_long(&p[4]);
5204 mng_info->global_phys_unit_type=p[8];
5205 mng_info->have_global_phys=MagickTrue;
5209 mng_info->have_global_phys=MagickFalse;
5211 if (memcmp(type,mng_pHYg,4) == 0)
5213 if (mng_info->phyg_warning == 0)
5214 (void) ThrowMagickException(&image->exception,GetMagickModule(),
5215 CoderError,"pHYg is not implemented.","`%s'",image->filename);
5217 mng_info->phyg_warning++;
5219 if (memcmp(type,mng_BASI,4) == 0)
5221 skip_to_iend=MagickTrue;
5223 if (mng_info->basi_warning == 0)
5224 (void) ThrowMagickException(&image->exception,GetMagickModule(),
5225 CoderError,"BASI is not implemented yet","`%s'",
5228 mng_info->basi_warning++;
5229 #ifdef MNG_BASI_SUPPORTED
5230 basi_width=(size_t) ((p[0] << 24) | (p[1] << 16) |
5231 (p[2] << 8) | p[3]);
5232 basi_height=(size_t) ((p[4] << 24) | (p[5] << 16) |
5233 (p[6] << 8) | p[7]);
5234 basi_color_type=p[8];
5235 basi_compression_method=p[9];
5236 basi_filter_type=p[10];
5237 basi_interlace_method=p[11];
5239 basi_red=(p[12] << 8) & p[13];
5245 basi_green=(p[14] << 8) & p[15];
5251 basi_blue=(p[16] << 8) & p[17];
5257 basi_alpha=(p[18] << 8) & p[19];
5261 if (basi_sample_depth == 16)
5268 basi_viewable=p[20];
5274 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5278 if (memcmp(type,mng_IHDR,4)
5279 #if defined(JNG_SUPPORTED)
5280 && memcmp(type,mng_JHDR,4)
5284 /* Not an IHDR or JHDR chunk */
5286 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5291 if (logging != MagickFalse)
5292 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5293 " Processing %c%c%c%c chunk",type[0],type[1],type[2],type[3]);
5295 mng_info->exists[object_id]=MagickTrue;
5296 mng_info->viewable[object_id]=MagickTrue;
5298 if (mng_info->invisible[object_id])
5300 if (logging != MagickFalse)
5301 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5302 " Skipping invisible object");
5304 skip_to_iend=MagickTrue;
5305 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5308 #if defined(MNG_INSERT_LAYERS)
5310 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
5312 image_width=(size_t) mng_get_long(p);
5313 image_height=(size_t) mng_get_long(&p[4]);
5315 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5318 Insert a transparent background layer behind the entire animation
5319 if it is not full screen.
5321 #if defined(MNG_INSERT_LAYERS)
5322 if (insert_layers && mng_type && first_mng_object)
5324 if ((mng_info->clip.left > 0) || (mng_info->clip.top > 0) ||
5325 (image_width < mng_info->mng_width) ||
5326 (mng_info->clip.right < (ssize_t) mng_info->mng_width) ||
5327 (image_height < mng_info->mng_height) ||
5328 (mng_info->clip.bottom < (ssize_t) mng_info->mng_height))
5330 if (GetAuthenticPixelQueue(image) != (PixelPacket *) NULL)
5333 Allocate next image structure.
5335 AcquireNextImage(image_info,image);
5337 if (GetNextImageInList(image) == (Image *) NULL)
5339 image=DestroyImageList(image);
5340 MngInfoFreeStruct(mng_info,&have_mng_structure);
5341 return((Image *) NULL);
5344 image=SyncNextImageInList(image);
5346 mng_info->image=image;
5348 if (term_chunk_found)
5350 image->start_loop=MagickTrue;
5351 image->iterations=mng_iterations;
5352 term_chunk_found=MagickFalse;
5356 image->start_loop=MagickFalse;
5358 /* Make a background rectangle. */
5361 image->columns=mng_info->mng_width;
5362 image->rows=mng_info->mng_height;
5363 image->page.width=mng_info->mng_width;
5364 image->page.height=mng_info->mng_height;
5367 image->background_color=mng_background_color;
5368 (void) SetImageBackgroundColor(image);
5369 if (logging != MagickFalse)
5370 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5371 " Inserted transparent background layer, W=%.20g, H=%.20g",
5372 (double) mng_info->mng_width,(double) mng_info->mng_height);
5376 Insert a background layer behind the upcoming image if
5377 framing_mode is 3, and we haven't already inserted one.
5379 if (insert_layers && (mng_info->framing_mode == 3) &&
5380 (subframe_width) && (subframe_height) && (simplicity == 0 ||
5381 (simplicity & 0x08)))
5383 if (GetAuthenticPixelQueue(image) != (PixelPacket *) NULL)
5386 Allocate next image structure.
5388 AcquireNextImage(image_info,image);
5390 if (GetNextImageInList(image) == (Image *) NULL)
5392 image=DestroyImageList(image);
5393 MngInfoFreeStruct(mng_info,&have_mng_structure);
5394 return((Image *) NULL);
5397 image=SyncNextImageInList(image);
5400 mng_info->image=image;
5402 if (term_chunk_found)
5404 image->start_loop=MagickTrue;
5405 image->iterations=mng_iterations;
5406 term_chunk_found=MagickFalse;
5410 image->start_loop=MagickFalse;
5413 image->columns=subframe_width;
5414 image->rows=subframe_height;
5415 image->page.width=subframe_width;
5416 image->page.height=subframe_height;
5417 image->page.x=mng_info->clip.left;
5418 image->page.y=mng_info->clip.top;
5419 image->background_color=mng_background_color;
5420 image->matte=MagickFalse;
5421 (void) SetImageBackgroundColor(image);
5423 if (logging != MagickFalse)
5424 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5425 " Insert background layer, L=%.20g, R=%.20g T=%.20g, B=%.20g",
5426 (double) mng_info->clip.left,(double) mng_info->clip.right,
5427 (double) mng_info->clip.top,(double) mng_info->clip.bottom);
5429 #endif /* MNG_INSERT_LAYERS */
5430 first_mng_object=MagickFalse;
5432 if (GetAuthenticPixelQueue(image) != (PixelPacket *) NULL)
5435 Allocate next image structure.
5437 AcquireNextImage(image_info,image);
5439 if (GetNextImageInList(image) == (Image *) NULL)
5441 image=DestroyImageList(image);
5442 MngInfoFreeStruct(mng_info,&have_mng_structure);
5443 return((Image *) NULL);
5446 image=SyncNextImageInList(image);
5448 mng_info->image=image;
5449 status=SetImageProgress(image,LoadImagesTag,TellBlob(image),
5450 GetBlobSize(image));
5452 if (status == MagickFalse)
5455 if (term_chunk_found)
5457 image->start_loop=MagickTrue;
5458 term_chunk_found=MagickFalse;
5462 image->start_loop=MagickFalse;
5464 if (mng_info->framing_mode == 1 || mng_info->framing_mode == 3)
5466 image->delay=frame_delay;
5467 frame_delay=default_frame_delay;
5473 image->page.width=mng_info->mng_width;
5474 image->page.height=mng_info->mng_height;
5475 image->page.x=mng_info->x_off[object_id];
5476 image->page.y=mng_info->y_off[object_id];
5477 image->iterations=mng_iterations;
5480 Seek back to the beginning of the IHDR or JHDR chunk's length field.
5483 if (logging != MagickFalse)
5484 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5485 " Seeking back to beginning of %c%c%c%c chunk",type[0],type[1],
5488 offset=SeekBlob(image,-((ssize_t) length+12),SEEK_CUR);
5491 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
5495 mng_info->image=image;
5496 mng_info->mng_type=mng_type;
5497 mng_info->object_id=object_id;
5499 if (memcmp(type,mng_IHDR,4) == 0)
5500 image=ReadOnePNGImage(mng_info,image_info,exception);
5502 #if defined(JNG_SUPPORTED)
5504 image=ReadOneJNGImage(mng_info,image_info,exception);
5507 if (image == (Image *) NULL)
5509 if (IsImageObject(previous) != MagickFalse)
5511 (void) DestroyImageList(previous);
5512 (void) CloseBlob(previous);
5515 MngInfoFreeStruct(mng_info,&have_mng_structure);
5516 return((Image *) NULL);
5519 if (image->columns == 0 || image->rows == 0)
5521 (void) CloseBlob(image);
5522 image=DestroyImageList(image);
5523 MngInfoFreeStruct(mng_info,&have_mng_structure);
5524 return((Image *) NULL);
5527 mng_info->image=image;
5534 if (mng_info->magn_methx || mng_info->magn_methy)
5540 if (logging != MagickFalse)
5541 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5542 " Processing MNG MAGN chunk");
5544 if (mng_info->magn_methx == 1)
5546 magnified_width=mng_info->magn_ml;
5548 if (image->columns > 1)
5549 magnified_width += mng_info->magn_mr;
5551 if (image->columns > 2)
5552 magnified_width += (png_uint_32)
5553 ((image->columns-2)*(mng_info->magn_mx));
5558 magnified_width=(png_uint_32) image->columns;
5560 if (image->columns > 1)
5561 magnified_width += mng_info->magn_ml-1;
5563 if (image->columns > 2)
5564 magnified_width += mng_info->magn_mr-1;
5566 if (image->columns > 3)
5567 magnified_width += (png_uint_32)
5568 ((image->columns-3)*(mng_info->magn_mx-1));
5571 if (mng_info->magn_methy == 1)
5573 magnified_height=mng_info->magn_mt;
5575 if (image->rows > 1)
5576 magnified_height += mng_info->magn_mb;
5578 if (image->rows > 2)
5579 magnified_height += (png_uint_32)
5580 ((image->rows-2)*(mng_info->magn_my));
5585 magnified_height=(png_uint_32) image->rows;
5587 if (image->rows > 1)
5588 magnified_height += mng_info->magn_mt-1;
5590 if (image->rows > 2)
5591 magnified_height += mng_info->magn_mb-1;
5593 if (image->rows > 3)
5594 magnified_height += (png_uint_32)
5595 ((image->rows-3)*(mng_info->magn_my-1));
5598 if (magnified_height > image->rows ||
5599 magnified_width > image->columns)
5614 register PixelPacket
5626 /* Allocate next image structure. */
5628 if (logging != MagickFalse)
5629 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5630 " Allocate magnified image");
5632 AcquireNextImage(image_info,image);
5634 if (GetNextImageInList(image) == (Image *) NULL)
5636 image=DestroyImageList(image);
5637 MngInfoFreeStruct(mng_info,&have_mng_structure);
5638 return((Image *) NULL);
5641 large_image=SyncNextImageInList(image);
5643 large_image->columns=magnified_width;
5644 large_image->rows=magnified_height;
5646 magn_methx=mng_info->magn_methx;
5647 magn_methy=mng_info->magn_methy;
5649 #if (MAGICKCORE_QUANTUM_DEPTH == 32)
5650 #define QM unsigned short
5651 if (magn_methx != 1 || magn_methy != 1)
5654 Scale pixels to unsigned shorts to prevent
5655 overflow of intermediate values of interpolations
5657 for (y=0; y < (ssize_t) image->rows; y++)
5659 q=GetAuthenticPixels(image,0,y,image->columns,1,
5662 for (x=(ssize_t) image->columns-1; x >= 0; x--)
5664 q->red=ScaleQuantumToShort(q->red);
5665 q->green=ScaleQuantumToShort(q->green);
5666 q->blue=ScaleQuantumToShort(q->blue);
5667 q->opacity=ScaleQuantumToShort(q->opacity);
5671 if (SyncAuthenticPixels(image,exception) == MagickFalse)
5679 if (image->matte != MagickFalse)
5680 (void) SetImageBackgroundColor(large_image);
5684 large_image->background_color.opacity=OpaqueOpacity;
5685 (void) SetImageBackgroundColor(large_image);
5687 if (magn_methx == 4)
5690 if (magn_methx == 5)
5693 if (magn_methy == 4)
5696 if (magn_methy == 5)
5700 /* magnify the rows into the right side of the large image */
5702 if (logging != MagickFalse)
5703 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5704 " Magnify the rows to %.20g",(double) large_image->rows);
5705 m=(ssize_t) mng_info->magn_mt;
5707 length=(size_t) image->columns;
5708 next=(PixelPacket *) AcquireQuantumMemory(length,sizeof(*next));
5709 prev=(PixelPacket *) AcquireQuantumMemory(length,sizeof(*prev));
5711 if ((prev == (PixelPacket *) NULL) ||
5712 (next == (PixelPacket *) NULL))
5714 image=DestroyImageList(image);
5715 MngInfoFreeStruct(mng_info,&have_mng_structure);
5716 ThrowReaderException(ResourceLimitError,
5717 "MemoryAllocationFailed");
5720 n=GetAuthenticPixels(image,0,0,image->columns,1,exception);
5721 (void) CopyMagickMemory(next,n,length);
5723 for (y=0; y < (ssize_t) image->rows; y++)
5726 m=(ssize_t) mng_info->magn_mt;
5728 else if (magn_methy > 1 && y == (ssize_t) image->rows-2)
5729 m=(ssize_t) mng_info->magn_mb;
5731 else if (magn_methy <= 1 && y == (ssize_t) image->rows-1)
5732 m=(ssize_t) mng_info->magn_mb;
5734 else if (magn_methy > 1 && y == (ssize_t) image->rows-1)
5738 m=(ssize_t) mng_info->magn_my;
5744 if (y < (ssize_t) image->rows-1)
5746 n=GetAuthenticPixels(image,0,y+1,image->columns,1,
5748 (void) CopyMagickMemory(next,n,length);
5751 for (i=0; i < m; i++, yy++)
5753 register PixelPacket
5756 assert(yy < (ssize_t) large_image->rows);
5759 q=GetAuthenticPixels(large_image,0,yy,large_image->columns,
5761 q+=(large_image->columns-image->columns);
5763 for (x=(ssize_t) image->columns-1; x >= 0; x--)
5765 /* TO DO: get color as function of indexes[x] */
5767 if (image->storage_class == PseudoClass)
5772 if (magn_methy <= 1)
5774 *q=(*pixels); /* replicate previous */
5777 else if (magn_methy == 2 || magn_methy == 4)
5785 (*q).red=(QM) (((ssize_t) (2*i*((*n).red
5786 -(*pixels).red)+m))/((ssize_t) (m*2))
5788 (*q).green=(QM) (((ssize_t) (2*i*((*n).green
5789 -(*pixels).green)+m))/((ssize_t) (m*2))
5791 (*q).blue=(QM) (((ssize_t) (2*i*((*n).blue
5792 -(*pixels).blue)+m))/((ssize_t) (m*2))
5795 if (image->matte != MagickFalse)
5796 (*q).opacity=(QM) (((ssize_t)
5798 -(*pixels).opacity)+m))
5799 /((ssize_t) (m*2))+(*pixels).opacity);
5802 if (magn_methy == 4)
5804 /* Replicate nearest */
5805 if (i <= ((m+1) << 1))
5806 (*q).opacity=(*pixels).opacity+0;
5808 (*q).opacity=(*n).opacity+0;
5812 else /* if (magn_methy == 3 || magn_methy == 5) */
5814 /* Replicate nearest */
5815 if (i <= ((m+1) << 1))
5821 if (magn_methy == 5)
5823 (*q).opacity=(QM) (((ssize_t) (2*i*((*n).opacity
5824 -(*pixels).opacity)+m))/((ssize_t) (m*2))
5825 +(*pixels).opacity);
5833 if (SyncAuthenticPixels(large_image,exception) == 0)
5839 prev=(PixelPacket *) RelinquishMagickMemory(prev);
5840 next=(PixelPacket *) RelinquishMagickMemory(next);
5842 length=image->columns;
5844 if (logging != MagickFalse)
5845 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5846 " Delete original image");
5848 DeleteImageFromList(&image);
5852 mng_info->image=image;
5854 /* magnify the columns */
5855 if (logging != MagickFalse)
5856 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5857 " Magnify the columns to %.20g",(double) image->columns);
5859 for (y=0; y < (ssize_t) image->rows; y++)
5861 register PixelPacket
5864 q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
5865 pixels=q+(image->columns-length);
5868 for (x=(ssize_t) (image->columns-length);
5869 x < (ssize_t) image->columns; x++)
5871 if (x == (ssize_t) (image->columns-length))
5872 m=(ssize_t) mng_info->magn_ml;
5874 else if (magn_methx > 1 && x == (ssize_t) image->columns-2)
5875 m=(ssize_t) mng_info->magn_mr;
5877 else if (magn_methx <= 1 && x == (ssize_t) image->columns-1)
5878 m=(ssize_t) mng_info->magn_mr;
5880 else if (magn_methx > 1 && x == (ssize_t) image->columns-1)
5884 m=(ssize_t) mng_info->magn_mx;
5886 for (i=0; i < m; i++)
5888 if (magn_methx <= 1)
5890 /* replicate previous */
5894 else if (magn_methx == 2 || magn_methx == 4)
5902 (*q).red=(QM) ((2*i*((*n).red
5904 /((ssize_t) (m*2))+(*pixels).red);
5905 (*q).green=(QM) ((2*i*((*n).green
5907 +m)/((ssize_t) (m*2))+(*pixels).green);
5908 (*q).blue=(QM) ((2*i*((*n).blue
5910 /((ssize_t) (m*2))+(*pixels).blue);
5911 if (image->matte != MagickFalse)
5912 (*q).opacity=(QM) ((2*i*((*n).opacity
5913 -(*pixels).opacity)+m)/((ssize_t) (m*2))
5914 +(*pixels).opacity);
5917 if (magn_methx == 4)
5919 /* Replicate nearest */
5920 if (i <= ((m+1) << 1))
5921 (*q).opacity=(*pixels).opacity+0;
5923 (*q).opacity=(*n).opacity+0;
5927 else /* if (magn_methx == 3 || magn_methx == 5) */
5929 /* Replicate nearest */
5930 if (i <= ((m+1) << 1))
5936 if (magn_methx == 5)
5939 (*q).opacity=(QM) ((2*i*((*n).opacity
5940 -(*pixels).opacity)+m) /((ssize_t) (m*2))
5941 +(*pixels).opacity);
5950 if (SyncAuthenticPixels(image,exception) == MagickFalse)
5953 #if (MAGICKCORE_QUANTUM_DEPTH == 32)
5954 if (magn_methx != 1 || magn_methy != 1)
5957 Rescale pixels to Quantum
5959 for (y=0; y < (ssize_t) image->rows; y++)
5961 q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
5963 for (x=(ssize_t) image->columns-1; x >= 0; x--)
5965 q->red=ScaleShortToQuantum(q->red);
5966 q->green=ScaleShortToQuantum(q->green);
5967 q->blue=ScaleShortToQuantum(q->blue);
5968 q->opacity=ScaleShortToQuantum(q->opacity);
5972 if (SyncAuthenticPixels(image,exception) == MagickFalse)
5977 if (logging != MagickFalse)
5978 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5979 " Finished MAGN processing");
5984 Crop_box is with respect to the upper left corner of the MNG.
5986 crop_box.left=mng_info->image_box.left+mng_info->x_off[object_id];
5987 crop_box.right=mng_info->image_box.right+mng_info->x_off[object_id];
5988 crop_box.top=mng_info->image_box.top+mng_info->y_off[object_id];
5989 crop_box.bottom=mng_info->image_box.bottom+mng_info->y_off[object_id];
5990 crop_box=mng_minimum_box(crop_box,mng_info->clip);
5991 crop_box=mng_minimum_box(crop_box,mng_info->frame);
5992 crop_box=mng_minimum_box(crop_box,mng_info->object_clip[object_id]);
5993 if ((crop_box.left != (mng_info->image_box.left
5994 +mng_info->x_off[object_id])) ||
5995 (crop_box.right != (mng_info->image_box.right
5996 +mng_info->x_off[object_id])) ||
5997 (crop_box.top != (mng_info->image_box.top
5998 +mng_info->y_off[object_id])) ||
5999 (crop_box.bottom != (mng_info->image_box.bottom
6000 +mng_info->y_off[object_id])))
6002 if (logging != MagickFalse)
6003 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6004 " Crop the PNG image");
6006 if ((crop_box.left < crop_box.right) &&
6007 (crop_box.top < crop_box.bottom))
6016 Crop_info is with respect to the upper left corner of
6019 crop_info.x=(crop_box.left-mng_info->x_off[object_id]);
6020 crop_info.y=(crop_box.top-mng_info->y_off[object_id]);
6021 crop_info.width=(size_t) (crop_box.right-crop_box.left);
6022 crop_info.height=(size_t) (crop_box.bottom-crop_box.top);
6023 image->page.width=image->columns;
6024 image->page.height=image->rows;
6027 im=CropImage(image,&crop_info,exception);
6029 if (im != (Image *) NULL)
6031 image->columns=im->columns;
6032 image->rows=im->rows;
6033 im=DestroyImage(im);
6034 image->page.width=image->columns;
6035 image->page.height=image->rows;
6036 image->page.x=crop_box.left;
6037 image->page.y=crop_box.top;
6044 No pixels in crop area. The MNG spec still requires
6045 a layer, though, so make a single transparent pixel in
6046 the top left corner.
6051 (void) SetImageBackgroundColor(image);
6052 image->page.width=1;
6053 image->page.height=1;
6058 #ifndef PNG_READ_EMPTY_PLTE_SUPPORTED
6059 image=mng_info->image;
6063 #if (MAGICKCORE_QUANTUM_DEPTH > 16)
6064 /* PNG does not handle depths greater than 16 so reduce it even
6067 if (image->depth > 16)
6071 #if (MAGICKCORE_QUANTUM_DEPTH >= 16)
6072 if (LosslessReduceDepthOK(image) != MagickFalse)
6076 GetImageException(image,exception);
6078 if (image_info->number_scenes != 0)
6080 if (mng_info->scenes_found >
6081 (ssize_t) (image_info->first_scene+image_info->number_scenes))
6085 if (logging != MagickFalse)
6086 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6087 " Finished reading image datastream.");
6089 } while (LocaleCompare(image_info->magick,"MNG") == 0);
6091 (void) CloseBlob(image);
6093 if (logging != MagickFalse)
6094 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6095 " Finished reading all image datastreams.");
6097 #if defined(MNG_INSERT_LAYERS)
6098 if (insert_layers && !mng_info->image_found && (mng_info->mng_width) &&
6099 (mng_info->mng_height))
6102 Insert a background layer if nothing else was found.
6104 if (logging != MagickFalse)
6105 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6106 " No images found. Inserting a background layer.");
6108 if (GetAuthenticPixelQueue(image) != (PixelPacket *) NULL)
6111 Allocate next image structure.
6113 AcquireNextImage(image_info,image);
6114 if (GetNextImageInList(image) == (Image *) NULL)
6116 image=DestroyImageList(image);
6117 MngInfoFreeStruct(mng_info,&have_mng_structure);
6119 if (logging != MagickFalse)
6120 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6121 " Allocation failed, returning NULL.");
6123 return((Image *) NULL);
6125 image=SyncNextImageInList(image);
6127 image->columns=mng_info->mng_width;
6128 image->rows=mng_info->mng_height;
6129 image->page.width=mng_info->mng_width;
6130 image->page.height=mng_info->mng_height;
6133 image->background_color=mng_background_color;
6134 image->matte=MagickFalse;
6136 if (image_info->ping == MagickFalse)
6137 (void) SetImageBackgroundColor(image);
6139 mng_info->image_found++;
6142 image->iterations=mng_iterations;
6144 if (mng_iterations == 1)
6145 image->start_loop=MagickTrue;
6147 while (GetPreviousImageInList(image) != (Image *) NULL)
6150 if (image_count > 10*mng_info->image_found)
6152 if (logging != MagickFalse)
6153 (void) LogMagickEvent(CoderEvent,GetMagickModule()," No beginning");
6155 (void) ThrowMagickException(&image->exception,GetMagickModule(),
6156 CoderError,"Linked list is corrupted, beginning of list not found",
6157 "`%s'",image_info->filename);
6159 return((Image *) NULL);
6162 image=GetPreviousImageInList(image);
6164 if (GetNextImageInList(image) == (Image *) NULL)
6166 if (logging != MagickFalse)
6167 (void) LogMagickEvent(CoderEvent,GetMagickModule()," Corrupt list");
6169 (void) ThrowMagickException(&image->exception,GetMagickModule(),
6170 CoderError,"Linked list is corrupted; next_image is NULL","`%s'",
6171 image_info->filename);
6175 if (mng_info->ticks_per_second && mng_info->image_found > 1 &&
6176 GetNextImageInList(image) ==
6179 if (logging != MagickFalse)
6180 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6181 " First image null");
6183 (void) ThrowMagickException(&image->exception,GetMagickModule(),
6184 CoderError,"image->next for first image is NULL but shouldn't be.",
6185 "`%s'",image_info->filename);
6188 if (mng_info->image_found == 0)
6190 if (logging != MagickFalse)
6191 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6192 " No visible images found.");
6194 (void) ThrowMagickException(&image->exception,GetMagickModule(),
6195 CoderError,"No visible images in file","`%s'",image_info->filename);
6197 if (image != (Image *) NULL)
6198 image=DestroyImageList(image);
6200 MngInfoFreeStruct(mng_info,&have_mng_structure);
6201 return((Image *) NULL);
6204 if (mng_info->ticks_per_second)
6205 final_delay=1UL*MagickMax(image->ticks_per_second,1L)*
6206 final_delay/mng_info->ticks_per_second;
6209 image->start_loop=MagickTrue;
6211 /* Find final nonzero image delay */
6212 final_image_delay=0;
6214 while (GetNextImageInList(image) != (Image *) NULL)
6217 final_image_delay=image->delay;
6219 image=GetNextImageInList(image);
6222 if (final_delay < final_image_delay)
6223 final_delay=final_image_delay;
6225 image->delay=final_delay;
6227 if (logging != MagickFalse)
6228 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6229 " image->delay=%.20g, final_delay=%.20g",(double) image->delay,
6230 (double) final_delay);
6232 if (logging != MagickFalse)
6238 image=GetFirstImageInList(image);
6240 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6241 " Before coalesce:");
6243 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6244 " scene 0 delay=%.20g",(double) image->delay);
6246 while (GetNextImageInList(image) != (Image *) NULL)
6248 image=GetNextImageInList(image);
6249 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6250 " scene %.20g delay=%.20g",(double) scene++,(double) image->delay);
6254 image=GetFirstImageInList(image);
6255 #ifdef MNG_COALESCE_LAYERS
6265 if (logging != MagickFalse)
6266 (void) LogMagickEvent(CoderEvent,GetMagickModule()," Coalesce Images");
6269 next_image=CoalesceImages(image,&image->exception);
6271 if (next_image == (Image *) NULL)
6272 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
6274 image=DestroyImageList(image);
6277 for (next=image; next != (Image *) NULL; next=next_image)
6279 next->page.width=mng_info->mng_width;
6280 next->page.height=mng_info->mng_height;
6283 next->scene=scene++;
6284 next_image=GetNextImageInList(next);
6286 if (next_image == (Image *) NULL)
6289 if (next->delay == 0)
6292 next_image->previous=GetPreviousImageInList(next);
6293 if (GetPreviousImageInList(next) == (Image *) NULL)
6296 next->previous->next=next_image;
6297 next=DestroyImage(next);
6303 while (GetNextImageInList(image) != (Image *) NULL)
6304 image=GetNextImageInList(image);
6306 image->dispose=BackgroundDispose;
6308 if (logging != MagickFalse)
6314 image=GetFirstImageInList(image);
6316 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6317 " After coalesce:");
6319 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6320 " scene 0 delay=%.20g dispose=%.20g",(double) image->delay,
6321 (double) image->dispose);
6323 while (GetNextImageInList(image) != (Image *) NULL)
6325 image=GetNextImageInList(image);
6327 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6328 " scene %.20g delay=%.20g dispose=%.20g",(double) scene++,
6329 (double) image->delay,(double) image->dispose);
6333 image=GetFirstImageInList(image);
6334 MngInfoFreeStruct(mng_info,&have_mng_structure);
6335 have_mng_structure=MagickFalse;
6337 if (logging != MagickFalse)
6338 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"exit ReadMNGImage()");
6340 return(GetFirstImageInList(image));
6342 #else /* PNG_LIBPNG_VER > 10011 */
6343 static Image *ReadPNGImage(const ImageInfo *image_info,ExceptionInfo *exception)
6345 printf("Your PNG library is too old: You have libpng-%s\n",
6346 PNG_LIBPNG_VER_STRING);
6348 (void) ThrowMagickException(exception,GetMagickModule(),CoderError,
6349 "PNG library is too old","`%s'",image_info->filename);
6351 return(Image *) NULL;
6354 static Image *ReadMNGImage(const ImageInfo *image_info,ExceptionInfo *exception)
6356 return(ReadPNGImage(image_info,exception));
6358 #endif /* PNG_LIBPNG_VER > 10011 */
6362 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6366 % R e g i s t e r P N G I m a g e %
6370 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6372 % RegisterPNGImage() adds properties for the PNG image format to
6373 % the list of supported formats. The properties include the image format
6374 % tag, a method to read and/or write the format, whether the format
6375 % supports the saving of more than one frame to the same file or blob,
6376 % whether the format supports native in-memory I/O, and a brief
6377 % description of the format.
6379 % The format of the RegisterPNGImage method is:
6381 % size_t RegisterPNGImage(void)
6384 ModuleExport size_t RegisterPNGImage(void)
6387 version[MaxTextExtent];
6395 "See http://www.libpng.org/ for details about the PNG format."
6400 "See http://www.libpng.org/pub/mng/ for details about the JNG\n"
6406 "See http://www.libpng.org/pub/mng/ for details about the MNG\n"
6412 #if defined(PNG_LIBPNG_VER_STRING)
6413 (void) ConcatenateMagickString(version,"libpng ",MaxTextExtent);
6414 (void) ConcatenateMagickString(version,PNG_LIBPNG_VER_STRING,MaxTextExtent);
6416 if (LocaleCompare(PNG_LIBPNG_VER_STRING,png_get_header_ver(NULL)) != 0)
6418 (void) ConcatenateMagickString(version,",",MaxTextExtent);
6419 (void) ConcatenateMagickString(version,png_get_libpng_ver(NULL),
6424 entry=SetMagickInfo("MNG");
6425 entry->seekable_stream=MagickTrue; /* To do: eliminate this. */
6427 #if defined(MAGICKCORE_PNG_DELEGATE)
6428 entry->decoder=(DecodeImageHandler *) ReadMNGImage;
6429 entry->encoder=(EncodeImageHandler *) WriteMNGImage;
6432 entry->magick=(IsImageFormatHandler *) IsMNG;
6433 entry->description=ConstantString("Multiple-image Network Graphics");
6435 if (*version != '\0')
6436 entry->version=ConstantString(version);
6438 entry->module=ConstantString("PNG");
6439 entry->note=ConstantString(MNGNote);
6440 (void) RegisterMagickInfo(entry);
6442 entry=SetMagickInfo("PNG");
6444 #if defined(MAGICKCORE_PNG_DELEGATE)
6445 entry->decoder=(DecodeImageHandler *) ReadPNGImage;
6446 entry->encoder=(EncodeImageHandler *) WritePNGImage;
6449 entry->magick=(IsImageFormatHandler *) IsPNG;
6450 entry->adjoin=MagickFalse;
6451 entry->description=ConstantString("Portable Network Graphics");
6452 entry->module=ConstantString("PNG");
6454 if (*version != '\0')
6455 entry->version=ConstantString(version);
6457 entry->note=ConstantString(PNGNote);
6458 (void) RegisterMagickInfo(entry);
6460 entry=SetMagickInfo("PNG8");
6462 #if defined(MAGICKCORE_PNG_DELEGATE)
6463 entry->decoder=(DecodeImageHandler *) ReadPNGImage;
6464 entry->encoder=(EncodeImageHandler *) WritePNGImage;
6467 entry->magick=(IsImageFormatHandler *) IsPNG;
6468 entry->adjoin=MagickFalse;
6469 entry->description=ConstantString(
6470 "8-bit indexed with optional binary transparency");
6471 entry->module=ConstantString("PNG");
6472 (void) RegisterMagickInfo(entry);
6474 entry=SetMagickInfo("PNG24");
6477 #if defined(ZLIB_VERSION)
6478 (void) ConcatenateMagickString(version,"zlib ",MaxTextExtent);
6479 (void) ConcatenateMagickString(version,ZLIB_VERSION,MaxTextExtent);
6481 if (LocaleCompare(ZLIB_VERSION,zlib_version) != 0)
6483 (void) ConcatenateMagickString(version,",",MaxTextExtent);
6484 (void) ConcatenateMagickString(version,zlib_version,MaxTextExtent);
6488 if (*version != '\0')
6489 entry->version=ConstantString(version);
6491 #if defined(MAGICKCORE_PNG_DELEGATE)
6492 entry->decoder=(DecodeImageHandler *) ReadPNGImage;
6493 entry->encoder=(EncodeImageHandler *) WritePNGImage;
6496 entry->magick=(IsImageFormatHandler *) IsPNG;
6497 entry->adjoin=MagickFalse;
6498 entry->description=ConstantString("opaque 24-bit RGB");
6499 entry->module=ConstantString("PNG");
6500 (void) RegisterMagickInfo(entry);
6502 entry=SetMagickInfo("PNG32");
6504 #if defined(MAGICKCORE_PNG_DELEGATE)
6505 entry->decoder=(DecodeImageHandler *) ReadPNGImage;
6506 entry->encoder=(EncodeImageHandler *) WritePNGImage;
6509 entry->magick=(IsImageFormatHandler *) IsPNG;
6510 entry->adjoin=MagickFalse;
6511 entry->description=ConstantString("opaque or transparent 32-bit RGBA");
6512 entry->module=ConstantString("PNG");
6513 (void) RegisterMagickInfo(entry);
6515 entry=SetMagickInfo("JNG");
6517 #if defined(JNG_SUPPORTED)
6518 #if defined(MAGICKCORE_PNG_DELEGATE)
6519 entry->decoder=(DecodeImageHandler *) ReadJNGImage;
6520 entry->encoder=(EncodeImageHandler *) WriteJNGImage;
6524 entry->magick=(IsImageFormatHandler *) IsJNG;
6525 entry->adjoin=MagickFalse;
6526 entry->description=ConstantString("JPEG Network Graphics");
6527 entry->module=ConstantString("PNG");
6528 entry->note=ConstantString(JNGNote);
6529 (void) RegisterMagickInfo(entry);
6531 #if defined(PNG_SETJMP_NOT_THREAD_SAFE)
6532 ping_semaphore=AllocateSemaphoreInfo();
6535 return(MagickImageCoderSignature);
6539 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6543 % U n r e g i s t e r P N G I m a g e %
6547 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6549 % UnregisterPNGImage() removes format registrations made by the
6550 % PNG module from the list of supported formats.
6552 % The format of the UnregisterPNGImage method is:
6554 % UnregisterPNGImage(void)
6557 ModuleExport void UnregisterPNGImage(void)
6559 (void) UnregisterMagickInfo("MNG");
6560 (void) UnregisterMagickInfo("PNG");
6561 (void) UnregisterMagickInfo("PNG8");
6562 (void) UnregisterMagickInfo("PNG24");
6563 (void) UnregisterMagickInfo("PNG32");
6564 (void) UnregisterMagickInfo("JNG");
6566 #if defined(PNG_SETJMP_NOT_THREAD_SAFE)
6567 if (ping_semaphore != (SemaphoreInfo *) NULL)
6568 DestroySemaphoreInfo(&ping_semaphore);
6572 #if defined(MAGICKCORE_PNG_DELEGATE)
6573 #if PNG_LIBPNG_VER > 10011
6575 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6579 % W r i t e M N G I m a g e %
6583 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6585 % WriteMNGImage() writes an image in the Portable Network Graphics
6586 % Group's "Multiple-image Network Graphics" encoded image format.
6588 % MNG support written by Glenn Randers-Pehrson, glennrp@image...
6590 % The format of the WriteMNGImage method is:
6592 % MagickBooleanType WriteMNGImage(const ImageInfo *image_info,Image *image)
6594 % A description of each parameter follows.
6596 % o image_info: the image info.
6598 % o image: The image.
6601 % To do (as of version 5.5.2, November 26, 2002 -- glennrp -- see also
6602 % "To do" under ReadPNGImage):
6604 % Preserve all unknown and not-yet-handled known chunks found in input
6605 % PNG file and copy them into output PNG files according to the PNG
6608 % Write the iCCP chunk at MNG level when (icc profile length > 0)
6610 % Improve selection of color type (use indexed-colour or indexed-colour
6611 % with tRNS when 256 or fewer unique RGBA values are present).
6613 % Figure out what to do with "dispose=<restore-to-previous>" (dispose == 3)
6614 % This will be complicated if we limit ourselves to generating MNG-LC
6615 % files. For now we ignore disposal method 3 and simply overlay the next
6618 % Check for identical PLTE's or PLTE/tRNS combinations and use a
6619 % global MNG PLTE or PLTE/tRNS combination when appropriate.
6620 % [mostly done 15 June 1999 but still need to take care of tRNS]
6622 % Check for identical sRGB and replace with a global sRGB (and remove
6623 % gAMA/cHRM if sRGB is found; check for identical gAMA/cHRM and
6624 % replace with global gAMA/cHRM (or with sRGB if appropriate; replace
6625 % local gAMA/cHRM with local sRGB if appropriate).
6627 % Check for identical sBIT chunks and write global ones.
6629 % Provide option to skip writing the signature tEXt chunks.
6631 % Use signatures to detect identical objects and reuse the first
6632 % instance of such objects instead of writing duplicate objects.
6634 % Use a smaller-than-32k value of compression window size when
6637 % Encode JNG datastreams. Mostly done as of 5.5.2; need to write
6638 % ancillary text chunks and save profiles.
6640 % Provide an option to force LC files (to ensure exact framing rate)
6643 % Provide an option to force VLC files instead of LC, even when offsets
6644 % are present. This will involve expanding the embedded images with a
6645 % transparent region at the top and/or left.
6649 Magick_png_write_raw_profile(const ImageInfo *image_info,png_struct *ping,
6650 png_info *ping_info, unsigned char *profile_type, unsigned char
6651 *profile_description, unsigned char *profile_data, png_uint_32 length)
6670 hex[16]={'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
6672 if (LocaleNCompare((char *) profile_type+1, "ng-chunk-",9) == 0)
6675 if (image_info->verbose)
6677 (void) printf("writing raw profile: type=%s, length=%.20g\n",
6678 (char *) profile_type, (double) length);
6681 text=(png_textp) png_malloc(ping,(png_uint_32) sizeof(png_text));
6682 description_length=(png_uint_32) strlen((const char *) profile_description);
6683 allocated_length=(png_uint_32) (length*2 + (length >> 5) + 20
6684 + description_length);
6685 text[0].text=(png_charp) png_malloc(ping,allocated_length);
6686 text[0].key=(png_charp) png_malloc(ping, (png_uint_32) 80);
6687 text[0].key[0]='\0';
6688 (void) ConcatenateMagickString(text[0].key,
6689 "Raw profile type ",MaxTextExtent);
6690 (void) ConcatenateMagickString(text[0].key,(const char *) profile_type,62);
6694 (void) CopyMagickString(dp,(const char *) profile_description,
6696 dp+=description_length;
6698 (void) FormatMagickString(dp,allocated_length-
6699 (png_size_t) (dp-text[0].text),"%8lu ",(unsigned long) length);
6702 for (i=0; i < (ssize_t) length; i++)
6706 *(dp++)=(char) hex[((*sp >> 4) & 0x0f)];
6707 *(dp++)=(char) hex[((*sp++ ) & 0x0f)];
6712 text[0].text_length=(png_size_t) (dp-text[0].text);
6713 text[0].compression=image_info->compression == NoCompression ||
6714 (image_info->compression == UndefinedCompression &&
6715 text[0].text_length < 128) ? -1 : 0;
6717 if (text[0].text_length <= allocated_length)
6718 png_set_text(ping,ping_info,text,1);
6720 png_free(ping,text[0].text);
6721 png_free(ping,text[0].key);
6722 png_free(ping,text);
6725 static MagickBooleanType Magick_png_write_chunk_from_profile(Image *image,
6726 const char *string, MagickBooleanType logging)
6739 ResetImageProfileIterator(image);
6741 for (name=GetNextImageProfile(image); name != (const char *) NULL; )
6743 profile=GetImageProfile(image,name);
6745 if (profile != (const StringInfo *) NULL)
6750 if (LocaleNCompare(name,string,11) == 0)
6752 if (logging != MagickFalse)
6753 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6754 " Found %s profile",name);
6756 ping_profile=CloneStringInfo(profile);
6757 data=GetStringInfoDatum(ping_profile),
6758 length=(png_uint_32) GetStringInfoLength(ping_profile);
6763 (void) WriteBlobMSBULong(image,length-5); /* data length */
6764 (void) WriteBlob(image,length-1,data+1);
6765 (void) WriteBlobMSBULong(image,crc32(0,data+1,(uInt) length-1));
6766 ping_profile=DestroyStringInfo(ping_profile);
6770 name=GetNextImageProfile(image);
6777 /* Write one PNG image */
6778 static MagickBooleanType WriteOnePNGImage(MngInfo *mng_info,
6779 const ImageInfo *IMimage_info,Image *IMimage)
6803 ping_trans_alpha[256];
6841 /* ping_exclude_iTXt, */
6848 ping_exclude_zCCP, /* hex-encoded iCCP */
6851 ping_need_colortype_warning,
6869 ping_interlace_method,
6870 ping_compression_method,
6886 number_semitransparent,
6888 ping_pHYs_unit_type;
6891 ping_pHYs_x_resolution,
6892 ping_pHYs_y_resolution;
6894 logging=LogMagickEvent(CoderEvent,GetMagickModule(),
6895 " enter WriteOnePNGImage()");
6897 image = CloneImage(IMimage,0,0,MagickFalse,&IMimage->exception);
6898 image_info=(ImageInfo *) CloneImageInfo(IMimage_info);
6900 if (mng_info->need_blob != MagickFalse)
6902 if (OpenBlob(image_info,image,WriteBinaryBlobMode,&image->exception) ==
6905 image_info=DestroyImageInfo(image_info);
6906 image=DestroyImage(image);
6907 return(MagickFalse);
6911 #if defined(PNG_SETJMP_NOT_THREAD_SAFE)
6912 LockSemaphoreInfo(ping_semaphore);
6915 /* Initialize some stuff */
6918 ping_interlace_method=0,
6919 ping_compression_method=0,
6920 ping_filter_method=0,
6923 ping_background.red = 0;
6924 ping_background.green = 0;
6925 ping_background.blue = 0;
6926 ping_background.gray = 0;
6927 ping_background.index = 0;
6929 ping_trans_color.red=0;
6930 ping_trans_color.green=0;
6931 ping_trans_color.blue=0;
6932 ping_trans_color.gray=0;
6934 ping_pHYs_unit_type = 0;
6935 ping_pHYs_x_resolution = 0;
6936 ping_pHYs_y_resolution = 0;
6938 ping_have_color=MagickTrue;
6939 ping_have_PLTE=MagickFalse;
6940 ping_have_bKGD=MagickFalse;
6941 ping_have_pHYs=MagickFalse;
6942 ping_have_tRNS=MagickFalse;
6944 ping_exclude_bKGD=mng_info->ping_exclude_bKGD;
6945 ping_exclude_cHRM=mng_info->ping_exclude_cHRM;
6946 ping_exclude_EXIF=mng_info->ping_exclude_EXIF; /* hex-encoded EXIF in zTXt */
6947 ping_exclude_gAMA=mng_info->ping_exclude_gAMA;
6948 ping_exclude_cHRM=mng_info->ping_exclude_cHRM;
6949 ping_exclude_iCCP=mng_info->ping_exclude_iCCP;
6950 /* ping_exclude_iTXt=mng_info->ping_exclude_iTXt; */
6951 ping_exclude_oFFs=mng_info->ping_exclude_oFFs;
6952 ping_exclude_pHYs=mng_info->ping_exclude_pHYs;
6953 ping_exclude_sRGB=mng_info->ping_exclude_sRGB;
6954 ping_exclude_tEXt=mng_info->ping_exclude_tEXt;
6955 ping_exclude_tRNS=mng_info->ping_exclude_tRNS;
6956 ping_exclude_vpAg=mng_info->ping_exclude_vpAg;
6957 ping_exclude_zCCP=mng_info->ping_exclude_zCCP; /* hex-encoded iCCP in zTXt */
6958 ping_exclude_zTXt=mng_info->ping_exclude_zTXt;
6960 ping_need_colortype_warning = MagickFalse;
6963 number_semitransparent = 0;
6964 number_transparent = 0;
6966 if (image->colorspace != RGBColorspace)
6967 (void) TransformImageColorspace(image,RGBColorspace);
6970 Sometimes we get PseudoClass images whose RGB values don't match
6971 the colors in the colormap. This code syncs the RGB values.
6973 if (image->depth <= 8 && image->taint && image->storage_class == PseudoClass)
6974 (void) SyncImage(image);
6976 #if (MAGICKCORE_QUANTUM_DEPTH == 8)
6977 if (image->depth > 8)
6979 if (logging != MagickFalse)
6980 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6981 " Reducing PNG bit depth to 8 since this is a Q8 build.");
6988 #if (MAGICKCORE_QUANTUM_DEPTH > 16)
6989 /* PNG does not handle depths greater than 16 so reduce it even
6992 if (image->depth > 16)
6996 #if (MAGICKCORE_QUANTUM_DEPTH >= 16)
6997 if (image->depth == 16 && mng_info->write_png_colortype != 16)
6998 if (mng_info->write_png8 || LosslessReduceDepthOK(image) != MagickFalse)
7002 #ifdef BUILD_PNG_PALETTE
7003 if (mng_info->write_png_colortype < 8 /* all */)
7006 * Sometimes we get DirectClass images that have 256 colors or fewer.
7007 * This code will build a colormap.
7009 * Also, sometimes we get PseudoClass images with an out-of-date
7010 * colormap. This code will replace the colormap with a new one.
7011 * Sometimes we get PseudoClass images that have more than 256 colors.
7012 * This code will delete the colormap and change the image to
7015 * If image->matte is MagickFalse, we ignore the opacity channel
7016 * even though it sometimes contains left-over non-opaque values.
7018 * Also we gather some information (number of opaque, transparent,
7019 * and semitransparent pixels, and whether the image has any non-gray
7020 * pixels) that we might need later. If the user wants to force
7021 * GrayAlpha or RGBA (colortype 4 or 6) we probably don't need any
7033 semitransparent[260],
7036 register IndexPacket
7039 register const PixelPacket
7042 if (logging != MagickFalse)
7043 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7044 " Enter BUILD_PALETTE:");
7046 if (logging != MagickFalse)
7048 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7049 " image->columns=%.20g",(double) image->columns);
7050 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7051 " image->rows=%.20g",(double) image->rows);
7052 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7053 " image->matte=%.20g",(double) image->matte);
7054 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7055 " image->depth=%.20g",(double) image->depth);
7057 if (image->colormap != NULL)
7059 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7060 " Original colormap:");
7061 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7062 " i (red,green,blue,opacity)");
7064 for (i=0; i < 256; i++)
7066 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7067 " %d (%d,%d,%d,%d)",
7069 (int) image->colormap[i].red,
7070 (int) image->colormap[i].green,
7071 (int) image->colormap[i].blue,
7072 (int) image->colormap[i].opacity);
7075 for (i=image->colors - 10; i < (ssize_t) image->colors; i++)
7079 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7080 " %d (%d,%d,%d,%d)",
7082 (int) image->colormap[i].red,
7083 (int) image->colormap[i].green,
7084 (int) image->colormap[i].blue,
7085 (int) image->colormap[i].opacity);
7090 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7091 " image->colors=%d",(int) image->colors);
7093 if (image->colors == 0)
7094 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7095 " (zero means unknown)");
7097 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7098 " Regenerate the colormap");
7101 exception=(&image->exception);
7103 ping_have_color=MagickFalse;
7106 for (y=0; y < (ssize_t) image->rows; y++)
7108 q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
7110 if (q == (PixelPacket *) NULL)
7113 for (x=0; x < (ssize_t) image->columns; x++)
7115 if (q->red != q->green || q->red != q->blue)
7116 ping_have_color=MagickTrue;
7118 if (image->matte == MagickFalse || q->opacity == OpaqueOpacity)
7120 if (number_opaque < 259)
7122 if (number_opaque == 0)
7125 opaque[0].opacity=OpaqueOpacity;
7129 for (i=0; i< (ssize_t) number_opaque; i++)
7131 if (IsColorEqual(opaque+i, (PixelPacket *) q))
7135 if (i == (ssize_t) number_opaque &&
7136 number_opaque < 259)
7140 opaque[i].opacity = OpaqueOpacity;
7144 else if (q->opacity == TransparentOpacity)
7146 if (number_transparent < 259)
7148 if (number_transparent == 0)
7151 ping_trans_color.red=(unsigned short)(q->red);
7152 ping_trans_color.green=(unsigned short) (q->green);
7153 ping_trans_color.blue=(unsigned short) (q->blue);
7154 ping_trans_color.gray=(unsigned short) (q->blue);
7155 number_transparent = 1;
7158 for (i=0; i< (ssize_t) number_transparent; i++)
7160 if (IsColorEqual(transparent+i, (PixelPacket *) q))
7164 if (i == (ssize_t) number_transparent &&
7165 number_transparent < 259)
7167 number_transparent++;
7168 transparent[i] = *q;
7174 if (number_semitransparent < 259)
7176 if (number_semitransparent == 0)
7178 semitransparent[0]=*q;
7179 number_semitransparent = 1;
7182 for (i=0; i< (ssize_t) number_semitransparent; i++)
7184 if (IsColorEqual(semitransparent+i,
7185 (PixelPacket *) q) &&
7186 q->opacity == semitransparent[i].opacity)
7190 if (i == (ssize_t) number_semitransparent &&
7191 number_semitransparent < 259)
7193 number_semitransparent++;
7194 semitransparent[i] = *q;
7202 image_colors=number_opaque+number_transparent+number_semitransparent;
7204 if (logging != MagickFalse)
7206 if (image_colors > 256)
7207 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7208 " image has more than 256 colors");
7211 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7212 " image has %d colors",image_colors);
7215 if (image_colors < 257)
7221 Initialize image colormap.
7224 if (logging != MagickFalse)
7225 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7226 " Sort the new colormap");
7228 /* Sort palette, transparent first */;
7232 for (i=0; i<number_transparent; i++)
7233 colormap[n++] = transparent[i];
7235 for (i=0; i<number_semitransparent; i++)
7236 colormap[n++] = semitransparent[i];
7238 for (i=0; i<number_opaque; i++)
7239 colormap[n++] = opaque[i];
7241 if (ping_exclude_bKGD == MagickFalse)
7243 /* Add the background color to the palette, if it
7244 * isn't already there.
7246 for (i=0; i<number_opaque; i++)
7248 if (IsColorEqual(opaque+i,
7249 &image->background_color))
7253 if (number_opaque < 257 && i == number_opaque)
7255 opaque[i]=image->background_color;
7256 opaque[i].opacity = OpaqueOpacity;
7261 if ((mng_info->ping_exclude_tRNS == MagickFalse ||
7262 (number_transparent == 0 && number_semitransparent == 0)) &&
7263 (((mng_info->write_png_colortype-1) ==
7264 PNG_COLOR_TYPE_PALETTE) ||
7265 (mng_info->write_png_colortype == 0)))
7267 if (logging != MagickFalse)
7269 if (n != (ssize_t) image_colors)
7270 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7271 " image_colors (%d) and n (%d) don't match",
7274 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7275 " AcquireImageColormap");
7278 image->colors = image_colors;
7280 if (AcquireImageColormap(image,image_colors) ==
7282 ThrowWriterException(ResourceLimitError,
7283 "MemoryAllocationFailed");
7285 for (i=0; i< (ssize_t) image_colors; i++)
7286 image->colormap[i] = colormap[i];
7288 if (logging != MagickFalse)
7290 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7291 " image->colors=%d (%d)",
7292 (int) image->colors, image_colors);
7294 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7295 " Update the pixel indexes");
7298 for (y=0; y < (ssize_t) image->rows; y++)
7300 q=GetAuthenticPixels(image,0,y,image->columns,1,
7303 if (q == (PixelPacket *) NULL)
7306 indexes=GetAuthenticIndexQueue(image);
7308 for (x=0; x < (ssize_t) image->columns; x++)
7310 for (i=0; i< (ssize_t) image_colors; i++)
7312 if ((image->matte == MagickFalse ||
7313 image->colormap[i].opacity == q->opacity) &&
7314 (IsColorEqual(&image->colormap[i],(PixelPacket *) q)))
7316 indexes[x]=(IndexPacket) i;
7323 if (SyncAuthenticPixels(image,exception) == MagickFalse)
7329 if (logging != MagickFalse)
7331 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7332 " image->colors=%d", (int) image->colors);
7334 if (image->colormap != NULL)
7336 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7337 " i (red,green,blue,opacity)");
7339 for (i=0; i < (ssize_t) image->colors; i++)
7341 if (i < 300 || i >= image->colors - 10)
7343 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7344 " %d (%d,%d,%d,%d)",
7346 (int) image->colormap[i].red,
7347 (int) image->colormap[i].green,
7348 (int) image->colormap[i].blue,
7349 (int) image->colormap[i].opacity);
7354 if (logging != MagickFalse)
7356 if (number_transparent < 257)
7357 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7358 " number_transparent = %d",
7359 number_transparent);
7362 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7363 " number_transparent > 256");
7365 if (number_opaque < 257)
7366 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7367 " number_opaque = %d",
7370 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7371 " number_opaque > 256");
7373 if (number_semitransparent < 257)
7374 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7375 " number_semitransparent = %d",
7376 number_semitransparent);
7379 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7380 " number_semitransparent > 256");
7383 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7384 " Exit BUILD_PALETTE:");
7387 #endif /* BUILD_PNG_PALETTE */
7389 if (mng_info->ping_exclude_tRNS != MagickFalse &&
7390 (number_transparent != 0 || number_semitransparent != 0))
7392 int colortype=mng_info->write_png_colortype;
7394 if (ping_have_color == MagickFalse)
7395 mng_info->write_png_colortype = 5;
7398 mng_info->write_png_colortype = 7;
7400 if (colortype != 0 && mng_info->write_png_colortype != (ssize_t) colortype)
7401 ping_need_colortype_warning=MagickTrue;
7405 image_depth=image->depth;
7407 quantum_info = (QuantumInfo *) NULL;
7409 image_colors=(int) image->colors;
7410 image_matte=image->matte;
7412 mng_info->IsPalette=image->storage_class == PseudoClass &&
7413 image_colors <= 256;
7416 Allocate the PNG structures
7418 #ifdef PNG_USER_MEM_SUPPORTED
7419 ping=png_create_write_struct_2(PNG_LIBPNG_VER_STRING,image,
7420 MagickPNGErrorHandler,MagickPNGWarningHandler,(void *) NULL,
7421 (png_malloc_ptr) Magick_png_malloc,(png_free_ptr) Magick_png_free);
7424 ping=png_create_write_struct(PNG_LIBPNG_VER_STRING,image,
7425 MagickPNGErrorHandler,MagickPNGWarningHandler);
7428 if (ping == (png_struct *) NULL)
7429 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
7431 ping_info=png_create_info_struct(ping);
7433 if (ping_info == (png_info *) NULL)
7435 png_destroy_write_struct(&ping,(png_info **) NULL);
7436 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
7439 png_set_write_fn(ping,image,png_put_data,png_flush_data);
7440 ping_pixels=(unsigned char *) NULL;
7442 if (setjmp(png_jmpbuf(ping)))
7448 if (image_info->verbose)
7449 (void) printf("PNG write has failed.\n");
7451 png_destroy_write_struct(&ping,&ping_info);
7452 #if defined(PNG_SETJMP_NOT_THREAD_SAFE)
7453 UnlockSemaphoreInfo(ping_semaphore);
7455 if (mng_info->need_blob != MagickFalse)
7456 (void) CloseBlob(image);
7457 image_info=DestroyImageInfo(image_info);
7458 image=DestroyImage(image);
7459 return(MagickFalse);
7462 Prepare PNG for writing.
7464 #if defined(PNG_MNG_FEATURES_SUPPORTED)
7465 if (mng_info->write_mng)
7466 (void) png_permit_mng_features(ping,PNG_ALL_MNG_FEATURES);
7469 # ifdef PNG_WRITE_EMPTY_PLTE_SUPPORTED
7470 if (mng_info->write_mng)
7471 png_permit_empty_plte(ping,MagickTrue);
7478 ping_width=(png_uint_32) image->columns;
7479 ping_height=(png_uint_32) image->rows;
7481 if (mng_info->write_png8 || mng_info->write_png24 || mng_info->write_png32)
7484 if (mng_info->write_png_depth != 0)
7485 image_depth=mng_info->write_png_depth;
7487 /* Adjust requested depth to next higher valid depth if necessary */
7488 if (image_depth > 8)
7491 if ((image_depth > 4) && (image_depth < 8))
7494 if (image_depth == 3)
7497 if (logging != MagickFalse)
7499 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7500 " width=%.20g",(double) ping_width);
7501 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7502 " height=%.20g",(double) ping_height);
7503 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7504 " image_matte=%.20g",(double) image->matte);
7505 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7506 " image->depth=%.20g",(double) image->depth);
7507 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7508 " Tentative ping_bit_depth=%.20g",(double) image_depth);
7511 save_image_depth=image_depth;
7512 ping_bit_depth=(png_byte) save_image_depth;
7515 #if defined(PNG_pHYs_SUPPORTED)
7516 if (ping_exclude_pHYs == MagickFalse)
7518 if ((image->x_resolution != 0) && (image->y_resolution != 0) &&
7519 (!mng_info->write_mng || !mng_info->equal_physs))
7521 if (logging != MagickFalse)
7522 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7523 " Setting up pHYs chunk");
7525 if (image->units == PixelsPerInchResolution)
7527 ping_pHYs_unit_type=PNG_RESOLUTION_METER;
7528 ping_pHYs_x_resolution=(png_uint_32) (100.0*image->x_resolution/2.54);
7529 ping_pHYs_y_resolution=(png_uint_32) (100.0*image->y_resolution/2.54);
7532 else if (image->units == PixelsPerCentimeterResolution)
7534 ping_pHYs_unit_type=PNG_RESOLUTION_METER;
7535 ping_pHYs_x_resolution=(png_uint_32) (100.0*image->x_resolution);
7536 ping_pHYs_y_resolution=(png_uint_32) (100.0*image->y_resolution);
7541 ping_pHYs_unit_type=PNG_RESOLUTION_UNKNOWN;
7542 ping_pHYs_x_resolution=(png_uint_32) image->x_resolution;
7543 ping_pHYs_y_resolution=(png_uint_32) image->y_resolution;
7546 ping_have_pHYs = MagickTrue;
7551 if (ping_exclude_bKGD == MagickFalse)
7553 if ((!mng_info->adjoin || !mng_info->equal_backgrounds))
7559 if (ping_bit_depth == 8)
7562 if (ping_bit_depth == 4)
7565 if (ping_bit_depth == 2)
7568 if (ping_bit_depth == 1)
7571 ping_background.red=(png_uint_16)
7572 (ScaleQuantumToShort(image->background_color.red) & mask);
7574 ping_background.green=(png_uint_16)
7575 (ScaleQuantumToShort(image->background_color.green) & mask);
7577 ping_background.blue=(png_uint_16)
7578 (ScaleQuantumToShort(image->background_color.blue) & mask);
7581 if (logging != MagickFalse)
7583 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7584 " Setting up bKGD chunk (1)");
7586 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7587 " ping_bit_depth=%d",ping_bit_depth);
7590 ping_have_bKGD = MagickTrue;
7594 Select the color type.
7599 if (mng_info->write_png8)
7602 /* TO DO: make this a function cause it's used twice, except
7603 for reducing the sample depth from 8. */
7605 number_colors=image_colors;
7607 ping_have_tRNS=MagickFalse;
7612 ping_color_type=(png_byte) PNG_COLOR_TYPE_PALETTE;
7614 if (logging != MagickFalse)
7615 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7616 " Setting up PLTE chunk with %d colors (%d)",
7617 number_colors, image_colors);
7619 for (i=0; i < (ssize_t) number_colors; i++)
7621 palette[i].red=ScaleQuantumToChar(image->colormap[i].red);
7622 palette[i].green=ScaleQuantumToChar(image->colormap[i].green);
7623 palette[i].blue=ScaleQuantumToChar(image->colormap[i].blue);
7624 if (logging != MagickFalse)
7625 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7626 #if MAGICKCORE_QUANTUM_DEPTH == 8
7627 " %3ld (%3d,%3d,%3d)",
7629 " %5ld (%5d,%5d,%5d)",
7631 (long) i,palette[i].red,palette[i].green,palette[i].blue);
7635 ping_have_PLTE=MagickTrue;
7636 image_depth=ping_bit_depth;
7639 if (matte != MagickFalse)
7642 Identify which colormap entry is transparent.
7644 assert(number_colors <= 256);
7645 assert(image->colormap != NULL);
7647 for (i=0; i < (ssize_t) number_transparent; i++)
7648 ping_trans_alpha[i]=0;
7650 /* PNG8 can't have semitransparent colors so we threshold them
7653 for (; i < (ssize_t) number_semitransparent; i++)
7654 ping_trans_alpha[i]=image->colormap[i].opacity >
7655 OpaqueOpacity/2 ? 0 : 255;
7657 ping_num_trans=(unsigned short) (number_transparent +
7658 number_semitransparent);
7660 if (ping_num_trans == 0)
7661 ping_have_tRNS=MagickFalse;
7664 ping_have_tRNS=MagickTrue;
7667 if (ping_exclude_bKGD == MagickFalse)
7670 * Identify which colormap entry is the background color.
7672 for (i=0; i < (ssize_t) MagickMax(1L*number_colors-1L,1L); i++)
7673 if (IsPNGColorEqual(ping_background,image->colormap[i]))
7676 ping_background.index=(png_byte) i;
7678 } /* end of write_png8 */
7680 else if (mng_info->write_png24)
7682 image_matte=MagickFalse;
7683 ping_color_type=(png_byte) PNG_COLOR_TYPE_RGB;
7686 else if (mng_info->write_png32)
7688 image_matte=MagickTrue;
7689 ping_color_type=(png_byte) PNG_COLOR_TYPE_RGB_ALPHA;
7692 else /* mng_info->write_pngNN not specified */
7694 image_depth=ping_bit_depth;
7696 if (mng_info->write_png_colortype != 0)
7698 ping_color_type=(png_byte) mng_info->write_png_colortype-1;
7700 if (ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA ||
7701 ping_color_type == PNG_COLOR_TYPE_RGB_ALPHA)
7702 image_matte=MagickTrue;
7705 image_matte=MagickFalse;
7708 else /* write_ping_colortype not specified */
7710 if (logging != MagickFalse)
7711 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7712 " Selecting PNG colortype:");
7714 ping_color_type=(png_byte) ((matte != MagickFalse)?
7715 PNG_COLOR_TYPE_RGB_ALPHA:PNG_COLOR_TYPE_RGB);
7717 if (image_info->type == TrueColorType)
7719 ping_color_type=(png_byte) PNG_COLOR_TYPE_RGB;
7720 image_matte=MagickFalse;
7723 if (image_info->type == TrueColorMatteType)
7725 ping_color_type=(png_byte) PNG_COLOR_TYPE_RGB_ALPHA;
7726 image_matte=MagickTrue;
7729 if (image_info->type == PaletteType ||
7730 image_info->type == PaletteMatteType)
7731 ping_color_type=(png_byte) PNG_COLOR_TYPE_PALETTE;
7733 if (image_info->type == UndefinedType ||
7734 image_info->type == OptimizeType)
7736 if (ping_have_color == MagickFalse)
7738 if (image_matte == MagickFalse)
7740 ping_color_type=(png_byte) PNG_COLOR_TYPE_GRAY;
7741 image_matte=MagickFalse;
7746 ping_color_type=(png_byte) PNG_COLOR_TYPE_GRAY_ALPHA;
7747 image_matte=MagickTrue;
7752 if (image_matte == MagickFalse)
7754 ping_color_type=(png_byte) PNG_COLOR_TYPE_RGB;
7755 image_matte=MagickFalse;
7760 ping_color_type=(png_byte) PNG_COLOR_TYPE_RGBA;
7761 image_matte=MagickTrue;
7768 if (logging != MagickFalse)
7769 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7770 " Selected PNG colortype=%d",ping_color_type);
7772 if (ping_bit_depth < 8)
7774 if (ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA ||
7775 ping_color_type == PNG_COLOR_TYPE_RGB ||
7776 ping_color_type == PNG_COLOR_TYPE_RGB_ALPHA)
7780 old_bit_depth=ping_bit_depth;
7782 if (ping_color_type == PNG_COLOR_TYPE_GRAY)
7784 if (image->matte == MagickFalse && image->colors < 256)
7786 if (ImageIsMonochrome(image))
7793 if (ping_color_type == PNG_COLOR_TYPE_PALETTE)
7798 if (image->colors == 0)
7801 (void) ThrowMagickException(&image->exception,
7802 GetMagickModule(),CoderError,
7803 "image has 0 colors", "`%s'","");
7806 while ((int) (one << ping_bit_depth) < (ssize_t) image_colors)
7807 ping_bit_depth <<= 1;
7810 if (logging != MagickFalse)
7812 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7813 " Number of colors: %.20g",(double) image_colors);
7815 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7816 " Tentative PNG bit depth: %d",ping_bit_depth);
7819 if (ping_bit_depth < (int) mng_info->write_png_depth)
7820 ping_bit_depth = mng_info->write_png_depth;
7823 image_depth=ping_bit_depth;
7825 if (logging != MagickFalse)
7827 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7828 " Tentative PNG color type: %.20g",(double) ping_color_type);
7830 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7831 " image_info->type: %.20g",(double) image_info->type);
7833 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7834 " image_depth: %.20g",(double) image_depth);
7836 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7838 " image->depth: %.20g",(double) image->depth);
7840 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7841 " ping_bit_depth: %.20g",(double) ping_bit_depth);
7844 if (matte != MagickFalse)
7846 if (mng_info->IsPalette)
7849 ping_color_type=PNG_COLOR_TYPE_GRAY_ALPHA;
7851 if (ping_have_color != MagickFalse)
7852 ping_color_type=PNG_COLOR_TYPE_RGBA;
7855 * Determine if there is any transparent color.
7857 if (number_transparent + number_semitransparent == 0)
7860 No transparent pixels are present. Change 4 or 6 to 0 or 2.
7863 image_matte=MagickFalse;
7864 ping_color_type&=0x03;
7874 if (ping_bit_depth == 8)
7877 if (ping_bit_depth == 4)
7880 if (ping_bit_depth == 2)
7883 if (ping_bit_depth == 1)
7886 ping_trans_color.red=(png_uint_16)
7887 (ScaleQuantumToShort(image->colormap[0].red) & mask);
7889 ping_trans_color.green=(png_uint_16)
7890 (ScaleQuantumToShort(image->colormap[0].green) & mask);
7892 ping_trans_color.blue=(png_uint_16)
7893 (ScaleQuantumToShort(image->colormap[0].blue) & mask);
7895 ping_trans_color.gray=(png_uint_16)
7896 (ScaleQuantumToShort(PixelIntensityToQuantum(
7897 image->colormap)) & mask);
7899 ping_trans_color.index=(png_byte) 0;
7901 ping_have_tRNS=MagickTrue;
7904 if (ping_have_tRNS != MagickFalse)
7907 Determine if there is one and only one transparent color
7908 and if so if it is fully transparent.
7910 if (logging != MagickFalse)
7911 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7912 " Is there a single fully transparent color?");
7914 if (number_transparent > 1 || number_semitransparent > 0)
7916 ping_have_tRNS = MagickFalse;
7917 if (logging != MagickFalse)
7918 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7923 if (logging != MagickFalse)
7924 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7925 " ... Yes: (%d,%d,%d), (gray: %d)",
7926 (int) ping_trans_color.red,
7927 (int) ping_trans_color.green,
7928 (int) ping_trans_color.blue,
7929 (int) ping_trans_color.gray);
7933 if (ping_have_tRNS != MagickFalse)
7935 ping_color_type &= 0x03; /* changes 4 or 6 to 0 or 2 */
7937 if (image_depth == 8)
7939 ping_trans_color.red&=0xff;
7940 ping_trans_color.green&=0xff;
7941 ping_trans_color.blue&=0xff;
7942 ping_trans_color.gray&=0xff;
7948 if (image_depth == 8)
7950 ping_trans_color.red&=0xff;
7951 ping_trans_color.green&=0xff;
7952 ping_trans_color.blue&=0xff;
7953 ping_trans_color.gray&=0xff;
7960 if (ping_have_tRNS != MagickFalse)
7961 image_matte=MagickFalse;
7963 if ((mng_info->IsPalette) &&
7964 mng_info->write_png_colortype-1 != PNG_COLOR_TYPE_PALETTE &&
7965 ImageIsGray(image) && (image_matte == MagickFalse || image_depth >= 8))
7969 if (image_matte != MagickFalse)
7970 ping_color_type=PNG_COLOR_TYPE_GRAY_ALPHA;
7974 ping_color_type=PNG_COLOR_TYPE_GRAY;
7976 if (save_image_depth == 16 && image_depth == 8)
7978 if (logging != MagickFalse)
7980 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7981 " Scaling ping_trans_color (0)");
7983 ping_trans_color.gray*=0x0101;
7987 if (image_depth > MAGICKCORE_QUANTUM_DEPTH)
7988 image_depth=MAGICKCORE_QUANTUM_DEPTH;
7990 if (image_colors == 0 || image_colors-1 > MaxColormapSize)
7991 image_colors=(int) (one << image_depth);
7993 if (image_depth > 8)
7999 if ((int) ping_color_type == PNG_COLOR_TYPE_PALETTE)
8001 if(!mng_info->write_png_depth)
8005 while ((int) (one << ping_bit_depth)
8006 < (ssize_t) image_colors)
8007 ping_bit_depth <<= 1;
8011 else if (ping_color_type ==
8012 PNG_COLOR_TYPE_GRAY && image_colors < 17 &&
8013 mng_info->IsPalette)
8016 /* Check if grayscale is reducible */
8018 depth_4_ok=MagickTrue,
8019 depth_2_ok=MagickTrue,
8020 depth_1_ok=MagickTrue;
8022 for (i=0; i < (ssize_t) image_colors; i++)
8027 intensity=ScaleQuantumToChar(image->colormap[i].red);
8029 if ((intensity & 0x0f) != ((intensity & 0xf0) >> 4))
8030 depth_4_ok=depth_2_ok=depth_1_ok=MagickFalse;
8032 else if ((intensity & 0x03) != ((intensity & 0x0c) >> 2))
8033 depth_2_ok=depth_1_ok=MagickFalse;
8035 else if ((intensity & 0x01) != ((intensity & 0x02) >> 1))
8036 depth_1_ok=MagickFalse;
8039 if (depth_1_ok && mng_info->write_png_depth <= 1)
8042 else if (depth_2_ok && mng_info->write_png_depth <= 2)
8045 else if (depth_4_ok && mng_info->write_png_depth <= 4)
8050 image_depth=ping_bit_depth;
8055 if (mng_info->IsPalette)
8057 number_colors=image_colors;
8059 if (image_depth <= 8)
8064 ping_color_type=(png_byte) PNG_COLOR_TYPE_PALETTE;
8066 if (mng_info->have_write_global_plte && matte == MagickFalse)
8068 png_set_PLTE(ping,ping_info,NULL,0);
8070 if (logging != MagickFalse)
8071 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8072 " Setting up empty PLTE chunk");
8077 for (i=0; i < (ssize_t) number_colors; i++)
8079 palette[i].red=ScaleQuantumToChar(image->colormap[i].red);
8080 palette[i].green=ScaleQuantumToChar(image->colormap[i].green);
8081 palette[i].blue=ScaleQuantumToChar(image->colormap[i].blue);
8084 if (logging != MagickFalse)
8085 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8086 " Setting up PLTE chunk with %d colors",
8089 ping_have_PLTE=MagickTrue;
8092 /* color_type is PNG_COLOR_TYPE_PALETTE */
8093 if (mng_info->write_png_depth == 0)
8101 while ((one << ping_bit_depth) < number_colors)
8102 ping_bit_depth <<= 1;
8107 if (matte != MagickFalse)
8110 * Set up trans_colors array.
8112 assert(number_colors <= 256);
8114 ping_num_trans=(unsigned short) (number_transparent +
8115 number_semitransparent);
8117 if (ping_num_trans == 0)
8118 ping_have_tRNS=MagickFalse;
8122 if (logging != MagickFalse)
8124 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8125 " Scaling ping_trans_color (1)");
8127 ping_have_tRNS=MagickTrue;
8129 for (i=0; i < ping_num_trans; i++)
8131 ping_trans_alpha[i]= (png_byte) (255-
8132 ScaleQuantumToChar(image->colormap[i].opacity));
8142 if (image_depth < 8)
8145 if ((save_image_depth == 16) && (image_depth == 8))
8147 if (logging != MagickFalse)
8149 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8150 " Scaling ping_trans_color from (%d,%d,%d)",
8151 (int) ping_trans_color.red,
8152 (int) ping_trans_color.green,
8153 (int) ping_trans_color.blue);
8156 ping_trans_color.red*=0x0101;
8157 ping_trans_color.green*=0x0101;
8158 ping_trans_color.blue*=0x0101;
8159 ping_trans_color.gray*=0x0101;
8161 if (logging != MagickFalse)
8163 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8165 (int) ping_trans_color.red,
8166 (int) ping_trans_color.green,
8167 (int) ping_trans_color.blue);
8172 if (ping_bit_depth < (ssize_t) mng_info->write_png_depth)
8173 ping_bit_depth = (ssize_t) mng_info->write_png_depth;
8176 Adjust background and transparency samples in sub-8-bit grayscale files.
8178 if (ping_bit_depth < 8 && ping_color_type ==
8179 PNG_COLOR_TYPE_GRAY)
8187 maxval=(png_uint_16) ((one << ping_bit_depth)-1);
8189 if (ping_exclude_bKGD == MagickFalse)
8192 ping_background.gray=(png_uint_16)
8193 (QuantumScale*(maxval*(PixelIntensity(&image->background_color))));
8195 if (logging != MagickFalse)
8196 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8197 " Setting up bKGD chunk (2)");
8199 ping_have_bKGD = MagickTrue;
8202 ping_trans_color.gray=(png_uint_16) (QuantumScale*(maxval*
8203 ping_trans_color.gray));
8206 if (ping_exclude_bKGD == MagickFalse)
8208 if ((int) ping_color_type == PNG_COLOR_TYPE_PALETTE)
8211 Identify which colormap entry is the background color.
8214 number_colors=image_colors;
8216 for (i=0; i < (ssize_t) MagickMax(1L*number_colors,1L); i++)
8217 if (IsPNGColorEqual(image->background_color,image->colormap[i]))
8220 ping_background.index=(png_byte) i;
8222 if (logging != MagickFalse)
8224 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8225 " Setting up bKGD chunk with index=%d",(int) i);
8228 if (i < (ssize_t) number_colors)
8230 ping_have_bKGD = MagickTrue;
8232 if (logging != MagickFalse)
8234 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8235 " background =(%d,%d,%d)",
8236 (int) ping_background.red,
8237 (int) ping_background.green,
8238 (int) ping_background.blue);
8242 else /* Can't happen */
8244 if (logging != MagickFalse)
8245 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8246 " No room in PLTE to add bKGD color");
8247 ping_have_bKGD = MagickFalse;
8252 if (logging != MagickFalse)
8253 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8254 " PNG color type: %d",ping_color_type);
8256 Initialize compression level and filtering.
8258 if (logging != MagickFalse)
8260 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8261 " Setting up deflate compression");
8263 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8264 " Compression buffer size: 32768");
8267 png_set_compression_buffer_size(ping,32768L);
8269 if (logging != MagickFalse)
8270 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8271 " Compression mem level: 9");
8273 png_set_compression_mem_level(ping, 9);
8275 quality=image->quality == UndefinedCompressionQuality ? 75UL :
8283 level=(int) MagickMin((ssize_t) quality/10,9);
8285 if (logging != MagickFalse)
8286 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8287 " Compression level: %d",level);
8289 png_set_compression_level(ping,level);
8294 if (logging != MagickFalse)
8295 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8296 " Compression strategy: Z_HUFFMAN_ONLY");
8298 png_set_compression_strategy(ping, Z_HUFFMAN_ONLY);
8301 if (logging != MagickFalse)
8302 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8303 " Setting up filtering");
8305 #if defined(PNG_MNG_FEATURES_SUPPORTED) && defined(PNG_INTRAPIXEL_DIFFERENCING)
8306 /* This became available in libpng-1.0.9. Output must be a MNG. */
8307 if (mng_info->write_mng && ((quality % 10) == 7))
8309 if (logging != MagickFalse)
8310 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8311 " Filter_type: PNG_INTRAPIXEL_DIFFERENCING");
8313 ping_filter_method=PNG_INTRAPIXEL_DIFFERENCING;
8317 if (logging != MagickFalse)
8318 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8326 if ((quality % 10) > 5)
8327 base_filter=PNG_ALL_FILTERS;
8330 if ((quality % 10) != 5)
8331 base_filter=(int) quality % 10;
8334 if (((int) ping_color_type == PNG_COLOR_TYPE_GRAY) ||
8335 ((int) ping_color_type == PNG_COLOR_TYPE_PALETTE) ||
8337 base_filter=PNG_NO_FILTERS;
8340 base_filter=PNG_ALL_FILTERS;
8342 if (logging != MagickFalse)
8344 if (base_filter == PNG_ALL_FILTERS)
8345 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8346 " Base filter method: ADAPTIVE");
8348 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8349 " Base filter method: NONE");
8352 png_set_filter(ping,PNG_FILTER_TYPE_BASE,base_filter);
8355 if (ping_exclude_iCCP == MagickFalse || ping_exclude_zCCP == MagickFalse)
8357 ResetImageProfileIterator(image);
8358 for (name=GetNextImageProfile(image); name != (const char *) NULL; )
8360 profile=GetImageProfile(image,name);
8362 if (profile != (StringInfo *) NULL)
8364 #ifdef PNG_WRITE_iCCP_SUPPORTED
8365 if ((LocaleCompare(name,"ICC") == 0) ||
8366 (LocaleCompare(name,"ICM") == 0))
8369 if (ping_exclude_iCCP == MagickFalse)
8371 png_set_iCCP(ping,ping_info,(const png_charp) name,0,
8372 #if (PNG_LIBPNG_VER < 10500)
8373 (png_charp) GetStringInfoDatum(profile),
8375 (png_const_bytep) GetStringInfoDatum(profile),
8377 (png_uint_32) GetStringInfoLength(profile));
8383 if (ping_exclude_zCCP == MagickFalse)
8385 Magick_png_write_raw_profile(image_info,ping,ping_info,
8386 (unsigned char *) name,(unsigned char *) name,
8387 GetStringInfoDatum(profile),
8388 (png_uint_32) GetStringInfoLength(profile));
8392 if (logging != MagickFalse)
8393 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8394 " Setting up text chunk with %s profile",name);
8396 name=GetNextImageProfile(image);
8400 #if defined(PNG_WRITE_sRGB_SUPPORTED)
8401 if ((mng_info->have_write_global_srgb == 0) &&
8402 ((image->rendering_intent != UndefinedIntent) ||
8403 (image->colorspace == sRGBColorspace)))
8405 if (ping_exclude_sRGB == MagickFalse)
8408 Note image rendering intent.
8410 if (logging != MagickFalse)
8411 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8412 " Setting up sRGB chunk");
8414 (void) png_set_sRGB(ping,ping_info,(
8415 Magick_RenderingIntent_to_PNG_RenderingIntent(
8416 image->rendering_intent)));
8418 if (ping_exclude_gAMA == MagickFalse)
8419 png_set_gAMA(ping,ping_info,0.45455);
8423 if ((!mng_info->write_mng) || (!png_get_valid(ping,ping_info,PNG_INFO_sRGB)))
8426 if (ping_exclude_gAMA == MagickFalse &&
8427 (ping_exclude_sRGB == MagickFalse ||
8428 (image->gamma < .45 || image->gamma > .46)))
8430 if ((mng_info->have_write_global_gama == 0) && (image->gamma != 0.0))
8434 To do: check for cHRM+gAMA == sRGB, and write sRGB instead.
8436 if (logging != MagickFalse)
8437 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8438 " Setting up gAMA chunk");
8440 png_set_gAMA(ping,ping_info,image->gamma);
8444 if (ping_exclude_cHRM == MagickFalse)
8446 if ((mng_info->have_write_global_chrm == 0) &&
8447 (image->chromaticity.red_primary.x != 0.0))
8450 Note image chromaticity.
8451 To do: check for cHRM+gAMA == sRGB, and write sRGB instead.
8459 wp=image->chromaticity.white_point;
8460 rp=image->chromaticity.red_primary;
8461 gp=image->chromaticity.green_primary;
8462 bp=image->chromaticity.blue_primary;
8464 if (logging != MagickFalse)
8465 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8466 " Setting up cHRM chunk");
8468 png_set_cHRM(ping,ping_info,wp.x,wp.y,rp.x,rp.y,gp.x,gp.y,
8474 ping_interlace_method=image_info->interlace != NoInterlace;
8476 if (mng_info->write_mng)
8477 png_set_sig_bytes(ping,8);
8479 /* Bail out if cannot meet defined PNG:bit-depth or PNG:color-type */
8481 if (mng_info->write_png_colortype != 0)
8483 if (mng_info->write_png_colortype-1 == PNG_COLOR_TYPE_GRAY)
8484 if (ImageIsGray(image) == MagickFalse)
8486 ping_color_type = PNG_COLOR_TYPE_RGB;
8488 if (ping_bit_depth < 8)
8492 if (mng_info->write_png_colortype-1 == PNG_COLOR_TYPE_GRAY_ALPHA)
8493 if (ImageIsGray(image) == MagickFalse)
8494 ping_color_type = PNG_COLOR_TYPE_RGB_ALPHA;
8497 if (ping_need_colortype_warning != MagickFalse ||
8498 ((mng_info->write_png_depth &&
8499 (int) mng_info->write_png_depth != ping_bit_depth) ||
8500 (mng_info->write_png_colortype &&
8501 ((int) mng_info->write_png_colortype-1 != ping_color_type &&
8502 mng_info->write_png_colortype != 7 &&
8503 !(mng_info->write_png_colortype == 5 && ping_color_type == 0)))))
8505 if (logging != MagickFalse)
8507 if (ping_need_colortype_warning != MagickFalse)
8509 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8510 " Image has transparency but tRNS chunk was excluded");
8513 if (mng_info->write_png_depth)
8515 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8516 " Defined PNG:bit-depth=%u, Computed depth=%u",
8517 mng_info->write_png_depth,
8521 if (mng_info->write_png_colortype)
8523 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8524 " Defined PNG:color-type=%u, Computed color type=%u",
8525 mng_info->write_png_colortype-1,
8531 "Cannot write image with defined PNG:bit-depth or PNG:color-type.");
8534 if (image_matte != MagickFalse && image->matte == MagickFalse)
8536 /* Add an opaque matte channel */
8537 image->matte = MagickTrue;
8538 (void) SetImageOpacity(image,0);
8540 if (logging != MagickFalse)
8541 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8542 " Added an opaque matte channel");
8545 if (number_transparent != 0 || number_semitransparent != 0)
8547 if (ping_color_type < 4)
8549 ping_have_tRNS=MagickTrue;
8550 if (logging != MagickFalse)
8551 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8552 " Setting ping_have_tRNS=MagickTrue.");
8556 if (logging != MagickFalse)
8557 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8558 " Writing PNG header chunks");
8560 png_set_IHDR(ping,ping_info,ping_width,ping_height,
8561 ping_bit_depth,ping_color_type,
8562 ping_interlace_method,ping_compression_method,
8563 ping_filter_method);
8565 if (ping_color_type == 3 && ping_have_PLTE != MagickFalse)
8567 png_set_PLTE(ping,ping_info,palette,number_colors);
8569 if (logging != MagickFalse)
8571 for (i=0; i< (ssize_t) number_colors; i++)
8573 if (i < ping_num_trans)
8574 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8575 " PLTE[%d] = (%d,%d,%d), tRNS[%d] = (%d)",
8577 (int) palette[i].red,
8578 (int) palette[i].green,
8579 (int) palette[i].blue,
8581 (int) ping_trans_alpha[i]);
8583 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8584 " PLTE[%d] = (%d,%d,%d)",
8586 (int) palette[i].red,
8587 (int) palette[i].green,
8588 (int) palette[i].blue);
8593 if (ping_exclude_bKGD == MagickFalse)
8595 if (ping_have_bKGD != MagickFalse)
8596 png_set_bKGD(ping,ping_info,&ping_background);
8599 if (ping_exclude_pHYs == MagickFalse)
8601 if (ping_have_pHYs != MagickFalse)
8603 png_set_pHYs(ping,ping_info,
8604 ping_pHYs_x_resolution,
8605 ping_pHYs_y_resolution,
8606 ping_pHYs_unit_type);
8610 #if defined(PNG_oFFs_SUPPORTED)
8611 if (ping_exclude_oFFs == MagickFalse)
8613 if (image->page.x || image->page.y)
8615 png_set_oFFs(ping,ping_info,(png_int_32) image->page.x,
8616 (png_int_32) image->page.y, 0);
8618 if (logging != MagickFalse)
8619 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8620 " Setting up oFFs chunk with x=%d, y=%d, units=0",
8621 (int) image->page.x, (int) image->page.y);
8626 png_write_info_before_PLTE(ping, ping_info);
8628 if (ping_have_tRNS != MagickFalse && ping_color_type < 4)
8630 if (logging != MagickFalse)
8632 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8633 " Calling png_set_tRNS with num_trans=%d",ping_num_trans);
8636 if (ping_color_type == 3)
8637 (void) png_set_tRNS(ping, ping_info,
8644 (void) png_set_tRNS(ping, ping_info,
8649 if (logging != MagickFalse)
8651 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8652 " tRNS color =(%d,%d,%d)",
8653 (int) ping_trans_color.red,
8654 (int) ping_trans_color.green,
8655 (int) ping_trans_color.blue);
8660 /* write any png-chunk-b profiles */
8661 (void) Magick_png_write_chunk_from_profile(image,"PNG-chunk-b",logging);
8662 png_write_info(ping,ping_info);
8664 /* write any PNG-chunk-m profiles */
8665 (void) Magick_png_write_chunk_from_profile(image,"PNG-chunk-m",logging);
8667 if (ping_exclude_vpAg == MagickFalse)
8669 if ((image->page.width != 0 && image->page.width != image->columns) ||
8670 (image->page.height != 0 && image->page.height != image->rows))
8675 (void) WriteBlobMSBULong(image,9L); /* data length=8 */
8676 PNGType(chunk,mng_vpAg);
8677 LogPNGChunk(logging,mng_vpAg,9L);
8678 PNGLong(chunk+4,(png_uint_32) image->page.width);
8679 PNGLong(chunk+8,(png_uint_32) image->page.height);
8680 chunk[12]=0; /* unit = pixels */
8681 (void) WriteBlob(image,13,chunk);
8682 (void) WriteBlobMSBULong(image,crc32(0,chunk,13));
8686 #if (PNG_LIBPNG_VER == 10206)
8687 /* avoid libpng-1.2.6 bug by setting PNG_HAVE_IDAT flag */
8688 #define PNG_HAVE_IDAT 0x04
8689 ping->mode |= PNG_HAVE_IDAT;
8690 #undef PNG_HAVE_IDAT
8693 png_set_packing(ping);
8697 rowbytes=image->columns;
8698 if (image_depth > 8)
8700 switch (ping_color_type)
8702 case PNG_COLOR_TYPE_RGB:
8706 case PNG_COLOR_TYPE_GRAY_ALPHA:
8710 case PNG_COLOR_TYPE_RGBA:
8718 if (logging != MagickFalse)
8720 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8721 " Writing PNG image data");
8723 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8724 " Allocating %.20g bytes of memory for pixels",(double) rowbytes);
8726 ping_pixels=(unsigned char *) AcquireQuantumMemory(rowbytes,
8727 sizeof(*ping_pixels));
8729 if (ping_pixels == (unsigned char *) NULL)
8730 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
8733 Initialize image scanlines.
8735 if (setjmp(png_jmpbuf(ping)))
8741 if (image_info->verbose)
8742 (void) printf("PNG write has failed.\n");
8744 png_destroy_write_struct(&ping,&ping_info);
8745 if (quantum_info != (QuantumInfo *) NULL)
8746 quantum_info=DestroyQuantumInfo(quantum_info);
8747 if (ping_pixels != (unsigned char *) NULL)
8748 ping_pixels=(unsigned char *) RelinquishMagickMemory(ping_pixels);
8749 #if defined(PNG_SETJMP_NOT_THREAD_SAFE)
8750 UnlockSemaphoreInfo(ping_semaphore);
8752 if (mng_info->need_blob != MagickFalse)
8753 (void) CloseBlob(image);
8754 image_info=DestroyImageInfo(image_info);
8755 image=DestroyImage(image);
8756 return(MagickFalse);
8758 quantum_info=AcquireQuantumInfo(image_info,image);
8759 if (quantum_info == (QuantumInfo *) NULL)
8760 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
8761 quantum_info->format=UndefinedQuantumFormat;
8762 quantum_info->depth=image_depth;
8763 num_passes=png_set_interlace_handling(ping);
8765 if ((!mng_info->write_png8 && !mng_info->write_png24 &&
8766 !mng_info->write_png32) &&
8767 (mng_info->IsPalette ||
8768 (image_info->type == BilevelType)) &&
8769 image_matte == MagickFalse && ImageIsMonochrome(image))
8771 /* Palette, Bilevel, or Opaque Monochrome */
8772 register const PixelPacket
8775 quantum_info->depth=8;
8776 for (pass=0; pass < num_passes; pass++)
8779 Convert PseudoClass image to a PNG monochrome image.
8781 for (y=0; y < (ssize_t) image->rows; y++)
8784 if (logging != MagickFalse)
8785 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8786 " Writing row of pixels (0)");
8788 p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception);
8790 if (p == (const PixelPacket *) NULL)
8793 if (mng_info->IsPalette)
8795 (void) ExportQuantumPixels(image,(const CacheView *) NULL,
8796 quantum_info,GrayQuantum,ping_pixels,&image->exception);
8797 if (mng_info->write_png_colortype-1 == PNG_COLOR_TYPE_PALETTE &&
8798 mng_info->write_png_depth &&
8799 mng_info->write_png_depth != old_bit_depth)
8801 /* Undo pixel scaling */
8802 for (i=0; i < (ssize_t) image->columns; i++)
8803 *(ping_pixels+i)=(unsigned char) (*(ping_pixels+i)
8804 >> (8-old_bit_depth));
8810 (void) ExportQuantumPixels(image,(const CacheView *) NULL,
8811 quantum_info,RedQuantum,ping_pixels,&image->exception);
8814 if (mng_info->write_png_colortype-1 != PNG_COLOR_TYPE_PALETTE)
8815 for (i=0; i < (ssize_t) image->columns; i++)
8816 *(ping_pixels+i)=(unsigned char) ((*(ping_pixels+i) > 127) ?
8819 if (logging != MagickFalse && y == 0)
8820 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8821 " Writing row of pixels (1)");
8823 png_write_row(ping,ping_pixels);
8825 if (image->previous == (Image *) NULL)
8827 status=SetImageProgress(image,LoadImageTag,pass,num_passes);
8828 if (status == MagickFalse)
8834 else /* Not Palette, Bilevel, or Opaque Monochrome */
8836 if ((!mng_info->write_png8 && !mng_info->write_png24 &&
8837 !mng_info->write_png32) &&
8838 (image_matte != MagickFalse ||
8839 (ping_bit_depth >= MAGICKCORE_QUANTUM_DEPTH)) &&
8840 (mng_info->IsPalette) && ImageIsGray(image))
8842 register const PixelPacket
8845 for (pass=0; pass < num_passes; pass++)
8848 for (y=0; y < (ssize_t) image->rows; y++)
8850 p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception);
8852 if (p == (const PixelPacket *) NULL)
8855 if (ping_color_type == PNG_COLOR_TYPE_GRAY)
8857 if (mng_info->IsPalette)
8858 (void) ExportQuantumPixels(image,(const CacheView *) NULL,
8859 quantum_info,GrayQuantum,ping_pixels,&image->exception);
8862 (void) ExportQuantumPixels(image,(const CacheView *) NULL,
8863 quantum_info,RedQuantum,ping_pixels,&image->exception);
8865 if (logging != MagickFalse && y == 0)
8866 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8867 " Writing GRAY PNG pixels (2)");
8870 else /* PNG_COLOR_TYPE_GRAY_ALPHA */
8872 if (logging != MagickFalse && y == 0)
8873 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8874 " Writing GRAY_ALPHA PNG pixels (2)");
8876 (void) ExportQuantumPixels(image,(const CacheView *) NULL,
8877 quantum_info,GrayAlphaQuantum,ping_pixels,&image->exception);
8880 if (logging != MagickFalse && y == 0)
8881 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8882 " Writing row of pixels (2)");
8884 png_write_row(ping,ping_pixels);
8887 if (image->previous == (Image *) NULL)
8889 status=SetImageProgress(image,LoadImageTag,pass,num_passes);
8890 if (status == MagickFalse)
8898 register const PixelPacket
8901 for (pass=0; pass < num_passes; pass++)
8903 if ((image_depth > 8) || (mng_info->write_png24 ||
8904 mng_info->write_png32 ||
8905 (!mng_info->write_png8 && !mng_info->IsPalette)))
8907 for (y=0; y < (ssize_t) image->rows; y++)
8909 p=GetVirtualPixels(image,0,y,image->columns,1,
8912 if (p == (const PixelPacket *) NULL)
8915 if (ping_color_type == PNG_COLOR_TYPE_GRAY)
8917 if (image->storage_class == DirectClass)
8918 (void) ExportQuantumPixels(image,(const CacheView *) NULL,
8919 quantum_info,RedQuantum,ping_pixels,&image->exception);
8922 (void) ExportQuantumPixels(image,(const CacheView *) NULL,
8923 quantum_info,GrayQuantum,ping_pixels,&image->exception);
8926 else if (ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
8928 (void) ExportQuantumPixels(image,(const CacheView *) NULL,
8929 quantum_info,GrayAlphaQuantum,ping_pixels,
8932 if (logging != MagickFalse && y == 0)
8933 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8934 " Writing GRAY_ALPHA PNG pixels (3)");
8937 else if (image_matte != MagickFalse)
8938 (void) ExportQuantumPixels(image,(const CacheView *) NULL,
8939 quantum_info,RGBAQuantum,ping_pixels,&image->exception);
8942 (void) ExportQuantumPixels(image,(const CacheView *) NULL,
8943 quantum_info,RGBQuantum,ping_pixels,&image->exception);
8945 if (logging != MagickFalse && y == 0)
8946 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8947 " Writing row of pixels (3)");
8949 png_write_row(ping,ping_pixels);
8954 /* not ((image_depth > 8) || (mng_info->write_png24 ||
8955 mng_info->write_png32 ||
8956 (!mng_info->write_png8 && !mng_info->IsPalette))) */
8958 if ((ping_color_type != PNG_COLOR_TYPE_GRAY) &&
8959 (ping_color_type != PNG_COLOR_TYPE_GRAY_ALPHA))
8961 if (logging != MagickFalse)
8962 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8963 " pass %d, Image Is not GRAY or GRAY_ALPHA",pass);
8965 quantum_info->depth=8;
8969 for (y=0; y < (ssize_t) image->rows; y++)
8971 if (logging != MagickFalse && y == 0)
8972 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8973 " pass %d, Image Is RGB, 16-bit GRAY, or GRAY_ALPHA",pass);
8975 p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception);
8977 if (p == (const PixelPacket *) NULL)
8980 if (ping_color_type == PNG_COLOR_TYPE_GRAY)
8981 (void) ExportQuantumPixels(image,(const CacheView *) NULL,
8982 quantum_info,GrayQuantum,ping_pixels,&image->exception);
8984 else if (ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
8986 if (logging != MagickFalse && y == 0)
8987 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8988 " Writing GRAY_ALPHA PNG pixels (4)");
8990 (void) ExportQuantumPixels(image,(const CacheView *) NULL,
8991 quantum_info,GrayAlphaQuantum,ping_pixels,
8996 (void) ExportQuantumPixels(image,(const CacheView *) NULL,
8997 quantum_info,IndexQuantum,ping_pixels,&image->exception);
8999 if (logging != MagickFalse && y <= 2)
9001 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9002 " Writing row of pixels (4)");
9004 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9005 " ping_pixels[0]=%d,ping_pixels[1]=%d",
9006 (int)ping_pixels[0],(int)ping_pixels[1]);
9008 png_write_row(ping,ping_pixels);
9012 if (image->previous == (Image *) NULL)
9014 status=SetImageProgress(image,LoadImageTag,pass,num_passes);
9015 if (status == MagickFalse)
9022 if (quantum_info != (QuantumInfo *) NULL)
9023 quantum_info=DestroyQuantumInfo(quantum_info);
9025 if (logging != MagickFalse)
9027 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9028 " Wrote PNG image data");
9030 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9031 " Width: %.20g",(double) ping_width);
9033 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9034 " Height: %.20g",(double) ping_height);
9036 if (mng_info->write_png_depth)
9038 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9039 " Defined PNG:bit-depth: %d",mng_info->write_png_depth);
9042 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9043 " PNG bit-depth written: %d",ping_bit_depth);
9045 if (mng_info->write_png_colortype)
9047 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9048 " Defined PNG:color-type: %d",mng_info->write_png_colortype-1);
9051 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9052 " PNG color-type written: %d",ping_color_type);
9054 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9055 " PNG Interlace method: %d",ping_interlace_method);
9058 Generate text chunks.
9060 if (ping_exclude_tEXt == MagickFalse && ping_exclude_zTXt == MagickFalse)
9062 ResetImagePropertyIterator(image);
9063 property=GetNextImageProperty(image);
9064 while (property != (const char *) NULL)
9069 value=GetImageProperty(image,property);
9070 if (value != (const char *) NULL)
9072 text=(png_textp) png_malloc(ping,(png_uint_32) sizeof(png_text));
9073 text[0].key=(char *) property;
9074 text[0].text=(char *) value;
9075 text[0].text_length=strlen(value);
9077 if (ping_exclude_tEXt != MagickFalse)
9078 text[0].compression=PNG_TEXT_COMPRESSION_zTXt;
9080 else if (ping_exclude_zTXt != MagickFalse)
9081 text[0].compression=PNG_TEXT_COMPRESSION_NONE;
9085 text[0].compression=image_info->compression == NoCompression ||
9086 (image_info->compression == UndefinedCompression &&
9087 text[0].text_length < 128) ? PNG_TEXT_COMPRESSION_NONE :
9088 PNG_TEXT_COMPRESSION_zTXt ;
9091 if (logging != MagickFalse)
9093 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9094 " Setting up text chunk");
9096 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9097 " keyword: %s",text[0].key);
9100 png_set_text(ping,ping_info,text,1);
9101 png_free(ping,text);
9103 property=GetNextImageProperty(image);
9107 /* write any PNG-chunk-e profiles */
9108 (void) Magick_png_write_chunk_from_profile(image,"PNG-chunk-e",logging);
9110 if (logging != MagickFalse)
9111 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9112 " Writing PNG end info");
9114 png_write_end(ping,ping_info);
9116 if (mng_info->need_fram && (int) image->dispose == BackgroundDispose)
9118 if (mng_info->page.x || mng_info->page.y ||
9119 (ping_width != mng_info->page.width) ||
9120 (ping_height != mng_info->page.height))
9126 Write FRAM 4 with clipping boundaries followed by FRAM 1.
9128 (void) WriteBlobMSBULong(image,27L); /* data length=27 */
9129 PNGType(chunk,mng_FRAM);
9130 LogPNGChunk(logging,mng_FRAM,27L);
9132 chunk[5]=0; /* frame name separator (no name) */
9133 chunk[6]=1; /* flag for changing delay, for next frame only */
9134 chunk[7]=0; /* flag for changing frame timeout */
9135 chunk[8]=1; /* flag for changing frame clipping for next frame */
9136 chunk[9]=0; /* flag for changing frame sync_id */
9137 PNGLong(chunk+10,(png_uint_32) (0L)); /* temporary 0 delay */
9138 chunk[14]=0; /* clipping boundaries delta type */
9139 PNGLong(chunk+15,(png_uint_32) (mng_info->page.x)); /* left cb */
9141 (png_uint_32) (mng_info->page.x + ping_width));
9142 PNGLong(chunk+23,(png_uint_32) (mng_info->page.y)); /* top cb */
9144 (png_uint_32) (mng_info->page.y + ping_height));
9145 (void) WriteBlob(image,31,chunk);
9146 (void) WriteBlobMSBULong(image,crc32(0,chunk,31));
9147 mng_info->old_framing_mode=4;
9148 mng_info->framing_mode=1;
9152 mng_info->framing_mode=3;
9154 if (mng_info->write_mng && !mng_info->need_fram &&
9155 ((int) image->dispose == 3))
9156 (void) ThrowMagickException(&image->exception,GetMagickModule(),
9157 CoderError,"Cannot convert GIF with disposal method 3 to MNG-LC",
9158 "`%s'",image->filename);
9164 png_destroy_write_struct(&ping,&ping_info);
9166 ping_pixels=(unsigned char *) RelinquishMagickMemory(ping_pixels);
9168 #if defined(PNG_SETJMP_NOT_THREAD_SAFE)
9169 UnlockSemaphoreInfo(ping_semaphore);
9172 if (mng_info->need_blob != MagickFalse)
9173 (void) CloseBlob(image);
9175 image_info=DestroyImageInfo(image_info);
9176 image=DestroyImage(image);
9178 /* Store bit depth actually written */
9179 s[0]=(char) ping_bit_depth;
9182 (void) SetImageProperty(IMimage,"png:bit-depth-written",s);
9184 if (logging != MagickFalse)
9185 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9186 " exit WriteOnePNGImage()");
9189 /* End write one PNG image */
9193 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
9197 % W r i t e P N G I m a g e %
9201 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
9203 % WritePNGImage() writes a Portable Network Graphics (PNG) or
9204 % Multiple-image Network Graphics (MNG) image file.
9206 % MNG support written by Glenn Randers-Pehrson, glennrp@image...
9208 % The format of the WritePNGImage method is:
9210 % MagickBooleanType WritePNGImage(const ImageInfo *image_info,Image *image)
9212 % A description of each parameter follows:
9214 % o image_info: the image info.
9216 % o image: The image.
9218 % Returns MagickTrue on success, MagickFalse on failure.
9220 % Communicating with the PNG encoder:
9222 % While the datastream written is always in PNG format and normally would
9223 % be given the "png" file extension, this method also writes the following
9224 % pseudo-formats which are subsets of PNG:
9226 % o PNG8: An 8-bit indexed PNG datastream is written. If transparency
9227 % is present, the tRNS chunk must only have values 0 and 255
9228 % (i.e., transparency is binary: fully opaque or fully
9229 % transparent). The pixels contain 8-bit indices even if
9230 % they could be represented with 1, 2, or 4 bits. Note: grayscale
9231 % images will be written as indexed PNG files even though the
9232 % PNG grayscale type might be slightly more efficient.
9234 % o PNG24: An 8-bit per sample RGB PNG datastream is written. The tRNS
9235 % chunk can be present to convey binary transparency by naming
9236 % one of the colors as transparent.
9238 % o PNG32: An 8-bit per sample RGBA PNG is written. Partial
9239 % transparency is permitted, i.e., the alpha sample for
9240 % each pixel can have any value from 0 to 255. The alpha
9241 % channel is present even if the image is fully opaque.
9243 % o -define: For more precise control of the PNG output, you can use the
9244 % Image options "png:bit-depth" and "png:color-type". These
9245 % can be set from the commandline with "-define" and also
9246 % from the application programming interfaces. The options
9247 % are case-independent and are converted to lowercase before
9248 % being passed to this encoder.
9250 % png:color-type can be 0, 2, 3, 4, or 6.
9252 % When png:color-type is 0 (Grayscale), png:bit-depth can
9253 % be 1, 2, 4, 8, or 16.
9255 % When png:color-type is 2 (RGB), png:bit-depth can
9258 % When png:color-type is 3 (Indexed), png:bit-depth can
9259 % be 1, 2, 4, or 8. This refers to the number of bits
9260 % used to store the index. The color samples always have
9261 % bit-depth 8 in indexed PNG files.
9263 % When png:color-type is 4 (Gray-Matte) or 6 (RGB-Matte),
9264 % png:bit-depth can be 8 or 16.
9266 % If the image cannot be written without loss in the requested PNG8, PNG24,
9267 % or PNG32 format or with the requested bit-depth and color-type without loss,
9268 % a PNG file will not be written, and the encoder will return MagickFalse.
9269 % Since image encoders should not be responsible for the "heavy lifting",
9270 % the user should make sure that ImageMagick has already reduced the
9271 % image depth and number of colors and limit transparency to binary
9272 % transparency prior to attempting to write the image in a format that
9273 % is subject to depth, color, or transparency limitations.
9275 % TODO: Enforce the previous paragraph.
9277 % Note that another definition, "png:bit-depth-written" exists, but it
9278 % is not intended for external use. It is only used internally by the
9279 % PNG encoder to inform the JNG encoder of the depth of the alpha channel.
9281 % It is possible to request that the PNG encoder write previously-formatted
9282 % ancillary chunks in the output PNG file, using the "-profile" commandline
9283 % option as shown below or by setting the profile via a programming
9286 % -profile PNG-chunk-x:<file>
9288 % where x is a location flag and <file> is a file containing the chunk
9289 % name in the first 4 bytes, then a colon (":"), followed by the chunk data.
9290 % This encoder will compute the chunk length and CRC, so those must not
9291 % be included in the file.
9293 % "x" can be "b" (before PLTE), "m" (middle, i.e., between PLTE and IDAT),
9294 % or "e" (end, i.e., after IDAT). If you want to write multiple chunks
9295 % of the same type, then add a short unique string after the "x" to prevent
9296 % subsequent profiles from overwriting the preceding ones, e.g.,
9298 % -profile PNG-chunk-b01:file01 -profile PNG-chunk-b02:file02
9300 % As of version 6.6.6 the following optimizations are always done:
9302 % o 32-bit depth is reduced to 16.
9303 % o 16-bit depth is reduced to 8 if all pixels contain samples whose
9304 % high byte and low byte are identical.
9305 % o Palette is sorted to remove unused entries and to put a
9306 % transparent color first, if BUILD_PNG_PALETTE is defined.
9307 % o Opaque matte channel is removed when writing an indexed PNG.
9308 % o Grayscale images are reduced to 1, 2, or 4 bit depth if
9309 % this can be done without loss and a larger bit depth N was not
9310 % requested via the "-define PNG:bit-depth=N" option.
9311 % o If matte channel is present but only one transparent color is
9312 % present, RGB+tRNS is written instead of RGBA
9313 % o Opaque matte channel is removed (or added, if color-type 4 or 6
9314 % was requested when converting an opaque image).
9316 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
9318 static MagickBooleanType WritePNGImage(const ImageInfo *image_info,
9340 assert(image_info != (const ImageInfo *) NULL);
9341 assert(image_info->signature == MagickSignature);
9342 assert(image != (Image *) NULL);
9343 assert(image->signature == MagickSignature);
9344 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
9345 logging=LogMagickEvent(CoderEvent,GetMagickModule(),"enter WritePNGImage()");
9347 Allocate a MngInfo structure.
9349 have_mng_structure=MagickFalse;
9350 mng_info=(MngInfo *) AcquireMagickMemory(sizeof(MngInfo));
9352 if (mng_info == (MngInfo *) NULL)
9353 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
9356 Initialize members of the MngInfo structure.
9358 (void) ResetMagickMemory(mng_info,0,sizeof(MngInfo));
9359 mng_info->image=image;
9360 mng_info->equal_backgrounds=MagickTrue;
9361 have_mng_structure=MagickTrue;
9363 /* See if user has requested a specific PNG subformat */
9365 mng_info->write_png8=LocaleCompare(image_info->magick,"PNG8") == 0;
9366 mng_info->write_png24=LocaleCompare(image_info->magick,"PNG24") == 0;
9367 mng_info->write_png32=LocaleCompare(image_info->magick,"PNG32") == 0;
9369 if (mng_info->write_png8)
9371 mng_info->write_png_colortype = /* 3 */ 4;
9372 mng_info->write_png_depth = 8;
9376 if (mng_info->write_png24)
9378 mng_info->write_png_colortype = /* 2 */ 3;
9379 mng_info->write_png_depth = 8;
9382 if (image->matte == MagickTrue)
9383 (void) SetImageType(image,TrueColorMatteType);
9386 (void) SetImageType(image,TrueColorType);
9388 (void) SyncImage(image);
9391 if (mng_info->write_png32)
9393 mng_info->write_png_colortype = /* 6 */ 7;
9394 mng_info->write_png_depth = 8;
9397 if (image->matte == MagickTrue)
9398 (void) SetImageType(image,TrueColorMatteType);
9401 (void) SetImageType(image,TrueColorType);
9403 (void) SyncImage(image);
9406 value=GetImageOption(image_info,"png:bit-depth");
9408 if (value != (char *) NULL)
9410 if (LocaleCompare(value,"1") == 0)
9411 mng_info->write_png_depth = 1;
9413 else if (LocaleCompare(value,"2") == 0)
9414 mng_info->write_png_depth = 2;
9416 else if (LocaleCompare(value,"4") == 0)
9417 mng_info->write_png_depth = 4;
9419 else if (LocaleCompare(value,"8") == 0)
9420 mng_info->write_png_depth = 8;
9422 else if (LocaleCompare(value,"16") == 0)
9423 mng_info->write_png_depth = 16;
9426 (void) ThrowMagickException(&image->exception,
9427 GetMagickModule(),CoderWarning,
9428 "ignoring invalid defined png:bit-depth",
9431 if (logging != MagickFalse)
9432 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9433 " png:bit-depth=%d was defined.\n",mng_info->write_png_depth);
9436 value=GetImageOption(image_info,"png:color-type");
9438 if (value != (char *) NULL)
9440 /* We must store colortype+1 because 0 is a valid colortype */
9441 if (LocaleCompare(value,"0") == 0)
9442 mng_info->write_png_colortype = 1;
9444 else if (LocaleCompare(value,"2") == 0)
9445 mng_info->write_png_colortype = 3;
9447 else if (LocaleCompare(value,"3") == 0)
9448 mng_info->write_png_colortype = 4;
9450 else if (LocaleCompare(value,"4") == 0)
9451 mng_info->write_png_colortype = 5;
9453 else if (LocaleCompare(value,"6") == 0)
9454 mng_info->write_png_colortype = 7;
9457 (void) ThrowMagickException(&image->exception,
9458 GetMagickModule(),CoderWarning,
9459 "ignoring invalid defined png:color-type",
9462 if (logging != MagickFalse)
9463 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9464 " png:color-type=%d was defined.\n",mng_info->write_png_colortype-1);
9467 /* Check for chunks to be excluded:
9469 * The default is to not exclude any known chunks except for any
9470 * listed in the "unused_chunks" array, above.
9472 * Chunks can be listed for exclusion via a "PNG:exclude-chunk"
9473 * define (in the image properties or in the image artifacts)
9474 * or via a mng_info member. For convenience, in addition
9475 * to or instead of a comma-separated list of chunks, the
9476 * "exclude-chunk" string can be simply "all" or "none".
9478 * The exclude-chunk define takes priority over the mng_info.
9480 * A "PNG:include-chunk" define takes priority over both the
9481 * mng_info and the "PNG:exclude-chunk" define. Like the
9482 * "exclude-chunk" string, it can define "all" or "none" as
9483 * well as a comma-separated list. Chunks that are unknown to
9484 * ImageMagick are always excluded, regardless of their "copy-safe"
9485 * status according to the PNG specification, and even if they
9486 * appear in the "include-chunk" list.
9488 * Finally, all chunks listed in the "unused_chunks" array are
9489 * automatically excluded, regardless of the other instructions
9492 * if you exclude sRGB but not gAMA (recommended), then sRGB chunk
9493 * will not be written and the gAMA chunk will only be written if it
9494 * is not between .45 and .46, or approximately (1.0/2.2).
9496 * If you exclude tRNS and the image has transparency, the colortype
9497 * is forced to be 4 or 6 (GRAY_ALPHA or RGB_ALPHA).
9499 * The -strip option causes StripImage() to set the png:include-chunk
9500 * artifact to "none,gama".
9503 mng_info->ping_exclude_bKGD=MagickFalse;
9504 mng_info->ping_exclude_cHRM=MagickFalse;
9505 mng_info->ping_exclude_EXIF=MagickFalse; /* hex-encoded EXIF in zTXt */
9506 mng_info->ping_exclude_gAMA=MagickFalse;
9507 mng_info->ping_exclude_cHRM=MagickFalse;
9508 mng_info->ping_exclude_iCCP=MagickFalse;
9509 /* mng_info->ping_exclude_iTXt=MagickFalse; */
9510 mng_info->ping_exclude_oFFs=MagickFalse;
9511 mng_info->ping_exclude_pHYs=MagickFalse;
9512 mng_info->ping_exclude_sRGB=MagickFalse;
9513 mng_info->ping_exclude_tEXt=MagickFalse;
9514 mng_info->ping_exclude_tRNS=MagickFalse;
9515 mng_info->ping_exclude_vpAg=MagickFalse;
9516 mng_info->ping_exclude_zCCP=MagickFalse; /* hex-encoded iCCP in zTXt */
9517 mng_info->ping_exclude_zTXt=MagickFalse;
9519 excluding=MagickFalse;
9521 for (source=0; source<1; source++)
9525 value=GetImageArtifact(image,"png:exclude-chunk");
9528 value=GetImageArtifact(image,"png:exclude-chunks");
9532 value=GetImageOption(image_info,"png:exclude-chunk");
9535 value=GetImageOption(image_info,"png:exclude-chunks");
9544 excluding=MagickTrue;
9546 if (logging != MagickFalse)
9549 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9550 " png:exclude-chunk=%s found in image artifacts.\n", value);
9552 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9553 " png:exclude-chunk=%s found in image properties.\n", value);
9558 for (i=0; i<(int) last; i+=5)
9561 if (LocaleNCompare(value+i,"all",3) == 0)
9563 mng_info->ping_exclude_bKGD=MagickTrue;
9564 mng_info->ping_exclude_cHRM=MagickTrue;
9565 mng_info->ping_exclude_EXIF=MagickTrue;
9566 mng_info->ping_exclude_gAMA=MagickTrue;
9567 mng_info->ping_exclude_iCCP=MagickTrue;
9568 /* mng_info->ping_exclude_iTXt=MagickTrue; */
9569 mng_info->ping_exclude_oFFs=MagickTrue;
9570 mng_info->ping_exclude_pHYs=MagickTrue;
9571 mng_info->ping_exclude_sRGB=MagickTrue;
9572 mng_info->ping_exclude_tEXt=MagickTrue;
9573 mng_info->ping_exclude_tRNS=MagickTrue;
9574 mng_info->ping_exclude_vpAg=MagickTrue;
9575 mng_info->ping_exclude_zCCP=MagickTrue;
9576 mng_info->ping_exclude_zTXt=MagickTrue;
9580 if (LocaleNCompare(value+i,"none",4) == 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;
9598 if (LocaleNCompare(value+i,"bkgd",4) == 0)
9599 mng_info->ping_exclude_bKGD=MagickTrue;
9601 if (LocaleNCompare(value+i,"chrm",4) == 0)
9602 mng_info->ping_exclude_cHRM=MagickTrue;
9604 if (LocaleNCompare(value+i,"exif",4) == 0)
9605 mng_info->ping_exclude_EXIF=MagickTrue;
9607 if (LocaleNCompare(value+i,"gama",4) == 0)
9608 mng_info->ping_exclude_gAMA=MagickTrue;
9610 if (LocaleNCompare(value+i,"iccp",4) == 0)
9611 mng_info->ping_exclude_iCCP=MagickTrue;
9614 if (LocaleNCompare(value+i,"itxt",4) == 0)
9615 mng_info->ping_exclude_iTXt=MagickTrue;
9618 if (LocaleNCompare(value+i,"gama",4) == 0)
9619 mng_info->ping_exclude_gAMA=MagickTrue;
9621 if (LocaleNCompare(value+i,"offs",4) == 0)
9622 mng_info->ping_exclude_oFFs=MagickTrue;
9624 if (LocaleNCompare(value+i,"phys",4) == 0)
9625 mng_info->ping_exclude_pHYs=MagickTrue;
9627 if (LocaleNCompare(value+i,"srgb",4) == 0)
9628 mng_info->ping_exclude_sRGB=MagickTrue;
9630 if (LocaleNCompare(value+i,"text",4) == 0)
9631 mng_info->ping_exclude_tEXt=MagickTrue;
9633 if (LocaleNCompare(value+i,"trns",4) == 0)
9634 mng_info->ping_exclude_tRNS=MagickTrue;
9636 if (LocaleNCompare(value+i,"vpag",4) == 0)
9637 mng_info->ping_exclude_vpAg=MagickTrue;
9639 if (LocaleNCompare(value+i,"zccp",4) == 0)
9640 mng_info->ping_exclude_zCCP=MagickTrue;
9642 if (LocaleNCompare(value+i,"ztxt",4) == 0)
9643 mng_info->ping_exclude_zTXt=MagickTrue;
9649 for (source=0; source<1; source++)
9653 value=GetImageArtifact(image,"png:include-chunk");
9656 value=GetImageArtifact(image,"png:include-chunks");
9660 value=GetImageOption(image_info,"png:include-chunk");
9663 value=GetImageOption(image_info,"png:include-chunks");
9671 excluding=MagickTrue;
9673 if (logging != MagickFalse)
9676 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9677 " png:include-chunk=%s found in image artifacts.\n", value);
9679 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9680 " png:include-chunk=%s found in image properties.\n", value);
9685 for (i=0; i<(int) last; i+=5)
9687 if (LocaleNCompare(value+i,"all",3) == 0)
9689 mng_info->ping_exclude_bKGD=MagickFalse;
9690 mng_info->ping_exclude_cHRM=MagickFalse;
9691 mng_info->ping_exclude_EXIF=MagickFalse;
9692 mng_info->ping_exclude_gAMA=MagickFalse;
9693 mng_info->ping_exclude_iCCP=MagickFalse;
9694 /* mng_info->ping_exclude_iTXt=MagickFalse; */
9695 mng_info->ping_exclude_oFFs=MagickFalse;
9696 mng_info->ping_exclude_pHYs=MagickFalse;
9697 mng_info->ping_exclude_sRGB=MagickFalse;
9698 mng_info->ping_exclude_tEXt=MagickFalse;
9699 mng_info->ping_exclude_tRNS=MagickFalse;
9700 mng_info->ping_exclude_vpAg=MagickFalse;
9701 mng_info->ping_exclude_zCCP=MagickFalse;
9702 mng_info->ping_exclude_zTXt=MagickFalse;
9706 if (LocaleNCompare(value+i,"none",4) == 0)
9708 mng_info->ping_exclude_bKGD=MagickTrue;
9709 mng_info->ping_exclude_cHRM=MagickTrue;
9710 mng_info->ping_exclude_EXIF=MagickTrue;
9711 mng_info->ping_exclude_gAMA=MagickTrue;
9712 mng_info->ping_exclude_iCCP=MagickTrue;
9713 /* mng_info->ping_exclude_iTXt=MagickTrue; */
9714 mng_info->ping_exclude_oFFs=MagickTrue;
9715 mng_info->ping_exclude_pHYs=MagickTrue;
9716 mng_info->ping_exclude_sRGB=MagickTrue;
9717 mng_info->ping_exclude_tEXt=MagickTrue;
9718 mng_info->ping_exclude_tRNS=MagickTrue;
9719 mng_info->ping_exclude_vpAg=MagickTrue;
9720 mng_info->ping_exclude_zCCP=MagickTrue;
9721 mng_info->ping_exclude_zTXt=MagickTrue;
9724 if (LocaleNCompare(value+i,"bkgd",4) == 0)
9725 mng_info->ping_exclude_bKGD=MagickFalse;
9727 if (LocaleNCompare(value+i,"chrm",4) == 0)
9728 mng_info->ping_exclude_cHRM=MagickFalse;
9730 if (LocaleNCompare(value+i,"exif",4) == 0)
9731 mng_info->ping_exclude_EXIF=MagickFalse;
9733 if (LocaleNCompare(value+i,"gama",4) == 0)
9734 mng_info->ping_exclude_gAMA=MagickFalse;
9736 if (LocaleNCompare(value+i,"iccp",4) == 0)
9737 mng_info->ping_exclude_iCCP=MagickFalse;
9740 if (LocaleNCompare(value+i,"itxt",4) == 0)
9741 mng_info->ping_exclude_iTXt=MagickFalse;
9744 if (LocaleNCompare(value+i,"gama",4) == 0)
9745 mng_info->ping_exclude_gAMA=MagickFalse;
9747 if (LocaleNCompare(value+i,"offs",4) == 0)
9748 mng_info->ping_exclude_oFFs=MagickFalse;
9750 if (LocaleNCompare(value+i,"phys",4) == 0)
9751 mng_info->ping_exclude_pHYs=MagickFalse;
9753 if (LocaleNCompare(value+i,"srgb",4) == 0)
9754 mng_info->ping_exclude_sRGB=MagickFalse;
9756 if (LocaleNCompare(value+i,"text",4) == 0)
9757 mng_info->ping_exclude_tEXt=MagickFalse;
9759 if (LocaleNCompare(value+i,"trns",4) == 0)
9760 mng_info->ping_exclude_tRNS=MagickFalse;
9762 if (LocaleNCompare(value+i,"vpag",4) == 0)
9763 mng_info->ping_exclude_vpAg=MagickFalse;
9765 if (LocaleNCompare(value+i,"zccp",4) == 0)
9766 mng_info->ping_exclude_zCCP=MagickFalse;
9768 if (LocaleNCompare(value+i,"ztxt",4) == 0)
9769 mng_info->ping_exclude_zTXt=MagickFalse;
9775 if (excluding != MagickFalse && logging != MagickFalse)
9777 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9778 " Chunks to be excluded from the output PNG:");
9779 if (mng_info->ping_exclude_bKGD != MagickFalse)
9780 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9782 if (mng_info->ping_exclude_cHRM != MagickFalse)
9783 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9785 if (mng_info->ping_exclude_EXIF != MagickFalse)
9786 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9788 if (mng_info->ping_exclude_gAMA != MagickFalse)
9789 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9791 if (mng_info->ping_exclude_iCCP != MagickFalse)
9792 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9795 if (mng_info->ping_exclude_iTXt != MagickFalse)
9796 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9799 if (mng_info->ping_exclude_oFFs != MagickFalse)
9800 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9802 if (mng_info->ping_exclude_pHYs != MagickFalse)
9803 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9805 if (mng_info->ping_exclude_sRGB != MagickFalse)
9806 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9808 if (mng_info->ping_exclude_tEXt != MagickFalse)
9809 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9811 if (mng_info->ping_exclude_tRNS != MagickFalse)
9812 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9814 if (mng_info->ping_exclude_vpAg != MagickFalse)
9815 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9817 if (mng_info->ping_exclude_zCCP != MagickFalse)
9818 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9820 if (mng_info->ping_exclude_zTXt != MagickFalse)
9821 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9825 mng_info->need_blob = MagickTrue;
9827 status=WriteOnePNGImage(mng_info,image_info,image);
9829 MngInfoFreeStruct(mng_info,&have_mng_structure);
9831 if (logging != MagickFalse)
9832 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"exit WritePNGImage()");
9837 #if defined(JNG_SUPPORTED)
9839 /* Write one JNG image */
9840 static MagickBooleanType WriteOneJNGImage(MngInfo *mng_info,
9841 const ImageInfo *image_info,Image *image)
9862 jng_alpha_compression_method,
9863 jng_alpha_sample_depth,
9870 logging=LogMagickEvent(CoderEvent,GetMagickModule(),
9871 " enter WriteOneJNGImage()");
9873 blob=(unsigned char *) NULL;
9874 jpeg_image=(Image *) NULL;
9875 jpeg_image_info=(ImageInfo *) NULL;
9878 transparent=image_info->type==GrayscaleMatteType ||
9879 image_info->type==TrueColorMatteType;
9881 jng_alpha_sample_depth=0;
9882 jng_quality=image_info->quality == 0UL ? 75UL : image_info->quality;
9883 jng_alpha_compression_method=0;
9885 if (image->matte != MagickFalse)
9887 /* if any pixels are transparent */
9888 transparent=MagickTrue;
9889 if (image_info->compression==JPEGCompression)
9890 jng_alpha_compression_method=8;
9897 /* Create JPEG blob, image, and image_info */
9898 if (logging != MagickFalse)
9899 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9900 " Creating jpeg_image_info for opacity.");
9902 jpeg_image_info=(ImageInfo *) CloneImageInfo(image_info);
9904 if (jpeg_image_info == (ImageInfo *) NULL)
9905 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
9907 if (logging != MagickFalse)
9908 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9909 " Creating jpeg_image.");
9911 jpeg_image=CloneImage(image,0,0,MagickTrue,&image->exception);
9913 if (jpeg_image == (Image *) NULL)
9914 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
9916 (void) CopyMagickString(jpeg_image->magick,"JPEG",MaxTextExtent);
9917 status=SeparateImageChannel(jpeg_image,OpacityChannel);
9918 status=NegateImage(jpeg_image,MagickFalse);
9919 jpeg_image->matte=MagickFalse;
9921 if (jng_quality >= 1000)
9922 jpeg_image_info->quality=jng_quality/1000;
9925 jpeg_image_info->quality=jng_quality;
9927 jpeg_image_info->type=GrayscaleType;
9928 (void) SetImageType(jpeg_image,GrayscaleType);
9929 (void) AcquireUniqueFilename(jpeg_image->filename);
9930 (void) FormatMagickString(jpeg_image_info->filename,MaxTextExtent,
9931 "%s",jpeg_image->filename);
9934 /* To do: check bit depth of PNG alpha channel */
9936 /* Check if image is grayscale. */
9937 if (image_info->type != TrueColorMatteType && image_info->type !=
9938 TrueColorType && ImageIsGray(image))
9943 if (jng_alpha_compression_method==0)
9948 /* Encode opacity as a grayscale PNG blob */
9949 status=OpenBlob(jpeg_image_info,jpeg_image,WriteBinaryBlobMode,
9951 if (logging != MagickFalse)
9952 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9953 " Creating PNG blob.");
9956 (void) CopyMagickString(jpeg_image_info->magick,"PNG",MaxTextExtent);
9957 (void) CopyMagickString(jpeg_image->magick,"PNG",MaxTextExtent);
9958 jpeg_image_info->interlace=NoInterlace;
9960 blob=ImageToBlob(jpeg_image_info,jpeg_image,&length,
9963 /* Retrieve sample depth used */
9964 value=GetImageProperty(jpeg_image,"png:bit-depth-written");
9965 if (value != (char *) NULL)
9966 jng_alpha_sample_depth= (unsigned int) value[0];
9970 /* Encode opacity as a grayscale JPEG blob */
9972 status=OpenBlob(jpeg_image_info,jpeg_image,WriteBinaryBlobMode,
9975 (void) CopyMagickString(jpeg_image_info->magick,"JPEG",MaxTextExtent);
9976 (void) CopyMagickString(jpeg_image->magick,"JPEG",MaxTextExtent);
9977 jpeg_image_info->interlace=NoInterlace;
9978 if (logging != MagickFalse)
9979 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9981 blob=ImageToBlob(jpeg_image_info,jpeg_image,&length,
9983 jng_alpha_sample_depth=8;
9985 if (logging != MagickFalse)
9986 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9987 " Successfully read jpeg_image into a blob, length=%.20g.",
9991 /* Destroy JPEG image and image_info */
9992 jpeg_image=DestroyImage(jpeg_image);
9993 (void) RelinquishUniqueFileResource(jpeg_image_info->filename);
9994 jpeg_image_info=DestroyImageInfo(jpeg_image_info);
9997 /* Write JHDR chunk */
9998 (void) WriteBlobMSBULong(image,16L); /* chunk data length=16 */
9999 PNGType(chunk,mng_JHDR);
10000 LogPNGChunk(logging,mng_JHDR,16L);
10001 PNGLong(chunk+4,(png_uint_32) image->columns);
10002 PNGLong(chunk+8,(png_uint_32) image->rows);
10003 chunk[12]=jng_color_type;
10004 chunk[13]=8; /* sample depth */
10005 chunk[14]=8; /*jng_image_compression_method */
10006 chunk[15]=(unsigned char) (image_info->interlace == NoInterlace ? 0 : 8);
10007 chunk[16]=jng_alpha_sample_depth;
10008 chunk[17]=jng_alpha_compression_method;
10009 chunk[18]=0; /*jng_alpha_filter_method */
10010 chunk[19]=0; /*jng_alpha_interlace_method */
10011 (void) WriteBlob(image,20,chunk);
10012 (void) WriteBlobMSBULong(image,crc32(0,chunk,20));
10013 if (logging != MagickFalse)
10015 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10016 " JNG width:%15lu",(unsigned long) image->columns);
10018 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10019 " JNG height:%14lu",(unsigned long) image->rows);
10021 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10022 " JNG color type:%10d",jng_color_type);
10024 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10025 " JNG sample depth:%8d",8);
10027 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10028 " JNG compression:%9d",8);
10030 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10031 " JNG interlace:%11d",0);
10033 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10034 " JNG alpha depth:%9d",jng_alpha_sample_depth);
10036 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10037 " JNG alpha compression:%3d",jng_alpha_compression_method);
10039 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10040 " JNG alpha filter:%8d",0);
10042 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10043 " JNG alpha interlace:%5d",0);
10046 /* Write any JNG-chunk-b profiles */
10047 (void) Magick_png_write_chunk_from_profile(image,"JNG-chunk-b",logging);
10050 Write leading ancillary chunks
10056 Write JNG bKGD chunk
10067 if (jng_color_type == 8 || jng_color_type == 12)
10071 (void) WriteBlobMSBULong(image,(size_t) (num_bytes-4L));
10072 PNGType(chunk,mng_bKGD);
10073 LogPNGChunk(logging,mng_bKGD,(size_t) (num_bytes-4L));
10074 red=ScaleQuantumToChar(image->background_color.red);
10075 green=ScaleQuantumToChar(image->background_color.green);
10076 blue=ScaleQuantumToChar(image->background_color.blue);
10083 (void) WriteBlob(image,(size_t) num_bytes,chunk);
10084 (void) WriteBlobMSBULong(image,crc32(0,chunk,(uInt) num_bytes));
10087 if ((image->colorspace == sRGBColorspace || image->rendering_intent))
10090 Write JNG sRGB chunk
10092 (void) WriteBlobMSBULong(image,1L);
10093 PNGType(chunk,mng_sRGB);
10094 LogPNGChunk(logging,mng_sRGB,1L);
10096 if (image->rendering_intent != UndefinedIntent)
10097 chunk[4]=(unsigned char)
10098 Magick_RenderingIntent_to_PNG_RenderingIntent(
10099 (image->rendering_intent));
10102 chunk[4]=(unsigned char)
10103 Magick_RenderingIntent_to_PNG_RenderingIntent(
10104 (PerceptualIntent));
10106 (void) WriteBlob(image,5,chunk);
10107 (void) WriteBlobMSBULong(image,crc32(0,chunk,5));
10111 if (image->gamma != 0.0)
10114 Write JNG gAMA chunk
10116 (void) WriteBlobMSBULong(image,4L);
10117 PNGType(chunk,mng_gAMA);
10118 LogPNGChunk(logging,mng_gAMA,4L);
10119 PNGLong(chunk+4,(png_uint_32) (100000*image->gamma+0.5));
10120 (void) WriteBlob(image,8,chunk);
10121 (void) WriteBlobMSBULong(image,crc32(0,chunk,8));
10124 if ((mng_info->equal_chrms == MagickFalse) &&
10125 (image->chromaticity.red_primary.x != 0.0))
10131 Write JNG cHRM chunk
10133 (void) WriteBlobMSBULong(image,32L);
10134 PNGType(chunk,mng_cHRM);
10135 LogPNGChunk(logging,mng_cHRM,32L);
10136 primary=image->chromaticity.white_point;
10137 PNGLong(chunk+4,(png_uint_32) (100000*primary.x+0.5));
10138 PNGLong(chunk+8,(png_uint_32) (100000*primary.y+0.5));
10139 primary=image->chromaticity.red_primary;
10140 PNGLong(chunk+12,(png_uint_32) (100000*primary.x+0.5));
10141 PNGLong(chunk+16,(png_uint_32) (100000*primary.y+0.5));
10142 primary=image->chromaticity.green_primary;
10143 PNGLong(chunk+20,(png_uint_32) (100000*primary.x+0.5));
10144 PNGLong(chunk+24,(png_uint_32) (100000*primary.y+0.5));
10145 primary=image->chromaticity.blue_primary;
10146 PNGLong(chunk+28,(png_uint_32) (100000*primary.x+0.5));
10147 PNGLong(chunk+32,(png_uint_32) (100000*primary.y+0.5));
10148 (void) WriteBlob(image,36,chunk);
10149 (void) WriteBlobMSBULong(image,crc32(0,chunk,36));
10153 if (image->x_resolution && image->y_resolution && !mng_info->equal_physs)
10156 Write JNG pHYs chunk
10158 (void) WriteBlobMSBULong(image,9L);
10159 PNGType(chunk,mng_pHYs);
10160 LogPNGChunk(logging,mng_pHYs,9L);
10161 if (image->units == PixelsPerInchResolution)
10163 PNGLong(chunk+4,(png_uint_32)
10164 (image->x_resolution*100.0/2.54+0.5));
10166 PNGLong(chunk+8,(png_uint_32)
10167 (image->y_resolution*100.0/2.54+0.5));
10174 if (image->units == PixelsPerCentimeterResolution)
10176 PNGLong(chunk+4,(png_uint_32)
10177 (image->x_resolution*100.0+0.5));
10179 PNGLong(chunk+8,(png_uint_32)
10180 (image->y_resolution*100.0+0.5));
10187 PNGLong(chunk+4,(png_uint_32) (image->x_resolution+0.5));
10188 PNGLong(chunk+8,(png_uint_32) (image->y_resolution+0.5));
10192 (void) WriteBlob(image,13,chunk);
10193 (void) WriteBlobMSBULong(image,crc32(0,chunk,13));
10196 if (mng_info->write_mng == 0 && (image->page.x || image->page.y))
10199 Write JNG oFFs chunk
10201 (void) WriteBlobMSBULong(image,9L);
10202 PNGType(chunk,mng_oFFs);
10203 LogPNGChunk(logging,mng_oFFs,9L);
10204 PNGsLong(chunk+4,(ssize_t) (image->page.x));
10205 PNGsLong(chunk+8,(ssize_t) (image->page.y));
10207 (void) WriteBlob(image,13,chunk);
10208 (void) WriteBlobMSBULong(image,crc32(0,chunk,13));
10210 if (mng_info->write_mng == 0 && (image->page.width || image->page.height))
10212 (void) WriteBlobMSBULong(image,9L); /* data length=8 */
10213 PNGType(chunk,mng_vpAg);
10214 LogPNGChunk(logging,mng_vpAg,9L);
10215 PNGLong(chunk+4,(png_uint_32) image->page.width);
10216 PNGLong(chunk+8,(png_uint_32) image->page.height);
10217 chunk[12]=0; /* unit = pixels */
10218 (void) WriteBlob(image,13,chunk);
10219 (void) WriteBlobMSBULong(image,crc32(0,chunk,13));
10225 if (jng_alpha_compression_method==0)
10233 /* Write IDAT chunk header */
10234 if (logging != MagickFalse)
10235 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10236 " Write IDAT chunks from blob, length=%.20g.",(double)
10239 /* Copy IDAT chunks */
10242 for (i=8; i<(ssize_t) length; i+=len+12)
10244 len=(*p<<24)|((*(p+1))<<16)|((*(p+2))<<8)|(*(p+3));
10247 if (*(p)==73 && *(p+1)==68 && *(p+2)==65 && *(p+3)==84) /* IDAT */
10249 /* Found an IDAT chunk. */
10250 (void) WriteBlobMSBULong(image,(size_t) len);
10251 LogPNGChunk(logging,mng_IDAT,(size_t) len);
10252 (void) WriteBlob(image,(size_t) len+4,p);
10253 (void) WriteBlobMSBULong(image,
10254 crc32(0,p,(uInt) len+4));
10259 if (logging != MagickFalse)
10260 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10261 " Skipping %c%c%c%c chunk, length=%.20g.",
10262 *(p),*(p+1),*(p+2),*(p+3),(double) len);
10269 /* Write JDAA chunk header */
10270 if (logging != MagickFalse)
10271 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10272 " Write JDAA chunk, length=%.20g.",(double) length);
10273 (void) WriteBlobMSBULong(image,(size_t) length);
10274 PNGType(chunk,mng_JDAA);
10275 LogPNGChunk(logging,mng_JDAA,length);
10276 /* Write JDAT chunk(s) data */
10277 (void) WriteBlob(image,4,chunk);
10278 (void) WriteBlob(image,length,blob);
10279 (void) WriteBlobMSBULong(image,crc32(crc32(0,chunk,4),blob,
10282 blob=(unsigned char *) RelinquishMagickMemory(blob);
10285 /* Encode image as a JPEG blob */
10286 if (logging != MagickFalse)
10287 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10288 " Creating jpeg_image_info.");
10289 jpeg_image_info=(ImageInfo *) CloneImageInfo(image_info);
10290 if (jpeg_image_info == (ImageInfo *) NULL)
10291 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
10293 if (logging != MagickFalse)
10294 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10295 " Creating jpeg_image.");
10297 jpeg_image=CloneImage(image,0,0,MagickTrue,&image->exception);
10298 if (jpeg_image == (Image *) NULL)
10299 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
10300 (void) CopyMagickString(jpeg_image->magick,"JPEG",MaxTextExtent);
10302 (void) AcquireUniqueFilename(jpeg_image->filename);
10303 (void) FormatMagickString(jpeg_image_info->filename,MaxTextExtent,"%s",
10304 jpeg_image->filename);
10306 status=OpenBlob(jpeg_image_info,jpeg_image,WriteBinaryBlobMode,
10307 &image->exception);
10309 if (logging != MagickFalse)
10310 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10311 " Created jpeg_image, %.20g x %.20g.",(double) jpeg_image->columns,
10312 (double) jpeg_image->rows);
10314 if (jng_color_type == 8 || jng_color_type == 12)
10315 jpeg_image_info->type=GrayscaleType;
10317 jpeg_image_info->quality=jng_quality % 1000;
10318 (void) CopyMagickString(jpeg_image_info->magick,"JPEG",MaxTextExtent);
10319 (void) CopyMagickString(jpeg_image->magick,"JPEG",MaxTextExtent);
10321 if (logging != MagickFalse)
10322 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10323 " Creating blob.");
10325 blob=ImageToBlob(jpeg_image_info,jpeg_image,&length,&image->exception);
10327 if (logging != MagickFalse)
10329 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10330 " Successfully read jpeg_image into a blob, length=%.20g.",
10333 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10334 " Write JDAT chunk, length=%.20g.",(double) length);
10337 /* Write JDAT chunk(s) */
10338 (void) WriteBlobMSBULong(image,(size_t) length);
10339 PNGType(chunk,mng_JDAT);
10340 LogPNGChunk(logging,mng_JDAT,length);
10341 (void) WriteBlob(image,4,chunk);
10342 (void) WriteBlob(image,length,blob);
10343 (void) WriteBlobMSBULong(image,crc32(crc32(0,chunk,4),blob,(uInt) length));
10345 jpeg_image=DestroyImage(jpeg_image);
10346 (void) RelinquishUniqueFileResource(jpeg_image_info->filename);
10347 jpeg_image_info=DestroyImageInfo(jpeg_image_info);
10348 blob=(unsigned char *) RelinquishMagickMemory(blob);
10350 /* Write any JNG-chunk-e profiles */
10351 (void) Magick_png_write_chunk_from_profile(image,"JNG-chunk-e",logging);
10353 /* Write IEND chunk */
10354 (void) WriteBlobMSBULong(image,0L);
10355 PNGType(chunk,mng_IEND);
10356 LogPNGChunk(logging,mng_IEND,0);
10357 (void) WriteBlob(image,4,chunk);
10358 (void) WriteBlobMSBULong(image,crc32(0,chunk,4));
10360 if (logging != MagickFalse)
10361 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10362 " exit WriteOneJNGImage()");
10369 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
10373 % W r i t e J N G I m a g e %
10377 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
10379 % WriteJNGImage() writes a JPEG Network Graphics (JNG) image file.
10381 % JNG support written by Glenn Randers-Pehrson, glennrp@image...
10383 % The format of the WriteJNGImage method is:
10385 % MagickBooleanType WriteJNGImage(const ImageInfo *image_info,Image *image)
10387 % A description of each parameter follows:
10389 % o image_info: the image info.
10391 % o image: The image.
10393 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
10395 static MagickBooleanType WriteJNGImage(const ImageInfo *image_info,Image *image)
10398 have_mng_structure,
10408 assert(image_info != (const ImageInfo *) NULL);
10409 assert(image_info->signature == MagickSignature);
10410 assert(image != (Image *) NULL);
10411 assert(image->signature == MagickSignature);
10412 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
10413 logging=LogMagickEvent(CoderEvent,GetMagickModule(),"enter WriteJNGImage()");
10414 status=OpenBlob(image_info,image,WriteBinaryBlobMode,&image->exception);
10415 if (status == MagickFalse)
10419 Allocate a MngInfo structure.
10421 have_mng_structure=MagickFalse;
10422 mng_info=(MngInfo *) AcquireMagickMemory(sizeof(MngInfo));
10423 if (mng_info == (MngInfo *) NULL)
10424 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
10426 Initialize members of the MngInfo structure.
10428 (void) ResetMagickMemory(mng_info,0,sizeof(MngInfo));
10429 mng_info->image=image;
10430 have_mng_structure=MagickTrue;
10432 (void) WriteBlob(image,8,(const unsigned char *) "\213JNG\r\n\032\n");
10434 status=WriteOneJNGImage(mng_info,image_info,image);
10435 (void) CloseBlob(image);
10437 (void) CatchImageException(image);
10438 MngInfoFreeStruct(mng_info,&have_mng_structure);
10439 if (logging != MagickFalse)
10440 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"exit WriteJNGImage()");
10447 static MagickBooleanType WriteMNGImage(const ImageInfo *image_info,Image *image)
10456 have_mng_structure,
10459 volatile MagickBooleanType
10471 #if defined(PNG_WRITE_EMPTY_PLTE_SUPPORTED) || \
10472 defined(PNG_MNG_FEATURES_SUPPORTED)
10475 all_images_are_gray,
10485 volatile unsigned int
10496 #if (PNG_LIBPNG_VER < 10200)
10497 if (image_info->verbose)
10498 printf("Your PNG library (libpng-%s) is rather old.\n",
10499 PNG_LIBPNG_VER_STRING);
10505 assert(image_info != (const ImageInfo *) NULL);
10506 assert(image_info->signature == MagickSignature);
10507 assert(image != (Image *) NULL);
10508 assert(image->signature == MagickSignature);
10509 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
10510 logging=LogMagickEvent(CoderEvent,GetMagickModule(),"enter WriteMNGImage()");
10511 status=OpenBlob(image_info,image,WriteBinaryBlobMode,&image->exception);
10512 if (status == MagickFalse)
10516 Allocate a MngInfo structure.
10518 have_mng_structure=MagickFalse;
10519 mng_info=(MngInfo *) AcquireMagickMemory(sizeof(MngInfo));
10520 if (mng_info == (MngInfo *) NULL)
10521 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
10523 Initialize members of the MngInfo structure.
10525 (void) ResetMagickMemory(mng_info,0,sizeof(MngInfo));
10526 mng_info->image=image;
10527 have_mng_structure=MagickTrue;
10528 write_mng=LocaleCompare(image_info->magick,"MNG") == 0;
10531 * See if user has requested a specific PNG subformat to be used
10532 * for all of the PNGs in the MNG being written, e.g.,
10534 * convert *.png png8:animation.mng
10536 * To do: check -define png:bit_depth and png:color_type as well,
10537 * or perhaps use mng:bit_depth and mng:color_type instead for
10541 mng_info->write_png8=LocaleCompare(image_info->magick,"PNG8") == 0;
10542 mng_info->write_png24=LocaleCompare(image_info->magick,"PNG24") == 0;
10543 mng_info->write_png32=LocaleCompare(image_info->magick,"PNG32") == 0;
10545 write_jng=MagickFalse;
10546 if (image_info->compression == JPEGCompression)
10547 write_jng=MagickTrue;
10549 mng_info->adjoin=image_info->adjoin &&
10550 (GetNextImageInList(image) != (Image *) NULL) && write_mng;
10552 if (logging != MagickFalse)
10554 /* Log some info about the input */
10558 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10559 " Checking input image(s)");
10561 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10562 " Image_info depth: %.20g",(double) image_info->depth);
10564 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10565 " Type: %d",image_info->type);
10568 for (p=image; p != (Image *) NULL; p=GetNextImageInList(p))
10570 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10571 " Scene: %.20g",(double) scene++);
10573 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10574 " Image depth: %.20g",(double) p->depth);
10577 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10581 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10584 if (p->storage_class == PseudoClass)
10585 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10586 " Storage class: PseudoClass");
10589 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10590 " Storage class: DirectClass");
10593 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10594 " Number of colors: %.20g",(double) p->colors);
10597 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10598 " Number of colors: unspecified");
10600 if (mng_info->adjoin == MagickFalse)
10605 use_global_plte=MagickFalse;
10606 all_images_are_gray=MagickFalse;
10607 #ifdef PNG_WRITE_EMPTY_PLTE_SUPPORTED
10608 need_local_plte=MagickTrue;
10610 need_defi=MagickFalse;
10611 need_matte=MagickFalse;
10612 mng_info->framing_mode=1;
10613 mng_info->old_framing_mode=1;
10616 if (image_info->page != (char *) NULL)
10619 Determine image bounding box.
10621 SetGeometry(image,&mng_info->page);
10622 (void) ParseMetaGeometry(image_info->page,&mng_info->page.x,
10623 &mng_info->page.y,&mng_info->page.width,&mng_info->page.height);
10635 mng_info->page=image->page;
10636 need_geom=MagickTrue;
10637 if (mng_info->page.width || mng_info->page.height)
10638 need_geom=MagickFalse;
10640 Check all the scenes.
10642 initial_delay=image->delay;
10643 need_iterations=MagickFalse;
10644 mng_info->equal_chrms=image->chromaticity.red_primary.x != 0.0;
10645 mng_info->equal_physs=MagickTrue,
10646 mng_info->equal_gammas=MagickTrue;
10647 mng_info->equal_srgbs=MagickTrue;
10648 mng_info->equal_backgrounds=MagickTrue;
10650 #if defined(PNG_WRITE_EMPTY_PLTE_SUPPORTED) || \
10651 defined(PNG_MNG_FEATURES_SUPPORTED)
10652 all_images_are_gray=MagickTrue;
10653 mng_info->equal_palettes=MagickFalse;
10654 need_local_plte=MagickFalse;
10656 for (next_image=image; next_image != (Image *) NULL; )
10660 if ((next_image->columns+next_image->page.x) > mng_info->page.width)
10661 mng_info->page.width=next_image->columns+next_image->page.x;
10663 if ((next_image->rows+next_image->page.y) > mng_info->page.height)
10664 mng_info->page.height=next_image->rows+next_image->page.y;
10667 if (next_image->page.x || next_image->page.y)
10668 need_defi=MagickTrue;
10670 if (next_image->matte)
10671 need_matte=MagickTrue;
10673 if ((int) next_image->dispose >= BackgroundDispose)
10674 if (next_image->matte || next_image->page.x || next_image->page.y ||
10675 ((next_image->columns < mng_info->page.width) &&
10676 (next_image->rows < mng_info->page.height)))
10677 mng_info->need_fram=MagickTrue;
10679 if (next_image->iterations)
10680 need_iterations=MagickTrue;
10682 final_delay=next_image->delay;
10684 if (final_delay != initial_delay || final_delay > 1UL*
10685 next_image->ticks_per_second)
10686 mng_info->need_fram=1;
10688 #if defined(PNG_WRITE_EMPTY_PLTE_SUPPORTED) || \
10689 defined(PNG_MNG_FEATURES_SUPPORTED)
10691 check for global palette possibility.
10693 if (image->matte != MagickFalse)
10694 need_local_plte=MagickTrue;
10696 if (need_local_plte == 0)
10698 if (ImageIsGray(image) == MagickFalse)
10699 all_images_are_gray=MagickFalse;
10700 mng_info->equal_palettes=PalettesAreEqual(image,next_image);
10701 if (use_global_plte == 0)
10702 use_global_plte=mng_info->equal_palettes;
10703 need_local_plte=!mng_info->equal_palettes;
10706 if (GetNextImageInList(next_image) != (Image *) NULL)
10708 if (next_image->background_color.red !=
10709 next_image->next->background_color.red ||
10710 next_image->background_color.green !=
10711 next_image->next->background_color.green ||
10712 next_image->background_color.blue !=
10713 next_image->next->background_color.blue)
10714 mng_info->equal_backgrounds=MagickFalse;
10716 if (next_image->gamma != next_image->next->gamma)
10717 mng_info->equal_gammas=MagickFalse;
10719 if (next_image->rendering_intent !=
10720 next_image->next->rendering_intent)
10721 mng_info->equal_srgbs=MagickFalse;
10723 if ((next_image->units != next_image->next->units) ||
10724 (next_image->x_resolution != next_image->next->x_resolution) ||
10725 (next_image->y_resolution != next_image->next->y_resolution))
10726 mng_info->equal_physs=MagickFalse;
10728 if (mng_info->equal_chrms)
10730 if (next_image->chromaticity.red_primary.x !=
10731 next_image->next->chromaticity.red_primary.x ||
10732 next_image->chromaticity.red_primary.y !=
10733 next_image->next->chromaticity.red_primary.y ||
10734 next_image->chromaticity.green_primary.x !=
10735 next_image->next->chromaticity.green_primary.x ||
10736 next_image->chromaticity.green_primary.y !=
10737 next_image->next->chromaticity.green_primary.y ||
10738 next_image->chromaticity.blue_primary.x !=
10739 next_image->next->chromaticity.blue_primary.x ||
10740 next_image->chromaticity.blue_primary.y !=
10741 next_image->next->chromaticity.blue_primary.y ||
10742 next_image->chromaticity.white_point.x !=
10743 next_image->next->chromaticity.white_point.x ||
10744 next_image->chromaticity.white_point.y !=
10745 next_image->next->chromaticity.white_point.y)
10746 mng_info->equal_chrms=MagickFalse;
10750 next_image=GetNextImageInList(next_image);
10752 if (image_count < 2)
10754 mng_info->equal_backgrounds=MagickFalse;
10755 mng_info->equal_chrms=MagickFalse;
10756 mng_info->equal_gammas=MagickFalse;
10757 mng_info->equal_srgbs=MagickFalse;
10758 mng_info->equal_physs=MagickFalse;
10759 use_global_plte=MagickFalse;
10760 #ifdef PNG_WRITE_EMPTY_PLTE_SUPPORTED
10761 need_local_plte=MagickTrue;
10763 need_iterations=MagickFalse;
10766 if (mng_info->need_fram == MagickFalse)
10769 Only certain framing rates 100/n are exactly representable without
10770 the FRAM chunk but we'll allow some slop in VLC files
10772 if (final_delay == 0)
10774 if (need_iterations != MagickFalse)
10777 It's probably a GIF with loop; don't run it *too* fast.
10779 if (mng_info->adjoin)
10782 (void) ThrowMagickException(&image->exception,
10783 GetMagickModule(),CoderWarning,
10784 "input has zero delay between all frames; assuming",
10789 mng_info->ticks_per_second=0;
10791 if (final_delay != 0)
10792 mng_info->ticks_per_second=(png_uint_32)
10793 (image->ticks_per_second/final_delay);
10794 if (final_delay > 50)
10795 mng_info->ticks_per_second=2;
10797 if (final_delay > 75)
10798 mng_info->ticks_per_second=1;
10800 if (final_delay > 125)
10801 mng_info->need_fram=MagickTrue;
10803 if (need_defi && final_delay > 2 && (final_delay != 4) &&
10804 (final_delay != 5) && (final_delay != 10) && (final_delay != 20) &&
10805 (final_delay != 25) && (final_delay != 50) && (final_delay !=
10806 1UL*image->ticks_per_second))
10807 mng_info->need_fram=MagickTrue; /* make it exact; cannot be VLC */
10810 if (mng_info->need_fram != MagickFalse)
10811 mng_info->ticks_per_second=1UL*image->ticks_per_second;
10813 If pseudocolor, we should also check to see if all the
10814 palettes are identical and write a global PLTE if they are.
10818 Write the MNG version 1.0 signature and MHDR chunk.
10820 (void) WriteBlob(image,8,(const unsigned char *) "\212MNG\r\n\032\n");
10821 (void) WriteBlobMSBULong(image,28L); /* chunk data length=28 */
10822 PNGType(chunk,mng_MHDR);
10823 LogPNGChunk(logging,mng_MHDR,28L);
10824 PNGLong(chunk+4,(png_uint_32) mng_info->page.width);
10825 PNGLong(chunk+8,(png_uint_32) mng_info->page.height);
10826 PNGLong(chunk+12,mng_info->ticks_per_second);
10827 PNGLong(chunk+16,0L); /* layer count=unknown */
10828 PNGLong(chunk+20,0L); /* frame count=unknown */
10829 PNGLong(chunk+24,0L); /* play time=unknown */
10834 if (need_defi || mng_info->need_fram || use_global_plte)
10835 PNGLong(chunk+28,27L); /* simplicity=LC+JNG */
10838 PNGLong(chunk+28,25L); /* simplicity=VLC+JNG */
10843 if (need_defi || mng_info->need_fram || use_global_plte)
10844 PNGLong(chunk+28,19L); /* simplicity=LC+JNG, no transparency */
10847 PNGLong(chunk+28,17L); /* simplicity=VLC+JNG, no transparency */
10855 if (need_defi || mng_info->need_fram || use_global_plte)
10856 PNGLong(chunk+28,11L); /* simplicity=LC */
10859 PNGLong(chunk+28,9L); /* simplicity=VLC */
10864 if (need_defi || mng_info->need_fram || use_global_plte)
10865 PNGLong(chunk+28,3L); /* simplicity=LC, no transparency */
10868 PNGLong(chunk+28,1L); /* simplicity=VLC, no transparency */
10871 (void) WriteBlob(image,32,chunk);
10872 (void) WriteBlobMSBULong(image,crc32(0,chunk,32));
10873 option=GetImageOption(image_info,"mng:need-cacheoff");
10874 if (option != (const char *) NULL)
10880 Write "nEED CACHEOFF" to turn playback caching off for streaming MNG.
10882 PNGType(chunk,mng_nEED);
10883 length=CopyMagickString((char *) chunk+4,"CACHEOFF",20);
10884 (void) WriteBlobMSBULong(image,(size_t) length);
10885 LogPNGChunk(logging,mng_nEED,(size_t) length);
10887 (void) WriteBlob(image,length,chunk);
10888 (void) WriteBlobMSBULong(image,crc32(0,chunk,(uInt) length));
10890 if ((GetPreviousImageInList(image) == (Image *) NULL) &&
10891 (GetNextImageInList(image) != (Image *) NULL) &&
10892 (image->iterations != 1))
10895 Write MNG TERM chunk
10897 (void) WriteBlobMSBULong(image,10L); /* data length=10 */
10898 PNGType(chunk,mng_TERM);
10899 LogPNGChunk(logging,mng_TERM,10L);
10900 chunk[4]=3; /* repeat animation */
10901 chunk[5]=0; /* show last frame when done */
10902 PNGLong(chunk+6,(png_uint_32) (mng_info->ticks_per_second*
10903 final_delay/MagickMax(image->ticks_per_second,1)));
10905 if (image->iterations == 0)
10906 PNGLong(chunk+10,PNG_UINT_31_MAX);
10909 PNGLong(chunk+10,(png_uint_32) image->iterations);
10911 if (logging != MagickFalse)
10913 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10914 " TERM delay: %.20g",(double) (mng_info->ticks_per_second*
10915 final_delay/MagickMax(image->ticks_per_second,1)));
10917 if (image->iterations == 0)
10918 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10919 " TERM iterations: %.20g",(double) PNG_UINT_31_MAX);
10922 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10923 " Image iterations: %.20g",(double) image->iterations);
10925 (void) WriteBlob(image,14,chunk);
10926 (void) WriteBlobMSBULong(image,crc32(0,chunk,14));
10929 To do: check for cHRM+gAMA == sRGB, and write sRGB instead.
10931 if ((image->colorspace == sRGBColorspace || image->rendering_intent) &&
10932 mng_info->equal_srgbs)
10935 Write MNG sRGB chunk
10937 (void) WriteBlobMSBULong(image,1L);
10938 PNGType(chunk,mng_sRGB);
10939 LogPNGChunk(logging,mng_sRGB,1L);
10941 if (image->rendering_intent != UndefinedIntent)
10942 chunk[4]=(unsigned char)
10943 Magick_RenderingIntent_to_PNG_RenderingIntent(
10944 (image->rendering_intent));
10947 chunk[4]=(unsigned char)
10948 Magick_RenderingIntent_to_PNG_RenderingIntent(
10949 (PerceptualIntent));
10951 (void) WriteBlob(image,5,chunk);
10952 (void) WriteBlobMSBULong(image,crc32(0,chunk,5));
10953 mng_info->have_write_global_srgb=MagickTrue;
10958 if (image->gamma && mng_info->equal_gammas)
10961 Write MNG gAMA chunk
10963 (void) WriteBlobMSBULong(image,4L);
10964 PNGType(chunk,mng_gAMA);
10965 LogPNGChunk(logging,mng_gAMA,4L);
10966 PNGLong(chunk+4,(png_uint_32) (100000*image->gamma+0.5));
10967 (void) WriteBlob(image,8,chunk);
10968 (void) WriteBlobMSBULong(image,crc32(0,chunk,8));
10969 mng_info->have_write_global_gama=MagickTrue;
10971 if (mng_info->equal_chrms)
10977 Write MNG cHRM chunk
10979 (void) WriteBlobMSBULong(image,32L);
10980 PNGType(chunk,mng_cHRM);
10981 LogPNGChunk(logging,mng_cHRM,32L);
10982 primary=image->chromaticity.white_point;
10983 PNGLong(chunk+4,(png_uint_32) (100000*primary.x+0.5));
10984 PNGLong(chunk+8,(png_uint_32) (100000*primary.y+0.5));
10985 primary=image->chromaticity.red_primary;
10986 PNGLong(chunk+12,(png_uint_32) (100000*primary.x+0.5));
10987 PNGLong(chunk+16,(png_uint_32) (100000*primary.y+0.5));
10988 primary=image->chromaticity.green_primary;
10989 PNGLong(chunk+20,(png_uint_32) (100000*primary.x+0.5));
10990 PNGLong(chunk+24,(png_uint_32) (100000*primary.y+0.5));
10991 primary=image->chromaticity.blue_primary;
10992 PNGLong(chunk+28,(png_uint_32) (100000*primary.x+0.5));
10993 PNGLong(chunk+32,(png_uint_32) (100000*primary.y+0.5));
10994 (void) WriteBlob(image,36,chunk);
10995 (void) WriteBlobMSBULong(image,crc32(0,chunk,36));
10996 mng_info->have_write_global_chrm=MagickTrue;
10999 if (image->x_resolution && image->y_resolution && mng_info->equal_physs)
11002 Write MNG pHYs chunk
11004 (void) WriteBlobMSBULong(image,9L);
11005 PNGType(chunk,mng_pHYs);
11006 LogPNGChunk(logging,mng_pHYs,9L);
11008 if (image->units == PixelsPerInchResolution)
11010 PNGLong(chunk+4,(png_uint_32)
11011 (image->x_resolution*100.0/2.54+0.5));
11013 PNGLong(chunk+8,(png_uint_32)
11014 (image->y_resolution*100.0/2.54+0.5));
11021 if (image->units == PixelsPerCentimeterResolution)
11023 PNGLong(chunk+4,(png_uint_32)
11024 (image->x_resolution*100.0+0.5));
11026 PNGLong(chunk+8,(png_uint_32)
11027 (image->y_resolution*100.0+0.5));
11034 PNGLong(chunk+4,(png_uint_32) (image->x_resolution+0.5));
11035 PNGLong(chunk+8,(png_uint_32) (image->y_resolution+0.5));
11039 (void) WriteBlob(image,13,chunk);
11040 (void) WriteBlobMSBULong(image,crc32(0,chunk,13));
11043 Write MNG BACK chunk and global bKGD chunk, if the image is transparent
11044 or does not cover the entire frame.
11046 if (write_mng && (image->matte || image->page.x > 0 ||
11047 image->page.y > 0 || (image->page.width &&
11048 (image->page.width+image->page.x < mng_info->page.width))
11049 || (image->page.height && (image->page.height+image->page.y
11050 < mng_info->page.height))))
11052 (void) WriteBlobMSBULong(image,6L);
11053 PNGType(chunk,mng_BACK);
11054 LogPNGChunk(logging,mng_BACK,6L);
11055 red=ScaleQuantumToShort(image->background_color.red);
11056 green=ScaleQuantumToShort(image->background_color.green);
11057 blue=ScaleQuantumToShort(image->background_color.blue);
11058 PNGShort(chunk+4,red);
11059 PNGShort(chunk+6,green);
11060 PNGShort(chunk+8,blue);
11061 (void) WriteBlob(image,10,chunk);
11062 (void) WriteBlobMSBULong(image,crc32(0,chunk,10));
11063 if (mng_info->equal_backgrounds)
11065 (void) WriteBlobMSBULong(image,6L);
11066 PNGType(chunk,mng_bKGD);
11067 LogPNGChunk(logging,mng_bKGD,6L);
11068 (void) WriteBlob(image,10,chunk);
11069 (void) WriteBlobMSBULong(image,crc32(0,chunk,10));
11073 #ifdef PNG_WRITE_EMPTY_PLTE_SUPPORTED
11074 if ((need_local_plte == MagickFalse) &&
11075 (image->storage_class == PseudoClass) &&
11076 (all_images_are_gray == MagickFalse))
11082 Write MNG PLTE chunk
11084 data_length=3*image->colors;
11085 (void) WriteBlobMSBULong(image,data_length);
11086 PNGType(chunk,mng_PLTE);
11087 LogPNGChunk(logging,mng_PLTE,data_length);
11089 for (i=0; i < (ssize_t) image->colors; i++)
11091 chunk[4+i*3]=ScaleQuantumToChar(image->colormap[i].red) & 0xff;
11092 chunk[5+i*3]=ScaleQuantumToChar(image->colormap[i].green) & 0xff;
11093 chunk[6+i*3]=ScaleQuantumToChar(image->colormap[i].blue) & 0xff;
11096 (void) WriteBlob(image,data_length+4,chunk);
11097 (void) WriteBlobMSBULong(image,crc32(0,chunk,(uInt) (data_length+4)));
11098 mng_info->have_write_global_plte=MagickTrue;
11104 #if defined(PNG_WRITE_EMPTY_PLTE_SUPPORTED) || \
11105 defined(PNG_MNG_FEATURES_SUPPORTED)
11106 mng_info->equal_palettes=MagickFalse;
11110 if (mng_info->adjoin)
11112 #if defined(PNG_WRITE_EMPTY_PLTE_SUPPORTED) || \
11113 defined(PNG_MNG_FEATURES_SUPPORTED)
11115 If we aren't using a global palette for the entire MNG, check to
11116 see if we can use one for two or more consecutive images.
11118 if (need_local_plte && use_global_plte && !all_images_are_gray)
11120 if (mng_info->IsPalette)
11123 When equal_palettes is true, this image has the same palette
11124 as the previous PseudoClass image
11126 mng_info->have_write_global_plte=mng_info->equal_palettes;
11127 mng_info->equal_palettes=PalettesAreEqual(image,image->next);
11128 if (mng_info->equal_palettes && !mng_info->have_write_global_plte)
11131 Write MNG PLTE chunk
11136 data_length=3*image->colors;
11137 (void) WriteBlobMSBULong(image,data_length);
11138 PNGType(chunk,mng_PLTE);
11139 LogPNGChunk(logging,mng_PLTE,data_length);
11141 for (i=0; i < (ssize_t) image->colors; i++)
11143 chunk[4+i*3]=ScaleQuantumToChar(image->colormap[i].red);
11144 chunk[5+i*3]=ScaleQuantumToChar(image->colormap[i].green);
11145 chunk[6+i*3]=ScaleQuantumToChar(image->colormap[i].blue);
11148 (void) WriteBlob(image,data_length+4,chunk);
11149 (void) WriteBlobMSBULong(image,crc32(0,chunk,
11150 (uInt) (data_length+4)));
11151 mng_info->have_write_global_plte=MagickTrue;
11155 mng_info->have_write_global_plte=MagickFalse;
11166 previous_x=mng_info->page.x;
11167 previous_y=mng_info->page.y;
11174 mng_info->page=image->page;
11175 if ((mng_info->page.x != previous_x) ||
11176 (mng_info->page.y != previous_y))
11178 (void) WriteBlobMSBULong(image,12L); /* data length=12 */
11179 PNGType(chunk,mng_DEFI);
11180 LogPNGChunk(logging,mng_DEFI,12L);
11181 chunk[4]=0; /* object 0 MSB */
11182 chunk[5]=0; /* object 0 LSB */
11183 chunk[6]=0; /* visible */
11184 chunk[7]=0; /* abstract */
11185 PNGLong(chunk+8,(png_uint_32) mng_info->page.x);
11186 PNGLong(chunk+12,(png_uint_32) mng_info->page.y);
11187 (void) WriteBlob(image,16,chunk);
11188 (void) WriteBlobMSBULong(image,crc32(0,chunk,16));
11193 mng_info->write_mng=write_mng;
11195 if ((int) image->dispose >= 3)
11196 mng_info->framing_mode=3;
11198 if (mng_info->need_fram && mng_info->adjoin &&
11199 ((image->delay != mng_info->delay) ||
11200 (mng_info->framing_mode != mng_info->old_framing_mode)))
11202 if (image->delay == mng_info->delay)
11205 Write a MNG FRAM chunk with the new framing mode.
11207 (void) WriteBlobMSBULong(image,1L); /* data length=1 */
11208 PNGType(chunk,mng_FRAM);
11209 LogPNGChunk(logging,mng_FRAM,1L);
11210 chunk[4]=(unsigned char) mng_info->framing_mode;
11211 (void) WriteBlob(image,5,chunk);
11212 (void) WriteBlobMSBULong(image,crc32(0,chunk,5));
11217 Write a MNG FRAM chunk with the delay.
11219 (void) WriteBlobMSBULong(image,10L); /* data length=10 */
11220 PNGType(chunk,mng_FRAM);
11221 LogPNGChunk(logging,mng_FRAM,10L);
11222 chunk[4]=(unsigned char) mng_info->framing_mode;
11223 chunk[5]=0; /* frame name separator (no name) */
11224 chunk[6]=2; /* flag for changing default delay */
11225 chunk[7]=0; /* flag for changing frame timeout */
11226 chunk[8]=0; /* flag for changing frame clipping */
11227 chunk[9]=0; /* flag for changing frame sync_id */
11228 PNGLong(chunk+10,(png_uint_32)
11229 ((mng_info->ticks_per_second*
11230 image->delay)/MagickMax(image->ticks_per_second,1)));
11231 (void) WriteBlob(image,14,chunk);
11232 (void) WriteBlobMSBULong(image,crc32(0,chunk,14));
11233 mng_info->delay=(png_uint_32) image->delay;
11235 mng_info->old_framing_mode=mng_info->framing_mode;
11238 #if defined(JNG_SUPPORTED)
11239 if (image_info->compression == JPEGCompression)
11244 if (logging != MagickFalse)
11245 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11246 " Writing JNG object.");
11247 /* To do: specify the desired alpha compression method. */
11248 write_info=CloneImageInfo(image_info);
11249 write_info->compression=UndefinedCompression;
11250 status=WriteOneJNGImage(mng_info,write_info,image);
11251 write_info=DestroyImageInfo(write_info);
11256 if (logging != MagickFalse)
11257 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11258 " Writing PNG object.");
11260 mng_info->need_blob = MagickFalse;
11262 /* We don't want any ancillary chunks written */
11263 mng_info->ping_exclude_bKGD=MagickTrue;
11264 mng_info->ping_exclude_cHRM=MagickTrue;
11265 mng_info->ping_exclude_EXIF=MagickTrue;
11266 mng_info->ping_exclude_gAMA=MagickTrue;
11267 mng_info->ping_exclude_cHRM=MagickTrue;
11268 mng_info->ping_exclude_iCCP=MagickTrue;
11269 /* mng_info->ping_exclude_iTXt=MagickTrue; */
11270 mng_info->ping_exclude_oFFs=MagickTrue;
11271 mng_info->ping_exclude_pHYs=MagickTrue;
11272 mng_info->ping_exclude_sRGB=MagickTrue;
11273 mng_info->ping_exclude_tEXt=MagickTrue;
11274 mng_info->ping_exclude_tRNS=MagickTrue;
11275 mng_info->ping_exclude_vpAg=MagickTrue;
11276 mng_info->ping_exclude_zCCP=MagickTrue;
11277 mng_info->ping_exclude_zTXt=MagickTrue;
11279 status=WriteOnePNGImage(mng_info,image_info,image);
11282 if (status == MagickFalse)
11284 MngInfoFreeStruct(mng_info,&have_mng_structure);
11285 (void) CloseBlob(image);
11286 return(MagickFalse);
11288 (void) CatchImageException(image);
11289 if (GetNextImageInList(image) == (Image *) NULL)
11291 image=SyncNextImageInList(image);
11292 status=SetImageProgress(image,SaveImagesTag,scene++,
11293 GetImageListLength(image));
11295 if (status == MagickFalse)
11298 } while (mng_info->adjoin);
11302 while (GetPreviousImageInList(image) != (Image *) NULL)
11303 image=GetPreviousImageInList(image);
11305 Write the MEND chunk.
11307 (void) WriteBlobMSBULong(image,0x00000000L);
11308 PNGType(chunk,mng_MEND);
11309 LogPNGChunk(logging,mng_MEND,0L);
11310 (void) WriteBlob(image,4,chunk);
11311 (void) WriteBlobMSBULong(image,crc32(0,chunk,4));
11314 Relinquish resources.
11316 (void) CloseBlob(image);
11317 MngInfoFreeStruct(mng_info,&have_mng_structure);
11319 if (logging != MagickFalse)
11320 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"exit WriteMNGImage()");
11322 return(MagickTrue);
11324 #else /* PNG_LIBPNG_VER > 10011 */
11326 static MagickBooleanType WritePNGImage(const ImageInfo *image_info,Image *image)
11329 printf("Your PNG library is too old: You have libpng-%s\n",
11330 PNG_LIBPNG_VER_STRING);
11332 ThrowBinaryException(CoderError,"PNG library is too old",
11333 image_info->filename);
11336 static MagickBooleanType WriteMNGImage(const ImageInfo *image_info,Image *image)
11338 return(WritePNGImage(image_info,image));
11340 #endif /* PNG_LIBPNG_VER > 10011 */