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 /* A warning about deprecated use of jmpbuf here is unavoidable if you
1349 * are building with libpng-1.4.x and can be ignored.
1351 longjmp(ping->jmpbuf,1);
1353 png_longjmp(ping,1);
1357 static void MagickPNGWarningHandler(png_struct *ping,png_const_charp message)
1362 if (LocaleCompare(message, "Missing PLTE before tRNS") == 0)
1363 png_error(ping, message);
1365 image=(Image *) png_get_error_ptr(ping);
1366 if (image->debug != MagickFalse)
1367 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1368 " libpng-%s warning: %s", PNG_LIBPNG_VER_STRING,message);
1370 (void) ThrowMagickException(&image->exception,GetMagickModule(),CoderWarning,
1371 message,"`%s'",image->filename);
1374 #ifdef PNG_USER_MEM_SUPPORTED
1375 static png_voidp Magick_png_malloc(png_structp png_ptr,png_uint_32 size)
1377 #if (PNG_LIBPNG_VER < 10011)
1382 ret=((png_voidp) AcquireMagickMemory((size_t) size));
1385 png_error("Insufficient memory.");
1390 return((png_voidp) AcquireMagickMemory((size_t) size));
1395 Free a pointer. It is removed from the list at the same time.
1397 static png_free_ptr Magick_png_free(png_structp png_ptr,png_voidp ptr)
1400 ptr=RelinquishMagickMemory(ptr);
1401 return((png_free_ptr) NULL);
1405 #if defined(__cplusplus) || defined(c_plusplus)
1410 Magick_png_read_raw_profile(Image *image, const ImageInfo *image_info,
1411 png_textp text,int ii)
1416 register unsigned char
1430 unhex[103]={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,0,0,0,
1432 0,0,0,0,0,0,0,0,0,1, 2,3,4,5,6,7,8,9,0,0,
1433 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,
1434 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,10,11,12,
1438 /* look for newline */
1442 /* look for length */
1443 while (*sp == '\0' || *sp == ' ' || *sp == '\n')
1446 length=(png_uint_32) StringToLong(sp);
1448 while (*sp != ' ' && *sp != '\n')
1451 /* allocate space */
1454 (void) ThrowMagickException(&image->exception,GetMagickModule(),
1455 CoderWarning,"UnableToCopyProfile","`%s'","invalid profile length");
1456 return(MagickFalse);
1459 profile=AcquireStringInfo(length);
1461 if (profile == (StringInfo *) NULL)
1463 (void) ThrowMagickException(&image->exception,GetMagickModule(),
1464 ResourceLimitError,"MemoryAllocationFailed","`%s'",
1465 "unable to copy profile");
1466 return(MagickFalse);
1469 /* copy profile, skipping white space and column 1 "=" signs */
1470 dp=GetStringInfoDatum(profile);
1473 for (i=0; i < (ssize_t) nibbles; i++)
1475 while (*sp < '0' || (*sp > '9' && *sp < 'a') || *sp > 'f')
1479 (void) ThrowMagickException(&image->exception,GetMagickModule(),
1480 CoderWarning,"UnableToCopyProfile","`%s'","ran out of data");
1481 profile=DestroyStringInfo(profile);
1482 return(MagickFalse);
1488 *dp=(unsigned char) (16*unhex[(int) *sp++]);
1491 (*dp++)+=unhex[(int) *sp++];
1494 We have already read "Raw profile type.
1496 (void) SetImageProfile(image,&text[ii].key[17],profile);
1497 profile=DestroyStringInfo(profile);
1499 if (image_info->verbose)
1500 (void) printf(" Found a generic profile, type %s\n",&text[ii].key[17]);
1505 #if defined(PNG_UNKNOWN_CHUNKS_SUPPORTED)
1506 static int read_vpag_chunk_callback(png_struct *ping, png_unknown_chunkp chunk)
1512 /* The unknown chunk structure contains the chunk data:
1517 Note that libpng has already taken care of the CRC handling.
1521 if (chunk->name[0] != 118 || chunk->name[1] != 112 ||
1522 chunk->name[2] != 65 ||chunk-> name[3] != 103)
1523 return(0); /* Did not recognize */
1525 /* recognized vpAg */
1527 if (chunk->size != 9)
1528 return(-1); /* Error return */
1530 if (chunk->data[8] != 0)
1531 return(0); /* ImageMagick requires pixel units */
1533 image=(Image *) png_get_user_chunk_ptr(ping);
1535 image->page.width=(size_t) ((chunk->data[0] << 24) |
1536 (chunk->data[1] << 16) | (chunk->data[2] << 8) | chunk->data[3]);
1538 image->page.height=(size_t) ((chunk->data[4] << 24) |
1539 (chunk->data[5] << 16) | (chunk->data[6] << 8) | chunk->data[7]);
1541 /* Return one of the following: */
1542 /* return(-n); chunk had an error */
1543 /* return(0); did not recognize */
1544 /* return(n); success */
1552 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1556 % R e a d O n e P N G I m a g e %
1560 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1562 % ReadOnePNGImage() reads a Portable Network Graphics (PNG) image file
1563 % (minus the 8-byte signature) and returns it. It allocates the memory
1564 % necessary for the new Image structure and returns a pointer to the new
1567 % The format of the ReadOnePNGImage method is:
1569 % Image *ReadOnePNGImage(MngInfo *mng_info, const ImageInfo *image_info,
1570 % ExceptionInfo *exception)
1572 % A description of each parameter follows:
1574 % o mng_info: Specifies a pointer to a MngInfo structure.
1576 % o image_info: the image info.
1578 % o exception: return any errors or warnings in this structure.
1581 static Image *ReadOnePNGImage(MngInfo *mng_info,
1582 const ImageInfo *image_info, ExceptionInfo *exception)
1584 /* Read one PNG image */
1595 ping_interlace_method,
1596 ping_compression_method,
1638 register unsigned char
1641 register IndexPacket
1648 register PixelPacket
1655 #if defined(PNG_UNKNOWN_CHUNKS_SUPPORTED)
1656 png_byte unused_chunks[]=
1658 104, 73, 83, 84, (png_byte) '\0', /* hIST */
1659 105, 84, 88, 116, (png_byte) '\0', /* iTXt */
1660 112, 67, 65, 76, (png_byte) '\0', /* pCAL */
1661 115, 67, 65, 76, (png_byte) '\0', /* sCAL */
1662 115, 80, 76, 84, (png_byte) '\0', /* sPLT */
1663 116, 73, 77, 69, (png_byte) '\0', /* tIME */
1667 logging=LogMagickEvent(CoderEvent,GetMagickModule(),
1668 " enter ReadOnePNGImage()");
1670 #if defined(PNG_SETJMP_NOT_THREAD_SAFE)
1671 LockSemaphoreInfo(ping_semaphore);
1674 #if (PNG_LIBPNG_VER < 10200)
1675 if (image_info->verbose)
1676 printf("Your PNG library (libpng-%s) is rather old.\n",
1677 PNG_LIBPNG_VER_STRING);
1680 #if (PNG_LIBPNG_VER >= 10400)
1681 # ifndef PNG_TRANSFORM_GRAY_TO_RGB /* Added at libpng-1.4.0beta67 */
1682 if (image_info->verbose)
1684 printf("Your PNG library (libpng-%s) is an old beta version.\n",
1685 PNG_LIBPNG_VER_STRING);
1686 printf("Please update it.\n");
1692 quantum_info = (QuantumInfo *) NULL;
1693 image=mng_info->image;
1695 if (logging != MagickFalse)
1696 (void)LogMagickEvent(CoderEvent,GetMagickModule(),
1697 " image->matte=%d",(int) image->matte);
1699 /* Set to an out-of-range color unless tRNS chunk is present */
1700 transparent_color.red=65537;
1701 transparent_color.green=65537;
1702 transparent_color.blue=65537;
1703 transparent_color.opacity=65537;
1706 Allocate the PNG structures
1708 #ifdef PNG_USER_MEM_SUPPORTED
1709 ping=png_create_read_struct_2(PNG_LIBPNG_VER_STRING, image,
1710 MagickPNGErrorHandler,MagickPNGWarningHandler, NULL,
1711 (png_malloc_ptr) Magick_png_malloc,(png_free_ptr) Magick_png_free);
1713 ping=png_create_read_struct(PNG_LIBPNG_VER_STRING,image,
1714 MagickPNGErrorHandler,MagickPNGWarningHandler);
1716 if (ping == (png_struct *) NULL)
1717 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1719 ping_info=png_create_info_struct(ping);
1721 if (ping_info == (png_info *) NULL)
1723 png_destroy_read_struct(&ping,(png_info **) NULL,(png_info **) NULL);
1724 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1727 end_info=png_create_info_struct(ping);
1729 if (end_info == (png_info *) NULL)
1731 png_destroy_read_struct(&ping,&ping_info,(png_info **) NULL);
1732 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1735 ping_pixels=(unsigned char *) NULL;
1737 if (setjmp(png_jmpbuf(ping)))
1740 PNG image is corrupt.
1742 png_destroy_read_struct(&ping,&ping_info,&end_info);
1743 #if defined(PNG_SETJMP_NOT_THREAD_SAFE)
1744 UnlockSemaphoreInfo(ping_semaphore);
1746 if (logging != MagickFalse)
1747 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1748 " exit ReadOnePNGImage() with error.");
1750 if (image != (Image *) NULL)
1752 InheritException(exception,&image->exception);
1756 return(GetFirstImageInList(image));
1759 Prepare PNG for reading.
1762 mng_info->image_found++;
1763 png_set_sig_bytes(ping,8);
1765 if (LocaleCompare(image_info->magick,"MNG") == 0)
1767 #if defined(PNG_MNG_FEATURES_SUPPORTED)
1768 (void) png_permit_mng_features(ping,PNG_ALL_MNG_FEATURES);
1769 png_set_read_fn(ping,image,png_get_data);
1771 #if defined(PNG_READ_EMPTY_PLTE_SUPPORTED)
1772 png_permit_empty_plte(ping,MagickTrue);
1773 png_set_read_fn(ping,image,png_get_data);
1775 mng_info->image=image;
1776 mng_info->bytes_in_read_buffer=0;
1777 mng_info->found_empty_plte=MagickFalse;
1778 mng_info->have_saved_bkgd_index=MagickFalse;
1779 png_set_read_fn(ping,mng_info,mng_get_data);
1785 png_set_read_fn(ping,image,png_get_data);
1787 #if defined(PNG_UNKNOWN_CHUNKS_SUPPORTED)
1788 /* Ignore unused chunks and all unknown chunks except for vpAg */
1789 png_set_keep_unknown_chunks(ping, 1, NULL, 0);
1790 png_set_keep_unknown_chunks(ping, 2, mng_vpAg, 1);
1791 png_set_keep_unknown_chunks(ping, 1, unused_chunks,
1792 (int)sizeof(unused_chunks)/5);
1793 /* Callback for other unknown chunks */
1794 png_set_read_user_chunk_fn(ping, image, read_vpag_chunk_callback);
1797 #if (PNG_LIBPNG_VER < 10400)
1798 # if defined(PNG_USE_PNGGCCRD) && defined(PNG_ASSEMBLER_CODE_SUPPORTED) && \
1799 (PNG_LIBPNG_VER >= 10200) && (PNG_LIBPNG_VER < 10220) && defined(__i386__)
1800 /* Disable thread-unsafe features of pnggccrd */
1801 if (png_access_version_number() >= 10200)
1803 png_uint_32 mmx_disable_mask=0;
1804 png_uint_32 asm_flags;
1806 mmx_disable_mask |= ( PNG_ASM_FLAG_MMX_READ_COMBINE_ROW \
1807 | PNG_ASM_FLAG_MMX_READ_FILTER_SUB \
1808 | PNG_ASM_FLAG_MMX_READ_FILTER_AVG \
1809 | PNG_ASM_FLAG_MMX_READ_FILTER_PAETH );
1810 asm_flags=png_get_asm_flags(ping);
1811 png_set_asm_flags(ping, asm_flags & ~mmx_disable_mask);
1816 png_read_info(ping,ping_info);
1818 png_get_IHDR(ping,ping_info,&ping_width,&ping_height,
1819 &ping_bit_depth,&ping_color_type,
1820 &ping_interlace_method,&ping_compression_method,
1821 &ping_filter_method);
1823 (void) png_get_tRNS(ping, ping_info, &ping_trans_alpha, &ping_num_trans,
1826 (void) png_get_bKGD(ping, ping_info, &ping_background);
1828 if (ping_bit_depth < 8)
1830 if (((int) ping_color_type == PNG_COLOR_TYPE_PALETTE))
1832 png_set_packing(ping);
1837 image->depth=ping_bit_depth;
1838 image->depth=GetImageQuantumDepth(image,MagickFalse);
1839 image->interlace=ping_interlace_method != 0 ? PNGInterlace : NoInterlace;
1840 if (logging != MagickFalse)
1842 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1843 " PNG width: %.20g, height: %.20g",
1844 (double) ping_width, (double) ping_height);
1846 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1847 " PNG color_type: %d, bit_depth: %d",
1848 ping_color_type, ping_bit_depth);
1850 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1851 " PNG compression_method: %d",
1852 ping_compression_method);
1854 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1855 " PNG interlace_method: %d, filter_method: %d",
1856 ping_interlace_method,ping_filter_method);
1859 #ifdef PNG_READ_iCCP_SUPPORTED
1860 if (png_get_valid(ping,ping_info,PNG_INFO_iCCP))
1865 #if (PNG_LIBPNG_VER < 10500)
1879 (void) png_get_iCCP(ping,ping_info,&name,(int *) &compression,&info,
1882 if (profile_length != 0)
1887 if (logging != MagickFalse)
1888 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1889 " Reading PNG iCCP chunk.");
1890 profile=AcquireStringInfo(profile_length);
1891 SetStringInfoDatum(profile,(const unsigned char *) info);
1892 (void) SetImageProfile(image,"icc",profile);
1893 profile=DestroyStringInfo(profile);
1897 #if defined(PNG_READ_sRGB_SUPPORTED)
1902 if (mng_info->have_global_srgb)
1903 image->rendering_intent=Magick_RenderingIntent_from_PNG_RenderingIntent
1904 (mng_info->global_srgb_intent);
1906 if (png_get_sRGB(ping,ping_info,&intent))
1908 image->rendering_intent=Magick_RenderingIntent_from_PNG_RenderingIntent
1911 if (logging != MagickFalse)
1912 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1913 " Reading PNG sRGB chunk: rendering_intent: %d",intent);
1921 if (!png_get_gAMA(ping,ping_info,&file_gamma))
1922 if (mng_info->have_global_gama)
1923 png_set_gAMA(ping,ping_info,mng_info->global_gamma);
1925 if (png_get_gAMA(ping,ping_info,&file_gamma))
1927 image->gamma=(float) file_gamma;
1928 if (logging != MagickFalse)
1929 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1930 " Reading PNG gAMA chunk: gamma: %f",file_gamma);
1933 if (!png_get_valid(ping,ping_info,PNG_INFO_cHRM))
1935 if (mng_info->have_global_chrm != MagickFalse)
1937 (void) png_set_cHRM(ping,ping_info,
1938 mng_info->global_chrm.white_point.x,
1939 mng_info->global_chrm.white_point.y,
1940 mng_info->global_chrm.red_primary.x,
1941 mng_info->global_chrm.red_primary.y,
1942 mng_info->global_chrm.green_primary.x,
1943 mng_info->global_chrm.green_primary.y,
1944 mng_info->global_chrm.blue_primary.x,
1945 mng_info->global_chrm.blue_primary.y);
1949 if (png_get_valid(ping,ping_info,PNG_INFO_cHRM))
1951 (void) png_get_cHRM(ping,ping_info,
1952 &image->chromaticity.white_point.x,
1953 &image->chromaticity.white_point.y,
1954 &image->chromaticity.red_primary.x,
1955 &image->chromaticity.red_primary.y,
1956 &image->chromaticity.green_primary.x,
1957 &image->chromaticity.green_primary.y,
1958 &image->chromaticity.blue_primary.x,
1959 &image->chromaticity.blue_primary.y);
1961 if (logging != MagickFalse)
1962 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1963 " Reading PNG cHRM chunk.");
1966 if (image->rendering_intent != UndefinedIntent)
1968 png_set_sRGB(ping,ping_info,
1969 Magick_RenderingIntent_to_PNG_RenderingIntent
1970 (image->rendering_intent));
1971 png_set_gAMA(ping,ping_info,0.45455f);
1972 png_set_cHRM(ping,ping_info,
1973 0.6400f, 0.3300f, 0.3000f, 0.6000f,
1974 0.1500f, 0.0600f, 0.3127f, 0.3290f);
1976 #if defined(PNG_oFFs_SUPPORTED)
1977 if (png_get_valid(ping,ping_info,PNG_INFO_oFFs))
1979 image->page.x=png_get_x_offset_pixels(ping, ping_info);
1980 image->page.y=png_get_y_offset_pixels(ping, ping_info);
1982 if (logging != MagickFalse)
1983 if (image->page.x || image->page.y)
1984 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1985 " Reading PNG oFFs chunk: x: %.20g, y: %.20g.",(double)
1986 image->page.x,(double) image->page.y);
1989 #if defined(PNG_pHYs_SUPPORTED)
1990 if (!png_get_valid(ping,ping_info,PNG_INFO_pHYs))
1992 if (mng_info->have_global_phys)
1994 png_set_pHYs(ping,ping_info,
1995 mng_info->global_x_pixels_per_unit,
1996 mng_info->global_y_pixels_per_unit,
1997 mng_info->global_phys_unit_type);
2001 if (png_get_valid(ping,ping_info,PNG_INFO_pHYs))
2011 Set image resolution.
2013 (void) png_get_pHYs(ping,ping_info,&x_resolution,&y_resolution,
2015 image->x_resolution=(double) x_resolution;
2016 image->y_resolution=(double) y_resolution;
2018 if (unit_type == PNG_RESOLUTION_METER)
2020 image->units=PixelsPerCentimeterResolution;
2021 image->x_resolution=(double) x_resolution/100.0;
2022 image->y_resolution=(double) y_resolution/100.0;
2025 if (logging != MagickFalse)
2026 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2027 " Reading PNG pHYs chunk: xres: %.20g, yres: %.20g, units: %d.",
2028 (double) x_resolution,(double) y_resolution,unit_type);
2031 if (png_get_valid(ping,ping_info,PNG_INFO_PLTE))
2039 (void) png_get_PLTE(ping,ping_info,&palette,&number_colors);
2041 if ((number_colors == 0) &&
2042 ((int) ping_color_type == PNG_COLOR_TYPE_PALETTE))
2044 if (mng_info->global_plte_length)
2046 png_set_PLTE(ping,ping_info,mng_info->global_plte,
2047 (int) mng_info->global_plte_length);
2049 if (!png_get_valid(ping,ping_info,PNG_INFO_tRNS))
2050 if (mng_info->global_trns_length)
2052 if (mng_info->global_trns_length >
2053 mng_info->global_plte_length)
2054 (void) ThrowMagickException(&image->exception,
2055 GetMagickModule(),CoderError,
2056 "global tRNS has more entries than global PLTE",
2057 "`%s'",image_info->filename);
2058 png_set_tRNS(ping,ping_info,mng_info->global_trns,
2059 (int) mng_info->global_trns_length,NULL);
2061 #if defined(PNG_READ_bKGD_SUPPORTED)
2063 #ifndef PNG_READ_EMPTY_PLTE_SUPPORTED
2064 mng_info->have_saved_bkgd_index ||
2066 png_get_valid(ping,ping_info,PNG_INFO_bKGD))
2071 #ifndef PNG_READ_EMPTY_PLTE_SUPPORTED
2072 if (mng_info->have_saved_bkgd_index)
2073 background.index=mng_info->saved_bkgd_index;
2075 if (png_get_valid(ping, ping_info, PNG_INFO_bKGD))
2076 background.index=ping_background->index;
2078 background.red=(png_uint_16)
2079 mng_info->global_plte[background.index].red;
2081 background.green=(png_uint_16)
2082 mng_info->global_plte[background.index].green;
2084 background.blue=(png_uint_16)
2085 mng_info->global_plte[background.index].blue;
2087 png_set_bKGD(ping,ping_info,&background);
2092 (void) ThrowMagickException(&image->exception,GetMagickModule(),
2093 CoderError,"No global PLTE in file","`%s'",
2094 image_info->filename);
2098 #if defined(PNG_READ_bKGD_SUPPORTED)
2099 if (mng_info->have_global_bkgd &&
2100 (!png_get_valid(ping,ping_info,PNG_INFO_bKGD)))
2101 image->background_color=mng_info->mng_global_bkgd;
2103 if (png_get_valid(ping,ping_info,PNG_INFO_bKGD))
2106 Set image background color.
2108 if (logging != MagickFalse)
2109 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2110 " Reading PNG bKGD chunk.");
2112 if (ping_bit_depth == MAGICKCORE_QUANTUM_DEPTH)
2114 image->background_color.red=ping_background->red;
2115 image->background_color.green=ping_background->green;
2116 image->background_color.blue=ping_background->blue;
2119 else /* Scale background components to 16-bit */
2124 if (logging != MagickFalse)
2125 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2126 " raw ping_background=(%d,%d,%d).",ping_background->red,
2127 ping_background->green,ping_background->blue);
2131 if (ping_bit_depth == 1)
2134 else if (ping_bit_depth == 2)
2137 else if (ping_bit_depth == 4)
2140 if (ping_bit_depth <= 8)
2143 ping_background->red *= bkgd_scale;
2144 ping_background->green *= bkgd_scale;
2145 ping_background->blue *= bkgd_scale;
2147 if (logging != MagickFalse)
2149 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2150 " bkgd_scale=%d.",bkgd_scale);
2152 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2153 " ping_background=(%d,%d,%d).",ping_background->red,
2154 ping_background->green,ping_background->blue);
2157 image->background_color.red=
2158 ScaleShortToQuantum(ping_background->red);
2160 image->background_color.green=
2161 ScaleShortToQuantum(ping_background->green);
2163 image->background_color.blue=
2164 ScaleShortToQuantum(ping_background->blue);
2166 image->background_color.opacity=OpaqueOpacity;
2168 if (logging != MagickFalse)
2169 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2170 " image->background_color=(%.20g,%.20g,%.20g).",
2171 (double) image->background_color.red,
2172 (double) image->background_color.green,
2173 (double) image->background_color.blue);
2178 if (png_get_valid(ping,ping_info,PNG_INFO_tRNS))
2181 Image has a tRNS chunk.
2189 if (logging != MagickFalse)
2190 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2191 " Reading PNG tRNS chunk.");
2193 max_sample = (int) ((one << ping_bit_depth) - 1);
2195 if ((ping_color_type == PNG_COLOR_TYPE_GRAY &&
2196 (int)ping_trans_color->gray > max_sample) ||
2197 (ping_color_type == PNG_COLOR_TYPE_RGB &&
2198 ((int)ping_trans_color->red > max_sample ||
2199 (int)ping_trans_color->green > max_sample ||
2200 (int)ping_trans_color->blue > max_sample)))
2202 if (logging != MagickFalse)
2203 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2204 " Ignoring PNG tRNS chunk with out-of-range sample.");
2205 png_free_data(ping, ping_info, PNG_FREE_TRNS, 0);
2206 png_set_invalid(ping,ping_info,PNG_INFO_tRNS);
2207 image->matte=MagickFalse;
2214 scale_to_short = 65535L/((1UL << ping_bit_depth)-1);
2216 /* Scale transparent_color to short */
2217 transparent_color.red= scale_to_short*ping_trans_color->red;
2218 transparent_color.green= scale_to_short*ping_trans_color->green;
2219 transparent_color.blue= scale_to_short*ping_trans_color->blue;
2220 transparent_color.opacity= scale_to_short*ping_trans_color->gray;
2222 if (ping_color_type == PNG_COLOR_TYPE_GRAY)
2224 if (logging != MagickFalse)
2226 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2227 " Raw tRNS graylevel is %d.",ping_trans_color->gray);
2229 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2230 " scaled graylevel is %d.",transparent_color.opacity);
2232 transparent_color.red=transparent_color.opacity;
2233 transparent_color.green=transparent_color.opacity;
2234 transparent_color.blue=transparent_color.opacity;
2238 #if defined(PNG_READ_sBIT_SUPPORTED)
2239 if (mng_info->have_global_sbit)
2241 if (!png_get_valid(ping,ping_info,PNG_INFO_sBIT))
2242 png_set_sBIT(ping,ping_info,&mng_info->global_sbit);
2245 num_passes=png_set_interlace_handling(ping);
2247 png_read_update_info(ping,ping_info);
2249 ping_rowbytes=png_get_rowbytes(ping,ping_info);
2252 Initialize image structure.
2254 mng_info->image_box.left=0;
2255 mng_info->image_box.right=(ssize_t) ping_width;
2256 mng_info->image_box.top=0;
2257 mng_info->image_box.bottom=(ssize_t) ping_height;
2258 if (mng_info->mng_type == 0)
2260 mng_info->mng_width=ping_width;
2261 mng_info->mng_height=ping_height;
2262 mng_info->frame=mng_info->image_box;
2263 mng_info->clip=mng_info->image_box;
2268 image->page.y=mng_info->y_off[mng_info->object_id];
2271 image->compression=ZipCompression;
2272 image->columns=ping_width;
2273 image->rows=ping_height;
2274 if (((int) ping_color_type == PNG_COLOR_TYPE_PALETTE) ||
2275 ((int) ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA) ||
2276 ((int) ping_color_type == PNG_COLOR_TYPE_GRAY))
2281 image->storage_class=PseudoClass;
2283 image->colors=one << ping_bit_depth;
2284 #if (MAGICKCORE_QUANTUM_DEPTH == 8)
2285 if (image->colors > 256)
2288 if (image->colors > 65536L)
2289 image->colors=65536L;
2291 if ((int) ping_color_type == PNG_COLOR_TYPE_PALETTE)
2299 (void) png_get_PLTE(ping,ping_info,&palette,&number_colors);
2300 image->colors=(size_t) number_colors;
2302 if (logging != MagickFalse)
2303 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2304 " Reading PNG PLTE chunk: number_colors: %d.",number_colors);
2308 if (image->storage_class == PseudoClass)
2311 Initialize image colormap.
2313 if (AcquireImageColormap(image,image->colors) == MagickFalse)
2314 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
2316 if ((int) ping_color_type == PNG_COLOR_TYPE_PALETTE)
2324 (void) png_get_PLTE(ping,ping_info,&palette,&number_colors);
2326 for (i=0; i < (ssize_t) image->colors; i++)
2328 image->colormap[i].red=ScaleCharToQuantum(palette[i].red);
2329 image->colormap[i].green=ScaleCharToQuantum(palette[i].green);
2330 image->colormap[i].blue=ScaleCharToQuantum(palette[i].blue);
2339 scale=(QuantumRange/((1UL << ping_bit_depth)-1));
2344 for (i=0; i < (ssize_t) image->colors; i++)
2346 image->colormap[i].red=(Quantum) (i*scale);
2347 image->colormap[i].green=(Quantum) (i*scale);
2348 image->colormap[i].blue=(Quantum) (i*scale);
2353 Read image scanlines.
2355 if (image->delay != 0)
2356 mng_info->scenes_found++;
2358 if ((mng_info->mng_type == 0 && (image->ping != MagickFalse)) || (
2359 (image_info->number_scenes != 0) && (mng_info->scenes_found > (ssize_t)
2360 (image_info->first_scene+image_info->number_scenes))))
2362 if (logging != MagickFalse)
2363 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2364 " Skipping PNG image data for scene %.20g",(double)
2365 mng_info->scenes_found-1);
2366 png_destroy_read_struct(&ping,&ping_info,&end_info);
2367 #if defined(PNG_SETJMP_NOT_THREAD_SAFE)
2368 UnlockSemaphoreInfo(ping_semaphore);
2370 if (logging != MagickFalse)
2371 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2372 " exit ReadOnePNGImage().");
2377 if (logging != MagickFalse)
2378 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2379 " Reading PNG IDAT chunk(s)");
2382 ping_pixels=(unsigned char *) AcquireQuantumMemory(image->rows,
2383 ping_rowbytes*sizeof(*ping_pixels));
2386 ping_pixels=(unsigned char *) AcquireQuantumMemory(ping_rowbytes,
2387 sizeof(*ping_pixels));
2389 if (ping_pixels == (unsigned char *) NULL)
2390 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
2392 if (logging != MagickFalse)
2393 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2394 " Converting PNG pixels to pixel packets");
2396 Convert PNG pixels to pixel packets.
2398 if (setjmp(png_jmpbuf(ping)))
2401 PNG image is corrupt.
2403 png_destroy_read_struct(&ping,&ping_info,&end_info);
2404 #if defined(PNG_SETJMP_NOT_THREAD_SAFE)
2405 UnlockSemaphoreInfo(ping_semaphore);
2407 if (quantum_info != (QuantumInfo *) NULL)
2408 quantum_info = DestroyQuantumInfo(quantum_info);
2410 if (ping_pixels != (unsigned char *) NULL)
2411 ping_pixels=(unsigned char *) RelinquishMagickMemory(ping_pixels);
2413 if (logging != MagickFalse)
2414 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2415 " exit ReadOnePNGImage() with error.");
2417 if (image != (Image *) NULL)
2419 InheritException(exception,&image->exception);
2423 return(GetFirstImageInList(image));
2426 quantum_info=AcquireQuantumInfo(image_info,image);
2428 if (quantum_info == (QuantumInfo *) NULL)
2429 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
2434 found_transparent_pixel;
2436 found_transparent_pixel=MagickFalse;
2438 if (image->storage_class == DirectClass)
2440 for (pass=0; pass < num_passes; pass++)
2443 Convert image to DirectClass pixel packets.
2445 #if (MAGICKCORE_QUANTUM_DEPTH == 8)
2449 depth=(ssize_t) ping_bit_depth;
2451 image->matte=(((int) ping_color_type == PNG_COLOR_TYPE_RGB_ALPHA) ||
2452 ((int) ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA) ||
2453 (png_get_valid(ping,ping_info,PNG_INFO_tRNS))) ?
2454 MagickTrue : MagickFalse;
2456 for (y=0; y < (ssize_t) image->rows; y++)
2459 row_offset=ping_rowbytes*y;
2464 png_read_row(ping,ping_pixels+row_offset,NULL);
2465 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
2467 if (q == (PixelPacket *) NULL)
2470 #if (0 && (MAGICKCORE_QUANTUM_DEPTH == 8) && !defined(MAGICKCORE_HDRI_SUPPORT))
2471 /* code deleted from version 6.6.6-8 */
2472 #else /* (MAGICKCORE_QUANTUM_DEPTH != 8) */
2474 if ((int) ping_color_type == PNG_COLOR_TYPE_GRAY)
2475 (void) ImportQuantumPixels(image,(CacheView *) NULL,quantum_info,
2476 GrayQuantum,ping_pixels+row_offset,exception);
2478 else if ((int) ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
2479 (void) ImportQuantumPixels(image,(CacheView *) NULL,quantum_info,
2480 GrayAlphaQuantum,ping_pixels+row_offset,exception);
2482 else if ((int) ping_color_type == PNG_COLOR_TYPE_RGB_ALPHA)
2483 (void) ImportQuantumPixels(image,(CacheView *) NULL,quantum_info,
2484 RGBAQuantum,ping_pixels+row_offset,exception);
2486 else if ((int) ping_color_type == PNG_COLOR_TYPE_PALETTE)
2487 (void) ImportQuantumPixels(image,(CacheView *) NULL,quantum_info,
2488 IndexQuantum,ping_pixels+row_offset,exception);
2490 else /* ping_color_type == PNG_COLOR_TYPE_RGB */
2491 (void) ImportQuantumPixels(image,(CacheView *) NULL,quantum_info,
2492 RGBQuantum,ping_pixels+row_offset,exception);
2494 if (found_transparent_pixel == MagickFalse)
2496 /* Is there a transparent pixel in the row? */
2497 if (y== 0 && logging != MagickFalse)
2498 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2499 " Looking for cheap transparent pixel");
2501 for (x=(ssize_t) image->columns-1; x >= 0; x--)
2503 if ((ping_color_type == PNG_COLOR_TYPE_RGBA ||
2504 ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA) &&
2505 (q->opacity != OpaqueOpacity))
2507 if (logging != MagickFalse)
2508 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2511 found_transparent_pixel = MagickTrue;
2514 if ((ping_color_type == PNG_COLOR_TYPE_RGB ||
2515 ping_color_type == PNG_COLOR_TYPE_GRAY) &&
2516 (ScaleQuantumToShort(q->red) == transparent_color.red &&
2517 ScaleQuantumToShort(q->green) == transparent_color.green &&
2518 ScaleQuantumToShort(q->blue) == transparent_color.blue))
2520 if (logging != MagickFalse)
2521 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2523 found_transparent_pixel = MagickTrue;
2530 if ((image->previous == (Image *) NULL) && (num_passes == 1))
2532 status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
2535 if (status == MagickFalse)
2538 if (SyncAuthenticPixels(image,exception) == MagickFalse)
2542 if ((image->previous == (Image *) NULL) && (num_passes != 1))
2544 status=SetImageProgress(image,LoadImageTag,pass,num_passes);
2545 if (status == MagickFalse)
2551 else /* image->storage_class != DirectClass */
2553 for (pass=0; pass < num_passes; pass++)
2562 Convert grayscale image to PseudoClass pixel packets.
2564 image->matte=ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA ?
2565 MagickTrue : MagickFalse;
2567 quantum_scanline=(Quantum *) AcquireQuantumMemory(image->columns,
2568 (image->matte ? 2 : 1)*sizeof(*quantum_scanline));
2570 if (quantum_scanline == (Quantum *) NULL)
2571 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
2573 for (y=0; y < (ssize_t) image->rows; y++)
2576 row_offset=ping_rowbytes*y;
2581 png_read_row(ping,ping_pixels+row_offset,NULL);
2582 q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
2584 if (q == (PixelPacket *) NULL)
2587 indexes=GetAuthenticIndexQueue(image);
2588 p=ping_pixels+row_offset;
2591 switch (ping_bit_depth)
2598 for (x=(ssize_t) image->columns-7; x > 0; x-=8)
2600 for (bit=7; bit >= 0; bit--)
2601 *r++=(Quantum) ((*p) & (0x01 << bit) ? 0x01 : 0x00);
2605 if ((image->columns % 8) != 0)
2607 for (bit=7; bit >= (ssize_t) (8-(image->columns % 8)); bit--)
2608 *r++=(Quantum) ((*p) & (0x01 << bit) ? 0x01 : 0x00);
2616 for (x=(ssize_t) image->columns-3; x > 0; x-=4)
2618 *r++=(*p >> 6) & 0x03;
2619 *r++=(*p >> 4) & 0x03;
2620 *r++=(*p >> 2) & 0x03;
2624 if ((image->columns % 4) != 0)
2626 for (i=3; i >= (ssize_t) (4-(image->columns % 4)); i--)
2627 *r++=(Quantum) ((*p >> (i*2)) & 0x03);
2635 for (x=(ssize_t) image->columns-1; x > 0; x-=2)
2637 *r++=(*p >> 4) & 0x0f;
2641 if ((image->columns % 2) != 0)
2642 *r++=(*p++ >> 4) & 0x0f;
2649 if (ping_color_type == 4)
2650 for (x=(ssize_t) image->columns-1; x >= 0; x--)
2653 /* In image.h, OpaqueOpacity is 0
2654 * TransparentOpacity is QuantumRange
2655 * In a PNG datastream, Opaque is QuantumRange
2656 * and Transparent is 0.
2658 q->opacity=ScaleCharToQuantum((unsigned char) (255-(*p++)));
2659 if (q->opacity != OpaqueOpacity)
2660 found_transparent_pixel = MagickTrue;
2665 for (x=(ssize_t) image->columns-1; x >= 0; x--)
2673 for (x=(ssize_t) image->columns-1; x >= 0; x--)
2675 #if (MAGICKCORE_QUANTUM_DEPTH == 16)
2679 if (image->colors > 256)
2687 *r=(Quantum) quantum;
2690 if (ping_color_type == 4)
2692 quantum=((*p++) << 8);
2694 q->opacity=(Quantum) (QuantumRange-quantum);
2695 if (q->opacity != OpaqueOpacity)
2696 found_transparent_pixel = MagickTrue;
2700 #if (MAGICKCORE_QUANTUM_DEPTH == 32)
2704 if (image->colors > 256)
2715 if (ping_color_type == 4)
2717 q->opacity=(*p << 8) | *(p+1);
2719 q->opacity=(Quantum) GetAlphaPixelComponent(q);
2720 if (q->opacity != OpaqueOpacity)
2721 found_transparent_pixel = MagickTrue;
2726 #else /* MAGICKCORE_QUANTUM_DEPTH == 8 */
2728 p++; /* strip low byte */
2730 if (ping_color_type == 4)
2732 q->opacity=(Quantum) (QuantumRange-(*p++));
2733 if (q->opacity != OpaqueOpacity)
2734 found_transparent_pixel = MagickTrue;
2749 Transfer image scanline.
2753 for (x=0; x < (ssize_t) image->columns; x++)
2754 indexes[x]=(IndexPacket) (*r++);
2756 if (SyncAuthenticPixels(image,exception) == MagickFalse)
2759 if ((image->previous == (Image *) NULL) && (num_passes == 1))
2761 status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
2764 if (status == MagickFalse)
2769 if ((image->previous == (Image *) NULL) && (num_passes != 1))
2771 status=SetImageProgress(image,LoadImageTag,pass,num_passes);
2773 if (status == MagickFalse)
2777 quantum_scanline=(Quantum *) RelinquishMagickMemory(quantum_scanline);
2780 image->matte=found_transparent_pixel;
2782 if (logging != MagickFalse)
2784 if (found_transparent_pixel != MagickFalse)
2785 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2786 " Found transparent pixel");
2789 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2790 " No transparent pixel was found");
2792 ping_color_type&=0x03;
2797 if (quantum_info != (QuantumInfo *) NULL)
2798 quantum_info=DestroyQuantumInfo(quantum_info);
2800 if (image->storage_class == PseudoClass)
2806 image->matte=MagickFalse;
2807 (void) SyncImage(image);
2811 png_read_end(ping,ping_info);
2813 if (image_info->number_scenes != 0 && mng_info->scenes_found-1 <
2814 (ssize_t) image_info->first_scene && image->delay != 0)
2816 png_destroy_read_struct(&ping,&ping_info,&end_info);
2817 ping_pixels=(unsigned char *) RelinquishMagickMemory(ping_pixels);
2819 (void) SetImageBackgroundColor(image);
2820 #if defined(PNG_SETJMP_NOT_THREAD_SAFE)
2821 UnlockSemaphoreInfo(ping_semaphore);
2823 if (logging != MagickFalse)
2824 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2825 " exit ReadOnePNGImage() early.");
2829 if (png_get_valid(ping,ping_info,PNG_INFO_tRNS))
2835 Image has a transparent background.
2837 storage_class=image->storage_class;
2838 image->matte=MagickTrue;
2840 /* Balfour fix from imagemagick discourse server, 5 Feb 2010 */
2842 if (storage_class == PseudoClass)
2844 if ((int) ping_color_type == PNG_COLOR_TYPE_PALETTE)
2846 for (x=0; x < ping_num_trans; x++)
2848 image->colormap[x].opacity =
2849 ScaleCharToQuantum((unsigned char)(255-ping_trans_alpha[x]));
2853 else if (ping_color_type == PNG_COLOR_TYPE_GRAY)
2855 for (x=0; x < (int) image->colors; x++)
2857 if (ScaleQuantumToShort(image->colormap[x].red) ==
2858 transparent_color.opacity)
2860 image->colormap[x].opacity = (Quantum) TransparentOpacity;
2864 (void) SyncImage(image);
2867 #if 1 /* Should have already been done above, but glennrp problem P10
2872 for (y=0; y < (ssize_t) image->rows; y++)
2874 image->storage_class=storage_class;
2875 q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
2877 if (q == (PixelPacket *) NULL)
2880 indexes=GetAuthenticIndexQueue(image);
2882 /* Caution: on a Q8 build, this does not distinguish between
2883 * 16-bit colors that differ only in the low byte
2885 for (x=(ssize_t) image->columns-1; x >= 0; x--)
2887 if (ScaleQuantumToShort(q->red) == transparent_color.red &&
2888 ScaleQuantumToShort(q->green) == transparent_color.green &&
2889 ScaleQuantumToShort(q->blue) == transparent_color.blue)
2891 q->opacity=(Quantum) TransparentOpacity;
2894 #if 0 /* I have not found a case where this is needed. */
2897 q->opacity=(Quantum) OpaqueOpacity;
2904 if (SyncAuthenticPixels(image,exception) == MagickFalse)
2910 image->storage_class=DirectClass;
2913 if ((ping_color_type == PNG_COLOR_TYPE_GRAY) ||
2914 (ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA))
2915 image->colorspace=GRAYColorspace;
2917 if (png_get_text(ping,ping_info,&text,&num_text) != 0)
2918 for (i=0; i < (ssize_t) num_text; i++)
2920 /* Check for a profile */
2922 if (logging != MagickFalse)
2923 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2924 " Reading PNG text chunk");
2926 if (memcmp(text[i].key, "Raw profile type ",17) == 0)
2927 (void) Magick_png_read_raw_profile(image,image_info,text,(int) i);
2934 length=text[i].text_length;
2935 value=(char *) AcquireQuantumMemory(length+MaxTextExtent,
2937 if (value == (char *) NULL)
2939 (void) ThrowMagickException(&image->exception,GetMagickModule(),
2940 ResourceLimitError,"MemoryAllocationFailed","`%s'",
2945 (void) ConcatenateMagickString(value,text[i].text,length+2);
2946 (void) SetImageProperty(image,text[i].key,value);
2948 if (logging != MagickFalse)
2949 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2950 " Keyword: %s",text[i].key);
2952 value=DestroyString(value);
2956 #ifdef MNG_OBJECT_BUFFERS
2958 Store the object if necessary.
2960 if (object_id && !mng_info->frozen[object_id])
2962 if (mng_info->ob[object_id] == (MngBuffer *) NULL)
2965 create a new object buffer.
2967 mng_info->ob[object_id]=(MngBuffer *)
2968 AcquireMagickMemory(sizeof(MngBuffer));
2970 if (mng_info->ob[object_id] != (MngBuffer *) NULL)
2972 mng_info->ob[object_id]->image=(Image *) NULL;
2973 mng_info->ob[object_id]->reference_count=1;
2977 if ((mng_info->ob[object_id] == (MngBuffer *) NULL) ||
2978 mng_info->ob[object_id]->frozen)
2980 if (mng_info->ob[object_id] == (MngBuffer *) NULL)
2981 (void) ThrowMagickException(&image->exception,GetMagickModule(),
2982 ResourceLimitError,"MemoryAllocationFailed","`%s'",
2985 if (mng_info->ob[object_id]->frozen)
2986 (void) ThrowMagickException(&image->exception,GetMagickModule(),
2987 ResourceLimitError,"Cannot overwrite frozen MNG object buffer",
2988 "`%s'",image->filename);
2994 if (mng_info->ob[object_id]->image != (Image *) NULL)
2995 mng_info->ob[object_id]->image=DestroyImage
2996 (mng_info->ob[object_id]->image);
2998 mng_info->ob[object_id]->image=CloneImage(image,0,0,MagickTrue,
3001 if (mng_info->ob[object_id]->image != (Image *) NULL)
3002 mng_info->ob[object_id]->image->file=(FILE *) NULL;
3005 (void) ThrowMagickException(&image->exception,GetMagickModule(),
3006 ResourceLimitError,"Cloning image for object buffer failed",
3007 "`%s'",image->filename);
3009 if (ping_width > 250000L || ping_height > 250000L)
3010 png_error(ping,"PNG Image dimensions are too large.");
3012 mng_info->ob[object_id]->width=ping_width;
3013 mng_info->ob[object_id]->height=ping_height;
3014 mng_info->ob[object_id]->color_type=ping_color_type;
3015 mng_info->ob[object_id]->sample_depth=ping_bit_depth;
3016 mng_info->ob[object_id]->interlace_method=ping_interlace_method;
3017 mng_info->ob[object_id]->compression_method=
3018 ping_compression_method;
3019 mng_info->ob[object_id]->filter_method=ping_filter_method;
3021 if (png_get_valid(ping,ping_info,PNG_INFO_PLTE))
3030 Copy the PLTE to the object buffer.
3032 png_get_PLTE(ping,ping_info,&plte,&number_colors);
3033 mng_info->ob[object_id]->plte_length=number_colors;
3035 for (i=0; i < number_colors; i++)
3037 mng_info->ob[object_id]->plte[i]=plte[i];
3042 mng_info->ob[object_id]->plte_length=0;
3047 Relinquish resources.
3049 png_destroy_read_struct(&ping,&ping_info,&end_info);
3051 ping_pixels=(unsigned char *) RelinquishMagickMemory(ping_pixels);
3052 #if defined(PNG_SETJMP_NOT_THREAD_SAFE)
3053 UnlockSemaphoreInfo(ping_semaphore);
3056 if (logging != MagickFalse)
3057 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3058 " exit ReadOnePNGImage()");
3062 /* end of reading one PNG image */
3065 static Image *ReadPNGImage(const ImageInfo *image_info,ExceptionInfo *exception)
3080 magic_number[MaxTextExtent];
3088 assert(image_info != (const ImageInfo *) NULL);
3089 assert(image_info->signature == MagickSignature);
3091 if (image_info->debug != MagickFalse)
3092 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
3093 image_info->filename);
3095 assert(exception != (ExceptionInfo *) NULL);
3096 assert(exception->signature == MagickSignature);
3097 logging=LogMagickEvent(CoderEvent,GetMagickModule(),"enter ReadPNGImage()");
3098 image=AcquireImage(image_info);
3099 mng_info=(MngInfo *) NULL;
3100 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
3102 if (status == MagickFalse)
3103 ThrowReaderException(FileOpenError,"UnableToOpenFile");
3106 Verify PNG signature.
3108 count=ReadBlob(image,8,(unsigned char *) magic_number);
3110 if (count < 8 || memcmp(magic_number,"\211PNG\r\n\032\n",8) != 0)
3111 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
3114 Allocate a MngInfo structure.
3116 have_mng_structure=MagickFalse;
3117 mng_info=(MngInfo *) AcquireMagickMemory(sizeof(MngInfo));
3119 if (mng_info == (MngInfo *) NULL)
3120 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
3123 Initialize members of the MngInfo structure.
3125 (void) ResetMagickMemory(mng_info,0,sizeof(MngInfo));
3126 mng_info->image=image;
3127 have_mng_structure=MagickTrue;
3130 image=ReadOnePNGImage(mng_info,image_info,exception);
3131 MngInfoFreeStruct(mng_info,&have_mng_structure);
3133 if (image == (Image *) NULL)
3135 if (previous != (Image *) NULL)
3137 if (previous->signature != MagickSignature)
3138 ThrowReaderException(CorruptImageError,"CorruptImage");
3140 (void) CloseBlob(previous);
3141 (void) DestroyImageList(previous);
3144 if (logging != MagickFalse)
3145 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3146 "exit ReadPNGImage() with error");
3148 return((Image *) NULL);
3151 (void) CloseBlob(image);
3153 if ((image->columns == 0) || (image->rows == 0))
3155 if (logging != MagickFalse)
3156 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3157 "exit ReadPNGImage() with error.");
3159 ThrowReaderException(CorruptImageError,"CorruptImage");
3162 if (LocaleCompare(image_info->magick,"PNG8") == 0)
3164 (void) SetImageType(image,PaletteType);
3166 if (image->matte != MagickFalse)
3168 /* To do: Reduce to binary transparency */
3172 if (LocaleCompare(image_info->magick,"PNG24") == 0)
3174 (void) SetImageType(image,TrueColorType);
3175 image->matte=MagickFalse;
3178 if (LocaleCompare(image_info->magick,"PNG32") == 0)
3179 (void) SetImageType(image,TrueColorMatteType);
3181 if (logging != MagickFalse)
3182 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"exit ReadPNGImage()");
3189 #if defined(JNG_SUPPORTED)
3191 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3195 % R e a d O n e J N G I m a g e %
3199 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3201 % ReadOneJNGImage() reads a JPEG Network Graphics (JNG) image file
3202 % (minus the 8-byte signature) and returns it. It allocates the memory
3203 % necessary for the new Image structure and returns a pointer to the new
3206 % JNG support written by Glenn Randers-Pehrson, glennrp@image...
3208 % The format of the ReadOneJNGImage method is:
3210 % Image *ReadOneJNGImage(MngInfo *mng_info, const ImageInfo *image_info,
3211 % ExceptionInfo *exception)
3213 % A description of each parameter follows:
3215 % o mng_info: Specifies a pointer to a MngInfo structure.
3217 % o image_info: the image info.
3219 % o exception: return any errors or warnings in this structure.
3222 static Image *ReadOneJNGImage(MngInfo *mng_info,
3223 const ImageInfo *image_info, ExceptionInfo *exception)
3250 jng_image_sample_depth,
3251 jng_image_compression_method,
3252 jng_image_interlace_method,
3253 jng_alpha_sample_depth,
3254 jng_alpha_compression_method,
3255 jng_alpha_filter_method,
3256 jng_alpha_interlace_method;
3258 register const PixelPacket
3265 register PixelPacket
3268 register unsigned char
3279 jng_alpha_compression_method=0;
3280 jng_alpha_sample_depth=8;
3284 alpha_image=(Image *) NULL;
3285 color_image=(Image *) NULL;
3286 alpha_image_info=(ImageInfo *) NULL;
3287 color_image_info=(ImageInfo *) NULL;
3289 logging=LogMagickEvent(CoderEvent,GetMagickModule(),
3290 " enter ReadOneJNGImage()");
3292 image=mng_info->image;
3294 if (GetAuthenticPixelQueue(image) != (PixelPacket *) NULL)
3297 Allocate next image structure.
3299 if (logging != MagickFalse)
3300 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3301 " AcquireNextImage()");
3303 AcquireNextImage(image_info,image);
3305 if (GetNextImageInList(image) == (Image *) NULL)
3306 return((Image *) NULL);
3308 image=SyncNextImageInList(image);
3310 mng_info->image=image;
3313 Signature bytes have already been read.
3316 read_JSEP=MagickFalse;
3317 reading_idat=MagickFalse;
3318 skip_to_iend=MagickFalse;
3322 type[MaxTextExtent];
3331 Read a new JNG chunk.
3333 status=SetImageProgress(image,LoadImagesTag,TellBlob(image),
3334 2*GetBlobSize(image));
3336 if (status == MagickFalse)
3340 (void) ConcatenateMagickString(type,"errr",MaxTextExtent);
3341 length=ReadBlobMSBLong(image);
3342 count=(unsigned int) ReadBlob(image,4,(unsigned char *) type);
3344 if (logging != MagickFalse)
3345 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3346 " Reading JNG chunk type %c%c%c%c, length: %.20g",
3347 type[0],type[1],type[2],type[3],(double) length);
3349 if (length > PNG_UINT_31_MAX || count == 0)
3350 ThrowReaderException(CorruptImageError,"CorruptImage");
3353 chunk=(unsigned char *) NULL;
3357 chunk=(unsigned char *) AcquireQuantumMemory(length,sizeof(*chunk));
3359 if (chunk == (unsigned char *) NULL)
3360 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
3362 for (i=0; i < (ssize_t) length; i++)
3363 chunk[i]=(unsigned char) ReadBlobByte(image);
3368 (void) ReadBlobMSBLong(image); /* read crc word */
3373 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
3378 if (memcmp(type,mng_JHDR,4) == 0)
3382 jng_width=(size_t) ((p[0] << 24) | (p[1] << 16) |
3383 (p[2] << 8) | p[3]);
3384 jng_height=(size_t) ((p[4] << 24) | (p[5] << 16) |
3385 (p[6] << 8) | p[7]);
3386 jng_color_type=p[8];
3387 jng_image_sample_depth=p[9];
3388 jng_image_compression_method=p[10];
3389 jng_image_interlace_method=p[11];
3391 image->interlace=jng_image_interlace_method != 0 ? PNGInterlace :
3394 jng_alpha_sample_depth=p[12];
3395 jng_alpha_compression_method=p[13];
3396 jng_alpha_filter_method=p[14];
3397 jng_alpha_interlace_method=p[15];
3399 if (logging != MagickFalse)
3401 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3402 " jng_width: %16lu",(unsigned long) jng_width);
3404 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3405 " jng_width: %16lu",(unsigned long) jng_height);
3407 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3408 " jng_color_type: %16d",jng_color_type);
3410 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3411 " jng_image_sample_depth: %3d",
3412 jng_image_sample_depth);
3414 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3415 " jng_image_compression_method:%3d",
3416 jng_image_compression_method);
3418 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3419 " jng_image_interlace_method: %3d",
3420 jng_image_interlace_method);
3422 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3423 " jng_alpha_sample_depth: %3d",
3424 jng_alpha_sample_depth);
3426 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3427 " jng_alpha_compression_method:%3d",
3428 jng_alpha_compression_method);
3430 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3431 " jng_alpha_filter_method: %3d",
3432 jng_alpha_filter_method);
3434 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3435 " jng_alpha_interlace_method: %3d",
3436 jng_alpha_interlace_method);
3441 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
3447 if ((reading_idat == MagickFalse) && (read_JSEP == MagickFalse) &&
3448 ((memcmp(type,mng_JDAT,4) == 0) || (memcmp(type,mng_JdAA,4) == 0) ||
3449 (memcmp(type,mng_IDAT,4) == 0) || (memcmp(type,mng_JDAA,4) == 0)))
3452 o create color_image
3453 o open color_blob, attached to color_image
3454 o if (color type has alpha)
3455 open alpha_blob, attached to alpha_image
3458 color_image_info=(ImageInfo *)AcquireMagickMemory(sizeof(ImageInfo));
3460 if (color_image_info == (ImageInfo *) NULL)
3461 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
3463 GetImageInfo(color_image_info);
3464 color_image=AcquireImage(color_image_info);
3466 if (color_image == (Image *) NULL)
3467 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
3469 if (logging != MagickFalse)
3470 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3471 " Creating color_blob.");
3473 (void) AcquireUniqueFilename(color_image->filename);
3474 status=OpenBlob(color_image_info,color_image,WriteBinaryBlobMode,
3477 if (status == MagickFalse)
3478 return((Image *) NULL);
3480 if ((image_info->ping == MagickFalse) && (jng_color_type >= 12))
3482 alpha_image_info=(ImageInfo *)
3483 AcquireMagickMemory(sizeof(ImageInfo));
3485 if (alpha_image_info == (ImageInfo *) NULL)
3486 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
3488 GetImageInfo(alpha_image_info);
3489 alpha_image=AcquireImage(alpha_image_info);
3491 if (alpha_image == (Image *) NULL)
3493 alpha_image=DestroyImage(alpha_image);
3494 ThrowReaderException(ResourceLimitError,
3495 "MemoryAllocationFailed");
3498 if (logging != MagickFalse)
3499 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3500 " Creating alpha_blob.");
3502 (void) AcquireUniqueFilename(alpha_image->filename);
3503 status=OpenBlob(alpha_image_info,alpha_image,WriteBinaryBlobMode,
3506 if (status == MagickFalse)
3507 return((Image *) NULL);
3509 if (jng_alpha_compression_method == 0)
3514 if (logging != MagickFalse)
3515 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3516 " Writing IHDR chunk to alpha_blob.");
3518 (void) WriteBlob(alpha_image,8,(const unsigned char *)
3519 "\211PNG\r\n\032\n");
3521 (void) WriteBlobMSBULong(alpha_image,13L);
3522 PNGType(data,mng_IHDR);
3523 LogPNGChunk(logging,mng_IHDR,13L);
3524 PNGLong(data+4,jng_width);
3525 PNGLong(data+8,jng_height);
3526 data[12]=jng_alpha_sample_depth;
3527 data[13]=0; /* color_type gray */
3528 data[14]=0; /* compression method 0 */
3529 data[15]=0; /* filter_method 0 */
3530 data[16]=0; /* interlace_method 0 */
3531 (void) WriteBlob(alpha_image,17,data);
3532 (void) WriteBlobMSBULong(alpha_image,crc32(0,data,17));
3535 reading_idat=MagickTrue;
3538 if (memcmp(type,mng_JDAT,4) == 0)
3540 /* Copy chunk to color_image->blob */
3542 if (logging != MagickFalse)
3543 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3544 " Copying JDAT chunk data to color_blob.");
3546 (void) WriteBlob(color_image,length,chunk);
3549 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
3554 if (memcmp(type,mng_IDAT,4) == 0)
3559 /* Copy IDAT header and chunk data to alpha_image->blob */
3561 if (image_info->ping == MagickFalse)
3563 if (logging != MagickFalse)
3564 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3565 " Copying IDAT chunk data to alpha_blob.");
3567 (void) WriteBlobMSBULong(alpha_image,(size_t) length);
3568 PNGType(data,mng_IDAT);
3569 LogPNGChunk(logging,mng_IDAT,length);
3570 (void) WriteBlob(alpha_image,4,data);
3571 (void) WriteBlob(alpha_image,length,chunk);
3572 (void) WriteBlobMSBULong(alpha_image,
3573 crc32(crc32(0,data,4),chunk,(uInt) length));
3577 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
3582 if ((memcmp(type,mng_JDAA,4) == 0) || (memcmp(type,mng_JdAA,4) == 0))
3584 /* Copy chunk data to alpha_image->blob */
3586 if (image_info->ping == MagickFalse)
3588 if (logging != MagickFalse)
3589 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3590 " Copying JDAA chunk data to alpha_blob.");
3592 (void) WriteBlob(alpha_image,length,chunk);
3596 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
3601 if (memcmp(type,mng_JSEP,4) == 0)
3603 read_JSEP=MagickTrue;
3606 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
3611 if (memcmp(type,mng_bKGD,4) == 0)
3615 image->background_color.red=ScaleCharToQuantum(p[1]);
3616 image->background_color.green=image->background_color.red;
3617 image->background_color.blue=image->background_color.red;
3622 image->background_color.red=ScaleCharToQuantum(p[1]);
3623 image->background_color.green=ScaleCharToQuantum(p[3]);
3624 image->background_color.blue=ScaleCharToQuantum(p[5]);
3627 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
3631 if (memcmp(type,mng_gAMA,4) == 0)
3634 image->gamma=((float) mng_get_long(p))*0.00001;
3636 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
3640 if (memcmp(type,mng_cHRM,4) == 0)
3644 image->chromaticity.white_point.x=0.00001*mng_get_long(p);
3645 image->chromaticity.white_point.y=0.00001*mng_get_long(&p[4]);
3646 image->chromaticity.red_primary.x=0.00001*mng_get_long(&p[8]);
3647 image->chromaticity.red_primary.y=0.00001*mng_get_long(&p[12]);
3648 image->chromaticity.green_primary.x=0.00001*mng_get_long(&p[16]);
3649 image->chromaticity.green_primary.y=0.00001*mng_get_long(&p[20]);
3650 image->chromaticity.blue_primary.x=0.00001*mng_get_long(&p[24]);
3651 image->chromaticity.blue_primary.y=0.00001*mng_get_long(&p[28]);
3654 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
3658 if (memcmp(type,mng_sRGB,4) == 0)
3662 image->rendering_intent=
3663 Magick_RenderingIntent_from_PNG_RenderingIntent(p[0]);
3664 image->gamma=0.45455f;
3665 image->chromaticity.red_primary.x=0.6400f;
3666 image->chromaticity.red_primary.y=0.3300f;
3667 image->chromaticity.green_primary.x=0.3000f;
3668 image->chromaticity.green_primary.y=0.6000f;
3669 image->chromaticity.blue_primary.x=0.1500f;
3670 image->chromaticity.blue_primary.y=0.0600f;
3671 image->chromaticity.white_point.x=0.3127f;
3672 image->chromaticity.white_point.y=0.3290f;
3675 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
3679 if (memcmp(type,mng_oFFs,4) == 0)
3683 image->page.x=mng_get_long(p);
3684 image->page.y=mng_get_long(&p[4]);
3686 if ((int) p[8] != 0)
3688 image->page.x/=10000;
3689 image->page.y/=10000;
3694 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
3699 if (memcmp(type,mng_pHYs,4) == 0)
3703 image->x_resolution=(double) mng_get_long(p);
3704 image->y_resolution=(double) mng_get_long(&p[4]);
3705 if ((int) p[8] == PNG_RESOLUTION_METER)
3707 image->units=PixelsPerCentimeterResolution;
3708 image->x_resolution=image->x_resolution/100.0f;
3709 image->y_resolution=image->y_resolution/100.0f;
3713 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
3718 if (memcmp(type,mng_iCCP,4) == 0)
3722 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
3729 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
3731 if (memcmp(type,mng_IEND,4))
3741 Finish up reading image data:
3743 o read main image from color_blob.
3747 o if (color_type has alpha)
3748 if alpha_encoding is PNG
3749 read secondary image from alpha_blob via ReadPNG
3750 if alpha_encoding is JPEG
3751 read secondary image from alpha_blob via ReadJPEG
3755 o copy intensity of secondary image into
3756 opacity samples of main image.
3758 o destroy the secondary image.
3761 (void) CloseBlob(color_image);
3763 if (logging != MagickFalse)
3764 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3765 " Reading jng_image from color_blob.");
3767 (void) FormatMagickString(color_image_info->filename,MaxTextExtent,"%s",
3768 color_image->filename);
3770 color_image_info->ping=MagickFalse; /* To do: avoid this */
3771 jng_image=ReadImage(color_image_info,exception);
3773 if (jng_image == (Image *) NULL)
3774 return((Image *) NULL);
3776 (void) RelinquishUniqueFileResource(color_image->filename);
3777 color_image=DestroyImage(color_image);
3778 color_image_info=DestroyImageInfo(color_image_info);
3780 if (jng_image == (Image *) NULL)
3781 return((Image *) NULL);
3783 if (logging != MagickFalse)
3784 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3785 " Copying jng_image pixels to main image.");
3787 image->rows=jng_height;
3788 image->columns=jng_width;
3789 length=image->columns*sizeof(PixelPacket);
3791 for (y=0; y < (ssize_t) image->rows; y++)
3793 s=GetVirtualPixels(jng_image,0,y,image->columns,1,&image->exception);
3794 q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
3795 (void) CopyMagickMemory(q,s,length);
3797 if (SyncAuthenticPixels(image,exception) == MagickFalse)
3801 jng_image=DestroyImage(jng_image);
3803 if (image_info->ping == MagickFalse)
3805 if (jng_color_type >= 12)
3807 if (jng_alpha_compression_method == 0)
3811 (void) WriteBlobMSBULong(alpha_image,0x00000000L);
3812 PNGType(data,mng_IEND);
3813 LogPNGChunk(logging,mng_IEND,0L);
3814 (void) WriteBlob(alpha_image,4,data);
3815 (void) WriteBlobMSBULong(alpha_image,crc32(0,data,4));
3818 (void) CloseBlob(alpha_image);
3820 if (logging != MagickFalse)
3821 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3822 " Reading opacity from alpha_blob.");
3824 (void) FormatMagickString(alpha_image_info->filename,MaxTextExtent,
3825 "%s",alpha_image->filename);
3827 jng_image=ReadImage(alpha_image_info,exception);
3829 if (jng_image != (Image *) NULL)
3830 for (y=0; y < (ssize_t) image->rows; y++)
3832 s=GetVirtualPixels(jng_image,0,y,image->columns,1,
3834 q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
3836 if (image->matte != MagickFalse)
3837 for (x=(ssize_t) image->columns; x != 0; x--,q++,s++)
3838 q->opacity=(Quantum) QuantumRange-s->red;
3841 for (x=(ssize_t) image->columns; x != 0; x--,q++,s++)
3843 q->opacity=(Quantum) QuantumRange-s->red;
3844 if (q->opacity != OpaqueOpacity)
3845 image->matte=MagickTrue;
3848 if (SyncAuthenticPixels(image,exception) == MagickFalse)
3851 (void) RelinquishUniqueFileResource(alpha_image->filename);
3852 alpha_image=DestroyImage(alpha_image);
3853 alpha_image_info=DestroyImageInfo(alpha_image_info);
3854 if (jng_image != (Image *) NULL)
3855 jng_image=DestroyImage(jng_image);
3859 /* Read the JNG image. */
3861 if (mng_info->mng_type == 0)
3863 mng_info->mng_width=jng_width;
3864 mng_info->mng_height=jng_height;
3867 if (image->page.width == 0 && image->page.height == 0)
3869 image->page.width=jng_width;
3870 image->page.height=jng_height;
3873 if (image->page.x == 0 && image->page.y == 0)
3875 image->page.x=mng_info->x_off[mng_info->object_id];
3876 image->page.y=mng_info->y_off[mng_info->object_id];
3881 image->page.y=mng_info->y_off[mng_info->object_id];
3884 mng_info->image_found++;
3885 status=SetImageProgress(image,LoadImagesTag,2*TellBlob(image),
3886 2*GetBlobSize(image));
3888 if (logging != MagickFalse)
3889 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3890 " exit ReadOneJNGImage()");
3896 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3900 % R e a d J N G I m a g e %
3904 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3906 % ReadJNGImage() reads a JPEG Network Graphics (JNG) image file
3907 % (including the 8-byte signature) and returns it. It allocates the memory
3908 % necessary for the new Image structure and returns a pointer to the new
3911 % JNG support written by Glenn Randers-Pehrson, glennrp@image...
3913 % The format of the ReadJNGImage method is:
3915 % Image *ReadJNGImage(const ImageInfo *image_info, ExceptionInfo
3918 % A description of each parameter follows:
3920 % o image_info: the image info.
3922 % o exception: return any errors or warnings in this structure.
3926 static Image *ReadJNGImage(const ImageInfo *image_info,ExceptionInfo *exception)
3941 magic_number[MaxTextExtent];
3949 assert(image_info != (const ImageInfo *) NULL);
3950 assert(image_info->signature == MagickSignature);
3951 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image_info->filename);
3952 assert(exception != (ExceptionInfo *) NULL);
3953 assert(exception->signature == MagickSignature);
3954 logging=LogMagickEvent(CoderEvent,GetMagickModule(),"enter ReadJNGImage()");
3955 image=AcquireImage(image_info);
3956 mng_info=(MngInfo *) NULL;
3957 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
3959 if (status == MagickFalse)
3960 return((Image *) NULL);
3962 if (LocaleCompare(image_info->magick,"JNG") != 0)
3963 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
3965 /* Verify JNG signature. */
3967 count=(size_t) ReadBlob(image,8,(unsigned char *) magic_number);
3969 if (count < 8 || memcmp(magic_number,"\213JNG\r\n\032\n",8) != 0)
3970 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
3972 /* Allocate a MngInfo structure. */
3974 have_mng_structure=MagickFalse;
3975 mng_info=(MngInfo *) AcquireMagickMemory(sizeof(*mng_info));
3977 if (mng_info == (MngInfo *) NULL)
3978 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
3980 /* Initialize members of the MngInfo structure. */
3982 (void) ResetMagickMemory(mng_info,0,sizeof(MngInfo));
3983 have_mng_structure=MagickTrue;
3985 mng_info->image=image;
3987 image=ReadOneJNGImage(mng_info,image_info,exception);
3988 MngInfoFreeStruct(mng_info,&have_mng_structure);
3990 if (image == (Image *) NULL)
3992 if (IsImageObject(previous) != MagickFalse)
3994 (void) CloseBlob(previous);
3995 (void) DestroyImageList(previous);
3998 if (logging != MagickFalse)
3999 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4000 "exit ReadJNGImage() with error");
4002 return((Image *) NULL);
4004 (void) CloseBlob(image);
4006 if (image->columns == 0 || image->rows == 0)
4008 if (logging != MagickFalse)
4009 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4010 "exit ReadJNGImage() with error");
4012 ThrowReaderException(CorruptImageError,"CorruptImage");
4015 if (logging != MagickFalse)
4016 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"exit ReadJNGImage()");
4022 static Image *ReadMNGImage(const ImageInfo *image_info,ExceptionInfo *exception)
4025 page_geometry[MaxTextExtent];
4058 #if defined(MNG_INSERT_LAYERS)
4060 mng_background_color;
4063 register unsigned char
4078 #if defined(MNG_INSERT_LAYERS)
4083 volatile unsigned int
4084 #ifdef MNG_OBJECT_BUFFERS
4085 mng_background_object=0,
4087 mng_type=0; /* 0: PNG or JNG; 1: MNG; 2: MNG-LC; 3: MNG-VLC */
4090 default_frame_timeout,
4092 #if defined(MNG_INSERT_LAYERS)
4098 /* These delays are all measured in image ticks_per_second,
4099 * not in MNG ticks_per_second
4102 default_frame_delay,
4106 #if defined(MNG_INSERT_LAYERS)
4115 previous_fb.bottom=0;
4117 previous_fb.right=0;
4119 default_fb.bottom=0;
4123 /* Open image file. */
4125 assert(image_info != (const ImageInfo *) NULL);
4126 assert(image_info->signature == MagickSignature);
4127 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image_info->filename);
4128 assert(exception != (ExceptionInfo *) NULL);
4129 assert(exception->signature == MagickSignature);
4130 logging=LogMagickEvent(CoderEvent,GetMagickModule(),"enter ReadMNGImage()");
4131 image=AcquireImage(image_info);
4132 mng_info=(MngInfo *) NULL;
4133 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
4135 if (status == MagickFalse)
4136 return((Image *) NULL);
4138 first_mng_object=MagickFalse;
4140 have_mng_structure=MagickFalse;
4142 /* Allocate a MngInfo structure. */
4144 mng_info=(MngInfo *) AcquireMagickMemory(sizeof(MngInfo));
4146 if (mng_info == (MngInfo *) NULL)
4147 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
4149 /* Initialize members of the MngInfo structure. */
4151 (void) ResetMagickMemory(mng_info,0,sizeof(MngInfo));
4152 mng_info->image=image;
4153 have_mng_structure=MagickTrue;
4155 if (LocaleCompare(image_info->magick,"MNG") == 0)
4158 magic_number[MaxTextExtent];
4160 /* Verify MNG signature. */
4161 count=(size_t) ReadBlob(image,8,(unsigned char *) magic_number);
4162 if (memcmp(magic_number,"\212MNG\r\n\032\n",8) != 0)
4163 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
4165 /* Initialize some nonzero members of the MngInfo structure. */
4166 for (i=0; i < MNG_MAX_OBJECTS; i++)
4168 mng_info->object_clip[i].right=(ssize_t) PNG_UINT_31_MAX;
4169 mng_info->object_clip[i].bottom=(ssize_t) PNG_UINT_31_MAX;
4171 mng_info->exists[0]=MagickTrue;
4174 first_mng_object=MagickTrue;
4176 #if defined(MNG_INSERT_LAYERS)
4177 insert_layers=MagickFalse; /* should be False when converting or mogrifying */
4179 default_frame_delay=0;
4180 default_frame_timeout=0;
4183 mng_info->ticks_per_second=1UL*image->ticks_per_second;
4185 skip_to_iend=MagickFalse;
4186 term_chunk_found=MagickFalse;
4187 mng_info->framing_mode=1;
4188 #if defined(MNG_INSERT_LAYERS)
4189 mandatory_back=MagickFalse;
4191 #if defined(MNG_INSERT_LAYERS)
4192 mng_background_color=image->background_color;
4194 default_fb=mng_info->frame;
4195 previous_fb=mng_info->frame;
4199 type[MaxTextExtent];
4201 if (LocaleCompare(image_info->magick,"MNG") == 0)
4210 (void) ConcatenateMagickString(type,"errr",MaxTextExtent);
4211 length=ReadBlobMSBLong(image);
4212 count=(size_t) ReadBlob(image,4,(unsigned char *) type);
4214 if (logging != MagickFalse)
4215 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4216 " Reading MNG chunk type %c%c%c%c, length: %.20g",
4217 type[0],type[1],type[2],type[3],(double) length);
4219 if (length > PNG_UINT_31_MAX)
4223 ThrowReaderException(CorruptImageError,"CorruptImage");
4226 chunk=(unsigned char *) NULL;
4230 chunk=(unsigned char *) AcquireQuantumMemory(length,sizeof(*chunk));
4232 if (chunk == (unsigned char *) NULL)
4233 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
4235 for (i=0; i < (ssize_t) length; i++)
4236 chunk[i]=(unsigned char) ReadBlobByte(image);
4241 (void) ReadBlobMSBLong(image); /* read crc word */
4243 #if !defined(JNG_SUPPORTED)
4244 if (memcmp(type,mng_JHDR,4) == 0)
4246 skip_to_iend=MagickTrue;
4248 if (mng_info->jhdr_warning == 0)
4249 (void) ThrowMagickException(&image->exception,GetMagickModule(),
4250 CoderError,"JNGCompressNotSupported","`%s'",image->filename);
4252 mng_info->jhdr_warning++;
4255 if (memcmp(type,mng_DHDR,4) == 0)
4257 skip_to_iend=MagickTrue;
4259 if (mng_info->dhdr_warning == 0)
4260 (void) ThrowMagickException(&image->exception,GetMagickModule(),
4261 CoderError,"DeltaPNGNotSupported","`%s'",image->filename);
4263 mng_info->dhdr_warning++;
4265 if (memcmp(type,mng_MEND,4) == 0)
4270 if (memcmp(type,mng_IEND,4) == 0)
4271 skip_to_iend=MagickFalse;
4274 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4276 if (logging != MagickFalse)
4277 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4283 if (memcmp(type,mng_MHDR,4) == 0)
4285 mng_info->mng_width=(size_t) ((p[0] << 24) | (p[1] << 16) |
4286 (p[2] << 8) | p[3]);
4288 mng_info->mng_height=(size_t) ((p[4] << 24) | (p[5] << 16) |
4289 (p[6] << 8) | p[7]);
4291 if (logging != MagickFalse)
4293 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4294 " MNG width: %.20g",(double) mng_info->mng_width);
4295 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4296 " MNG height: %.20g",(double) mng_info->mng_height);
4300 mng_info->ticks_per_second=(size_t) mng_get_long(p);
4302 if (mng_info->ticks_per_second == 0)
4303 default_frame_delay=0;
4306 default_frame_delay=1UL*image->ticks_per_second/
4307 mng_info->ticks_per_second;
4309 frame_delay=default_frame_delay;
4315 simplicity=(size_t) mng_get_long(p);
4318 mng_type=1; /* Full MNG */
4320 if ((simplicity != 0) && ((simplicity | 11) == 11))
4321 mng_type=2; /* LC */
4323 if ((simplicity != 0) && ((simplicity | 9) == 9))
4324 mng_type=3; /* VLC */
4326 #if defined(MNG_INSERT_LAYERS)
4328 insert_layers=MagickTrue;
4330 if (GetAuthenticPixelQueue(image) != (PixelPacket *) NULL)
4332 /* Allocate next image structure. */
4333 AcquireNextImage(image_info,image);
4335 if (GetNextImageInList(image) == (Image *) NULL)
4336 return((Image *) NULL);
4338 image=SyncNextImageInList(image);
4339 mng_info->image=image;
4342 if ((mng_info->mng_width > 65535L) ||
4343 (mng_info->mng_height > 65535L))
4344 ThrowReaderException(ImageError,"WidthOrHeightExceedsLimit");
4346 (void) FormatMagickString(page_geometry,MaxTextExtent,
4347 "%.20gx%.20g+0+0",(double) mng_info->mng_width,(double)
4348 mng_info->mng_height);
4350 mng_info->frame.left=0;
4351 mng_info->frame.right=(ssize_t) mng_info->mng_width;
4352 mng_info->frame.top=0;
4353 mng_info->frame.bottom=(ssize_t) mng_info->mng_height;
4354 mng_info->clip=default_fb=previous_fb=mng_info->frame;
4356 for (i=0; i < MNG_MAX_OBJECTS; i++)
4357 mng_info->object_clip[i]=mng_info->frame;
4359 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4363 if (memcmp(type,mng_TERM,4) == 0)
4374 final_delay=(png_uint_32) mng_get_long(&p[2]);
4375 mng_iterations=(png_uint_32) mng_get_long(&p[6]);
4377 if (mng_iterations == PNG_UINT_31_MAX)
4380 image->iterations=mng_iterations;
4381 term_chunk_found=MagickTrue;
4384 if (logging != MagickFalse)
4386 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4387 " repeat=%d",repeat);
4389 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4390 " final_delay=%.20g",(double) final_delay);
4392 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4393 " image->iterations=%.20g",(double) image->iterations);
4396 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4399 if (memcmp(type,mng_DEFI,4) == 0)
4402 (void) ThrowMagickException(&image->exception,GetMagickModule(),
4403 CoderError,"DEFI chunk found in MNG-VLC datastream","`%s'",
4406 object_id=(p[0] << 8) | p[1];
4408 if (mng_type == 2 && object_id != 0)
4409 (void) ThrowMagickException(&image->exception,GetMagickModule(),
4410 CoderError,"Nonzero object_id in MNG-LC datastream","`%s'",
4413 if (object_id > MNG_MAX_OBJECTS)
4416 Instead ofsuing a warning we should allocate a larger
4417 MngInfo structure and continue.
4419 (void) ThrowMagickException(&image->exception,GetMagickModule(),
4420 CoderError,"object id too large","`%s'",image->filename);
4421 object_id=MNG_MAX_OBJECTS;
4424 if (mng_info->exists[object_id])
4425 if (mng_info->frozen[object_id])
4427 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4428 (void) ThrowMagickException(&image->exception,
4429 GetMagickModule(),CoderError,
4430 "DEFI cannot redefine a frozen MNG object","`%s'",
4435 mng_info->exists[object_id]=MagickTrue;
4438 mng_info->invisible[object_id]=p[2];
4441 Extract object offset info.
4445 mng_info->x_off[object_id]=(ssize_t) ((p[4] << 24) |
4446 (p[5] << 16) | (p[6] << 8) | p[7]);
4448 mng_info->y_off[object_id]=(ssize_t) ((p[8] << 24) |
4449 (p[9] << 16) | (p[10] << 8) | p[11]);
4451 if (logging != MagickFalse)
4453 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4454 " x_off[%d]: %.20g",object_id,(double)
4455 mng_info->x_off[object_id]);
4457 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4458 " y_off[%d]: %.20g",object_id,(double)
4459 mng_info->y_off[object_id]);
4464 Extract object clipping info.
4467 mng_info->object_clip[object_id]=mng_read_box(mng_info->frame,0,
4470 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4473 if (memcmp(type,mng_bKGD,4) == 0)
4475 mng_info->have_global_bkgd=MagickFalse;
4479 mng_info->mng_global_bkgd.red=
4480 ScaleShortToQuantum((unsigned short) ((p[0] << 8) | p[1]));
4482 mng_info->mng_global_bkgd.green=
4483 ScaleShortToQuantum((unsigned short) ((p[2] << 8) | p[3]));
4485 mng_info->mng_global_bkgd.blue=
4486 ScaleShortToQuantum((unsigned short) ((p[4] << 8) | p[5]));
4488 mng_info->have_global_bkgd=MagickTrue;
4491 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4494 if (memcmp(type,mng_BACK,4) == 0)
4496 #if defined(MNG_INSERT_LAYERS)
4498 mandatory_back=p[6];
4503 if (mandatory_back && length > 5)
4505 mng_background_color.red=
4506 ScaleShortToQuantum((unsigned short) ((p[0] << 8) | p[1]));
4508 mng_background_color.green=
4509 ScaleShortToQuantum((unsigned short) ((p[2] << 8) | p[3]));
4511 mng_background_color.blue=
4512 ScaleShortToQuantum((unsigned short) ((p[4] << 8) | p[5]));
4514 mng_background_color.opacity=OpaqueOpacity;
4517 #ifdef MNG_OBJECT_BUFFERS
4519 mng_background_object=(p[7] << 8) | p[8];
4522 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4526 if (memcmp(type,mng_PLTE,4) == 0)
4528 /* Read global PLTE. */
4530 if (length && (length < 769))
4532 if (mng_info->global_plte == (png_colorp) NULL)
4533 mng_info->global_plte=(png_colorp) AcquireQuantumMemory(256,
4534 sizeof(*mng_info->global_plte));
4536 for (i=0; i < (ssize_t) (length/3); i++)
4538 mng_info->global_plte[i].red=p[3*i];
4539 mng_info->global_plte[i].green=p[3*i+1];
4540 mng_info->global_plte[i].blue=p[3*i+2];
4543 mng_info->global_plte_length=(unsigned int) (length/3);
4546 for ( ; i < 256; i++)
4548 mng_info->global_plte[i].red=i;
4549 mng_info->global_plte[i].green=i;
4550 mng_info->global_plte[i].blue=i;
4554 mng_info->global_plte_length=256;
4557 mng_info->global_plte_length=0;
4559 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4563 if (memcmp(type,mng_tRNS,4) == 0)
4565 /* read global tRNS */
4568 for (i=0; i < (ssize_t) length; i++)
4569 mng_info->global_trns[i]=p[i];
4572 for ( ; i < 256; i++)
4573 mng_info->global_trns[i]=255;
4575 mng_info->global_trns_length=(unsigned int) length;
4576 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4579 if (memcmp(type,mng_gAMA,4) == 0)
4586 igamma=mng_get_long(p);
4587 mng_info->global_gamma=((float) igamma)*0.00001;
4588 mng_info->have_global_gama=MagickTrue;
4592 mng_info->have_global_gama=MagickFalse;
4594 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4598 if (memcmp(type,mng_cHRM,4) == 0)
4600 /* Read global cHRM */
4604 mng_info->global_chrm.white_point.x=0.00001*mng_get_long(p);
4605 mng_info->global_chrm.white_point.y=0.00001*mng_get_long(&p[4]);
4606 mng_info->global_chrm.red_primary.x=0.00001*mng_get_long(&p[8]);
4607 mng_info->global_chrm.red_primary.y=0.00001*
4608 mng_get_long(&p[12]);
4609 mng_info->global_chrm.green_primary.x=0.00001*
4610 mng_get_long(&p[16]);
4611 mng_info->global_chrm.green_primary.y=0.00001*
4612 mng_get_long(&p[20]);
4613 mng_info->global_chrm.blue_primary.x=0.00001*
4614 mng_get_long(&p[24]);
4615 mng_info->global_chrm.blue_primary.y=0.00001*
4616 mng_get_long(&p[28]);
4617 mng_info->have_global_chrm=MagickTrue;
4620 mng_info->have_global_chrm=MagickFalse;
4622 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4626 if (memcmp(type,mng_sRGB,4) == 0)
4633 mng_info->global_srgb_intent=
4634 Magick_RenderingIntent_from_PNG_RenderingIntent(p[0]);
4635 mng_info->have_global_srgb=MagickTrue;
4638 mng_info->have_global_srgb=MagickFalse;
4640 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4644 if (memcmp(type,mng_iCCP,4) == 0)
4652 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4657 if (memcmp(type,mng_FRAM,4) == 0)
4660 (void) ThrowMagickException(&image->exception,GetMagickModule(),
4661 CoderError,"FRAM chunk found in MNG-VLC datastream","`%s'",
4664 if ((mng_info->framing_mode == 2) || (mng_info->framing_mode == 4))
4665 image->delay=frame_delay;
4667 frame_delay=default_frame_delay;
4668 frame_timeout=default_frame_timeout;
4673 mng_info->framing_mode=p[0];
4675 if (logging != MagickFalse)
4676 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4677 " Framing_mode=%d",mng_info->framing_mode);
4681 /* Note the delay and frame clipping boundaries. */
4683 p++; /* framing mode */
4685 while (*p && ((p-chunk) < (ssize_t) length))
4686 p++; /* frame name */
4688 p++; /* frame name terminator */
4690 if ((p-chunk) < (ssize_t) (length-4))
4697 change_delay=(*p++);
4698 change_timeout=(*p++);
4699 change_clipping=(*p++);
4700 p++; /* change_sync */
4704 frame_delay=1UL*image->ticks_per_second*
4707 if (mng_info->ticks_per_second != 0)
4708 frame_delay/=mng_info->ticks_per_second;
4711 frame_delay=PNG_UINT_31_MAX;
4713 if (change_delay == 2)
4714 default_frame_delay=frame_delay;
4718 if (logging != MagickFalse)
4719 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4720 " Framing_delay=%.20g",(double) frame_delay);
4725 frame_timeout=1UL*image->ticks_per_second*
4728 if (mng_info->ticks_per_second != 0)
4729 frame_timeout/=mng_info->ticks_per_second;
4732 frame_timeout=PNG_UINT_31_MAX;
4734 if (change_delay == 2)
4735 default_frame_timeout=frame_timeout;
4739 if (logging != MagickFalse)
4740 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4741 " Framing_timeout=%.20g",(double) frame_timeout);
4744 if (change_clipping)
4746 fb=mng_read_box(previous_fb,(char) p[0],&p[1]);
4750 if (logging != MagickFalse)
4751 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4752 " Frame_clip: L=%.20g R=%.20g T=%.20g B=%.20g",
4753 (double) fb.left,(double) fb.right,(double) fb.top,
4754 (double) fb.bottom);
4756 if (change_clipping == 2)
4762 mng_info->clip=mng_minimum_box(fb,mng_info->frame);
4764 subframe_width=(size_t) (mng_info->clip.right
4765 -mng_info->clip.left);
4767 subframe_height=(size_t) (mng_info->clip.bottom
4768 -mng_info->clip.top);
4770 Insert a background layer behind the frame if framing_mode is 4.
4772 #if defined(MNG_INSERT_LAYERS)
4773 if (logging != MagickFalse)
4774 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4775 " subframe_width=%.20g, subframe_height=%.20g",(double)
4776 subframe_width,(double) subframe_height);
4778 if (insert_layers && (mng_info->framing_mode == 4) &&
4779 (subframe_width) && (subframe_height))
4781 /* Allocate next image structure. */
4782 if (GetAuthenticPixelQueue(image) != (PixelPacket *) NULL)
4784 AcquireNextImage(image_info,image);
4786 if (GetNextImageInList(image) == (Image *) NULL)
4788 image=DestroyImageList(image);
4789 MngInfoFreeStruct(mng_info,&have_mng_structure);
4790 return((Image *) NULL);
4793 image=SyncNextImageInList(image);
4796 mng_info->image=image;
4798 if (term_chunk_found)
4800 image->start_loop=MagickTrue;
4801 image->iterations=mng_iterations;
4802 term_chunk_found=MagickFalse;
4806 image->start_loop=MagickFalse;
4808 image->columns=subframe_width;
4809 image->rows=subframe_height;
4810 image->page.width=subframe_width;
4811 image->page.height=subframe_height;
4812 image->page.x=mng_info->clip.left;
4813 image->page.y=mng_info->clip.top;
4814 image->background_color=mng_background_color;
4815 image->matte=MagickFalse;
4817 (void) SetImageBackgroundColor(image);
4819 if (logging != MagickFalse)
4820 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4821 " Insert backgd layer, L=%.20g, R=%.20g T=%.20g, B=%.20g",
4822 (double) mng_info->clip.left,(double) mng_info->clip.right,
4823 (double) mng_info->clip.top,(double) mng_info->clip.bottom);
4826 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4829 if (memcmp(type,mng_CLIP,4) == 0)
4838 first_object=(p[0] << 8) | p[1];
4839 last_object=(p[2] << 8) | p[3];
4841 for (i=(int) first_object; i <= (int) last_object; i++)
4843 if (mng_info->exists[i] && !mng_info->frozen[i])
4848 box=mng_info->object_clip[i];
4849 mng_info->object_clip[i]=mng_read_box(box,(char) p[4],&p[5]);
4853 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4856 if (memcmp(type,mng_SAVE,4) == 0)
4858 for (i=1; i < MNG_MAX_OBJECTS; i++)
4859 if (mng_info->exists[i])
4861 mng_info->frozen[i]=MagickTrue;
4862 #ifdef MNG_OBJECT_BUFFERS
4863 if (mng_info->ob[i] != (MngBuffer *) NULL)
4864 mng_info->ob[i]->frozen=MagickTrue;
4869 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4874 if ((memcmp(type,mng_DISC,4) == 0) || (memcmp(type,mng_SEEK,4) == 0))
4876 /* Read DISC or SEEK. */
4878 if ((length == 0) || !memcmp(type,mng_SEEK,4))
4880 for (i=1; i < MNG_MAX_OBJECTS; i++)
4881 MngInfoDiscardObject(mng_info,i);
4889 for (j=0; j < (ssize_t) length; j+=2)
4891 i=p[j] << 8 | p[j+1];
4892 MngInfoDiscardObject(mng_info,i);
4897 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4902 if (memcmp(type,mng_MOVE,4) == 0)
4910 first_object=(p[0] << 8) | p[1];
4911 last_object=(p[2] << 8) | p[3];
4912 for (i=(ssize_t) first_object; i <= (ssize_t) last_object; i++)
4914 if (mng_info->exists[i] && !mng_info->frozen[i])
4922 old_pair.a=mng_info->x_off[i];
4923 old_pair.b=mng_info->y_off[i];
4924 new_pair=mng_read_pair(old_pair,(int) p[4],&p[5]);
4925 mng_info->x_off[i]=new_pair.a;
4926 mng_info->y_off[i]=new_pair.b;
4930 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4934 if (memcmp(type,mng_LOOP,4) == 0)
4936 ssize_t loop_iters=1;
4937 loop_level=chunk[0];
4938 mng_info->loop_active[loop_level]=1; /* mark loop active */
4940 /* Record starting point. */
4941 loop_iters=mng_get_long(&chunk[1]);
4943 if (logging != MagickFalse)
4944 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4945 " LOOP level %.20g has %.20g iterations ",(double) loop_level,
4946 (double) loop_iters);
4948 if (loop_iters == 0)
4949 skipping_loop=loop_level;
4953 mng_info->loop_jump[loop_level]=TellBlob(image);
4954 mng_info->loop_count[loop_level]=loop_iters;
4957 mng_info->loop_iteration[loop_level]=0;
4958 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4962 if (memcmp(type,mng_ENDL,4) == 0)
4964 loop_level=chunk[0];
4966 if (skipping_loop > 0)
4968 if (skipping_loop == loop_level)
4971 Found end of zero-iteration loop.
4974 mng_info->loop_active[loop_level]=0;
4980 if (mng_info->loop_active[loop_level] == 1)
4982 mng_info->loop_count[loop_level]--;
4983 mng_info->loop_iteration[loop_level]++;
4985 if (logging != MagickFalse)
4986 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4987 " ENDL: LOOP level %.20g has %.20g remaining iters ",
4988 (double) loop_level,(double)
4989 mng_info->loop_count[loop_level]);
4991 if (mng_info->loop_count[loop_level] != 0)
4993 offset=SeekBlob(image,mng_info->loop_jump[loop_level],
4997 ThrowReaderException(CorruptImageError,
4998 "ImproperImageHeader");
5009 mng_info->loop_active[loop_level]=0;
5011 for (i=0; i < loop_level; i++)
5012 if (mng_info->loop_active[i] == 1)
5013 last_level=(short) i;
5014 loop_level=last_level;
5019 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5023 if (memcmp(type,mng_CLON,4) == 0)
5025 if (mng_info->clon_warning == 0)
5026 (void) ThrowMagickException(&image->exception,GetMagickModule(),
5027 CoderError,"CLON is not implemented yet","`%s'",
5030 mng_info->clon_warning++;
5033 if (memcmp(type,mng_MAGN,4) == 0)
5048 magn_first=(p[0] << 8) | p[1];
5054 magn_last=(p[2] << 8) | p[3];
5057 magn_last=magn_first;
5058 #ifndef MNG_OBJECT_BUFFERS
5059 if (magn_first || magn_last)
5060 if (mng_info->magn_warning == 0)
5062 (void) ThrowMagickException(&image->exception,
5063 GetMagickModule(),CoderError,
5064 "MAGN is not implemented yet for nonzero objects",
5065 "`%s'",image->filename);
5067 mng_info->magn_warning++;
5077 magn_mx=(p[5] << 8) | p[6];
5086 magn_my=(p[7] << 8) | p[8];
5095 magn_ml=(p[9] << 8) | p[10];
5104 magn_mr=(p[11] << 8) | p[12];
5113 magn_mt=(p[13] << 8) | p[14];
5122 magn_mb=(p[15] << 8) | p[16];
5134 magn_methy=magn_methx;
5137 if (magn_methx > 5 || magn_methy > 5)
5138 if (mng_info->magn_warning == 0)
5140 (void) ThrowMagickException(&image->exception,
5141 GetMagickModule(),CoderError,
5142 "Unknown MAGN method in MNG datastream","`%s'",
5145 mng_info->magn_warning++;
5147 #ifdef MNG_OBJECT_BUFFERS
5148 /* Magnify existing objects in the range magn_first to magn_last */
5150 if (magn_first == 0 || magn_last == 0)
5152 /* Save the magnification factors for object 0 */
5153 mng_info->magn_mb=magn_mb;
5154 mng_info->magn_ml=magn_ml;
5155 mng_info->magn_mr=magn_mr;
5156 mng_info->magn_mt=magn_mt;
5157 mng_info->magn_mx=magn_mx;
5158 mng_info->magn_my=magn_my;
5159 mng_info->magn_methx=magn_methx;
5160 mng_info->magn_methy=magn_methy;
5164 if (memcmp(type,mng_PAST,4) == 0)
5166 if (mng_info->past_warning == 0)
5167 (void) ThrowMagickException(&image->exception,GetMagickModule(),
5168 CoderError,"PAST is not implemented yet","`%s'",
5171 mng_info->past_warning++;
5174 if (memcmp(type,mng_SHOW,4) == 0)
5176 if (mng_info->show_warning == 0)
5177 (void) ThrowMagickException(&image->exception,GetMagickModule(),
5178 CoderError,"SHOW is not implemented yet","`%s'",
5181 mng_info->show_warning++;
5184 if (memcmp(type,mng_sBIT,4) == 0)
5187 mng_info->have_global_sbit=MagickFalse;
5191 mng_info->global_sbit.gray=p[0];
5192 mng_info->global_sbit.red=p[0];
5193 mng_info->global_sbit.green=p[1];
5194 mng_info->global_sbit.blue=p[2];
5195 mng_info->global_sbit.alpha=p[3];
5196 mng_info->have_global_sbit=MagickTrue;
5199 if (memcmp(type,mng_pHYs,4) == 0)
5203 mng_info->global_x_pixels_per_unit=
5204 (size_t) mng_get_long(p);
5205 mng_info->global_y_pixels_per_unit=
5206 (size_t) mng_get_long(&p[4]);
5207 mng_info->global_phys_unit_type=p[8];
5208 mng_info->have_global_phys=MagickTrue;
5212 mng_info->have_global_phys=MagickFalse;
5214 if (memcmp(type,mng_pHYg,4) == 0)
5216 if (mng_info->phyg_warning == 0)
5217 (void) ThrowMagickException(&image->exception,GetMagickModule(),
5218 CoderError,"pHYg is not implemented.","`%s'",image->filename);
5220 mng_info->phyg_warning++;
5222 if (memcmp(type,mng_BASI,4) == 0)
5224 skip_to_iend=MagickTrue;
5226 if (mng_info->basi_warning == 0)
5227 (void) ThrowMagickException(&image->exception,GetMagickModule(),
5228 CoderError,"BASI is not implemented yet","`%s'",
5231 mng_info->basi_warning++;
5232 #ifdef MNG_BASI_SUPPORTED
5233 basi_width=(size_t) ((p[0] << 24) | (p[1] << 16) |
5234 (p[2] << 8) | p[3]);
5235 basi_height=(size_t) ((p[4] << 24) | (p[5] << 16) |
5236 (p[6] << 8) | p[7]);
5237 basi_color_type=p[8];
5238 basi_compression_method=p[9];
5239 basi_filter_type=p[10];
5240 basi_interlace_method=p[11];
5242 basi_red=(p[12] << 8) & p[13];
5248 basi_green=(p[14] << 8) & p[15];
5254 basi_blue=(p[16] << 8) & p[17];
5260 basi_alpha=(p[18] << 8) & p[19];
5264 if (basi_sample_depth == 16)
5271 basi_viewable=p[20];
5277 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5281 if (memcmp(type,mng_IHDR,4)
5282 #if defined(JNG_SUPPORTED)
5283 && memcmp(type,mng_JHDR,4)
5287 /* Not an IHDR or JHDR chunk */
5289 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5294 if (logging != MagickFalse)
5295 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5296 " Processing %c%c%c%c chunk",type[0],type[1],type[2],type[3]);
5298 mng_info->exists[object_id]=MagickTrue;
5299 mng_info->viewable[object_id]=MagickTrue;
5301 if (mng_info->invisible[object_id])
5303 if (logging != MagickFalse)
5304 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5305 " Skipping invisible object");
5307 skip_to_iend=MagickTrue;
5308 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5311 #if defined(MNG_INSERT_LAYERS)
5313 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
5315 image_width=(size_t) mng_get_long(p);
5316 image_height=(size_t) mng_get_long(&p[4]);
5318 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5321 Insert a transparent background layer behind the entire animation
5322 if it is not full screen.
5324 #if defined(MNG_INSERT_LAYERS)
5325 if (insert_layers && mng_type && first_mng_object)
5327 if ((mng_info->clip.left > 0) || (mng_info->clip.top > 0) ||
5328 (image_width < mng_info->mng_width) ||
5329 (mng_info->clip.right < (ssize_t) mng_info->mng_width) ||
5330 (image_height < mng_info->mng_height) ||
5331 (mng_info->clip.bottom < (ssize_t) mng_info->mng_height))
5333 if (GetAuthenticPixelQueue(image) != (PixelPacket *) NULL)
5336 Allocate next image structure.
5338 AcquireNextImage(image_info,image);
5340 if (GetNextImageInList(image) == (Image *) NULL)
5342 image=DestroyImageList(image);
5343 MngInfoFreeStruct(mng_info,&have_mng_structure);
5344 return((Image *) NULL);
5347 image=SyncNextImageInList(image);
5349 mng_info->image=image;
5351 if (term_chunk_found)
5353 image->start_loop=MagickTrue;
5354 image->iterations=mng_iterations;
5355 term_chunk_found=MagickFalse;
5359 image->start_loop=MagickFalse;
5361 /* Make a background rectangle. */
5364 image->columns=mng_info->mng_width;
5365 image->rows=mng_info->mng_height;
5366 image->page.width=mng_info->mng_width;
5367 image->page.height=mng_info->mng_height;
5370 image->background_color=mng_background_color;
5371 (void) SetImageBackgroundColor(image);
5372 if (logging != MagickFalse)
5373 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5374 " Inserted transparent background layer, W=%.20g, H=%.20g",
5375 (double) mng_info->mng_width,(double) mng_info->mng_height);
5379 Insert a background layer behind the upcoming image if
5380 framing_mode is 3, and we haven't already inserted one.
5382 if (insert_layers && (mng_info->framing_mode == 3) &&
5383 (subframe_width) && (subframe_height) && (simplicity == 0 ||
5384 (simplicity & 0x08)))
5386 if (GetAuthenticPixelQueue(image) != (PixelPacket *) NULL)
5389 Allocate next image structure.
5391 AcquireNextImage(image_info,image);
5393 if (GetNextImageInList(image) == (Image *) NULL)
5395 image=DestroyImageList(image);
5396 MngInfoFreeStruct(mng_info,&have_mng_structure);
5397 return((Image *) NULL);
5400 image=SyncNextImageInList(image);
5403 mng_info->image=image;
5405 if (term_chunk_found)
5407 image->start_loop=MagickTrue;
5408 image->iterations=mng_iterations;
5409 term_chunk_found=MagickFalse;
5413 image->start_loop=MagickFalse;
5416 image->columns=subframe_width;
5417 image->rows=subframe_height;
5418 image->page.width=subframe_width;
5419 image->page.height=subframe_height;
5420 image->page.x=mng_info->clip.left;
5421 image->page.y=mng_info->clip.top;
5422 image->background_color=mng_background_color;
5423 image->matte=MagickFalse;
5424 (void) SetImageBackgroundColor(image);
5426 if (logging != MagickFalse)
5427 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5428 " Insert background layer, L=%.20g, R=%.20g T=%.20g, B=%.20g",
5429 (double) mng_info->clip.left,(double) mng_info->clip.right,
5430 (double) mng_info->clip.top,(double) mng_info->clip.bottom);
5432 #endif /* MNG_INSERT_LAYERS */
5433 first_mng_object=MagickFalse;
5435 if (GetAuthenticPixelQueue(image) != (PixelPacket *) NULL)
5438 Allocate next image structure.
5440 AcquireNextImage(image_info,image);
5442 if (GetNextImageInList(image) == (Image *) NULL)
5444 image=DestroyImageList(image);
5445 MngInfoFreeStruct(mng_info,&have_mng_structure);
5446 return((Image *) NULL);
5449 image=SyncNextImageInList(image);
5451 mng_info->image=image;
5452 status=SetImageProgress(image,LoadImagesTag,TellBlob(image),
5453 GetBlobSize(image));
5455 if (status == MagickFalse)
5458 if (term_chunk_found)
5460 image->start_loop=MagickTrue;
5461 term_chunk_found=MagickFalse;
5465 image->start_loop=MagickFalse;
5467 if (mng_info->framing_mode == 1 || mng_info->framing_mode == 3)
5469 image->delay=frame_delay;
5470 frame_delay=default_frame_delay;
5476 image->page.width=mng_info->mng_width;
5477 image->page.height=mng_info->mng_height;
5478 image->page.x=mng_info->x_off[object_id];
5479 image->page.y=mng_info->y_off[object_id];
5480 image->iterations=mng_iterations;
5483 Seek back to the beginning of the IHDR or JHDR chunk's length field.
5486 if (logging != MagickFalse)
5487 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5488 " Seeking back to beginning of %c%c%c%c chunk",type[0],type[1],
5491 offset=SeekBlob(image,-((ssize_t) length+12),SEEK_CUR);
5494 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
5498 mng_info->image=image;
5499 mng_info->mng_type=mng_type;
5500 mng_info->object_id=object_id;
5502 if (memcmp(type,mng_IHDR,4) == 0)
5503 image=ReadOnePNGImage(mng_info,image_info,exception);
5505 #if defined(JNG_SUPPORTED)
5507 image=ReadOneJNGImage(mng_info,image_info,exception);
5510 if (image == (Image *) NULL)
5512 if (IsImageObject(previous) != MagickFalse)
5514 (void) DestroyImageList(previous);
5515 (void) CloseBlob(previous);
5518 MngInfoFreeStruct(mng_info,&have_mng_structure);
5519 return((Image *) NULL);
5522 if (image->columns == 0 || image->rows == 0)
5524 (void) CloseBlob(image);
5525 image=DestroyImageList(image);
5526 MngInfoFreeStruct(mng_info,&have_mng_structure);
5527 return((Image *) NULL);
5530 mng_info->image=image;
5537 if (mng_info->magn_methx || mng_info->magn_methy)
5543 if (logging != MagickFalse)
5544 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5545 " Processing MNG MAGN chunk");
5547 if (mng_info->magn_methx == 1)
5549 magnified_width=mng_info->magn_ml;
5551 if (image->columns > 1)
5552 magnified_width += mng_info->magn_mr;
5554 if (image->columns > 2)
5555 magnified_width += (png_uint_32)
5556 ((image->columns-2)*(mng_info->magn_mx));
5561 magnified_width=(png_uint_32) image->columns;
5563 if (image->columns > 1)
5564 magnified_width += mng_info->magn_ml-1;
5566 if (image->columns > 2)
5567 magnified_width += mng_info->magn_mr-1;
5569 if (image->columns > 3)
5570 magnified_width += (png_uint_32)
5571 ((image->columns-3)*(mng_info->magn_mx-1));
5574 if (mng_info->magn_methy == 1)
5576 magnified_height=mng_info->magn_mt;
5578 if (image->rows > 1)
5579 magnified_height += mng_info->magn_mb;
5581 if (image->rows > 2)
5582 magnified_height += (png_uint_32)
5583 ((image->rows-2)*(mng_info->magn_my));
5588 magnified_height=(png_uint_32) image->rows;
5590 if (image->rows > 1)
5591 magnified_height += mng_info->magn_mt-1;
5593 if (image->rows > 2)
5594 magnified_height += mng_info->magn_mb-1;
5596 if (image->rows > 3)
5597 magnified_height += (png_uint_32)
5598 ((image->rows-3)*(mng_info->magn_my-1));
5601 if (magnified_height > image->rows ||
5602 magnified_width > image->columns)
5617 register PixelPacket
5629 /* Allocate next image structure. */
5631 if (logging != MagickFalse)
5632 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5633 " Allocate magnified image");
5635 AcquireNextImage(image_info,image);
5637 if (GetNextImageInList(image) == (Image *) NULL)
5639 image=DestroyImageList(image);
5640 MngInfoFreeStruct(mng_info,&have_mng_structure);
5641 return((Image *) NULL);
5644 large_image=SyncNextImageInList(image);
5646 large_image->columns=magnified_width;
5647 large_image->rows=magnified_height;
5649 magn_methx=mng_info->magn_methx;
5650 magn_methy=mng_info->magn_methy;
5652 #if (MAGICKCORE_QUANTUM_DEPTH == 32)
5653 #define QM unsigned short
5654 if (magn_methx != 1 || magn_methy != 1)
5657 Scale pixels to unsigned shorts to prevent
5658 overflow of intermediate values of interpolations
5660 for (y=0; y < (ssize_t) image->rows; y++)
5662 q=GetAuthenticPixels(image,0,y,image->columns,1,
5665 for (x=(ssize_t) image->columns-1; x >= 0; x--)
5667 q->red=ScaleQuantumToShort(q->red);
5668 q->green=ScaleQuantumToShort(q->green);
5669 q->blue=ScaleQuantumToShort(q->blue);
5670 q->opacity=ScaleQuantumToShort(q->opacity);
5674 if (SyncAuthenticPixels(image,exception) == MagickFalse)
5682 if (image->matte != MagickFalse)
5683 (void) SetImageBackgroundColor(large_image);
5687 large_image->background_color.opacity=OpaqueOpacity;
5688 (void) SetImageBackgroundColor(large_image);
5690 if (magn_methx == 4)
5693 if (magn_methx == 5)
5696 if (magn_methy == 4)
5699 if (magn_methy == 5)
5703 /* magnify the rows into the right side of the large image */
5705 if (logging != MagickFalse)
5706 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5707 " Magnify the rows to %.20g",(double) large_image->rows);
5708 m=(ssize_t) mng_info->magn_mt;
5710 length=(size_t) image->columns;
5711 next=(PixelPacket *) AcquireQuantumMemory(length,sizeof(*next));
5712 prev=(PixelPacket *) AcquireQuantumMemory(length,sizeof(*prev));
5714 if ((prev == (PixelPacket *) NULL) ||
5715 (next == (PixelPacket *) NULL))
5717 image=DestroyImageList(image);
5718 MngInfoFreeStruct(mng_info,&have_mng_structure);
5719 ThrowReaderException(ResourceLimitError,
5720 "MemoryAllocationFailed");
5723 n=GetAuthenticPixels(image,0,0,image->columns,1,exception);
5724 (void) CopyMagickMemory(next,n,length);
5726 for (y=0; y < (ssize_t) image->rows; y++)
5729 m=(ssize_t) mng_info->magn_mt;
5731 else if (magn_methy > 1 && y == (ssize_t) image->rows-2)
5732 m=(ssize_t) mng_info->magn_mb;
5734 else if (magn_methy <= 1 && y == (ssize_t) image->rows-1)
5735 m=(ssize_t) mng_info->magn_mb;
5737 else if (magn_methy > 1 && y == (ssize_t) image->rows-1)
5741 m=(ssize_t) mng_info->magn_my;
5747 if (y < (ssize_t) image->rows-1)
5749 n=GetAuthenticPixels(image,0,y+1,image->columns,1,
5751 (void) CopyMagickMemory(next,n,length);
5754 for (i=0; i < m; i++, yy++)
5756 register PixelPacket
5759 assert(yy < (ssize_t) large_image->rows);
5762 q=GetAuthenticPixels(large_image,0,yy,large_image->columns,
5764 q+=(large_image->columns-image->columns);
5766 for (x=(ssize_t) image->columns-1; x >= 0; x--)
5768 /* TO DO: get color as function of indexes[x] */
5770 if (image->storage_class == PseudoClass)
5775 if (magn_methy <= 1)
5777 *q=(*pixels); /* replicate previous */
5780 else if (magn_methy == 2 || magn_methy == 4)
5788 (*q).red=(QM) (((ssize_t) (2*i*((*n).red
5789 -(*pixels).red)+m))/((ssize_t) (m*2))
5791 (*q).green=(QM) (((ssize_t) (2*i*((*n).green
5792 -(*pixels).green)+m))/((ssize_t) (m*2))
5794 (*q).blue=(QM) (((ssize_t) (2*i*((*n).blue
5795 -(*pixels).blue)+m))/((ssize_t) (m*2))
5798 if (image->matte != MagickFalse)
5799 (*q).opacity=(QM) (((ssize_t)
5801 -(*pixels).opacity)+m))
5802 /((ssize_t) (m*2))+(*pixels).opacity);
5805 if (magn_methy == 4)
5807 /* Replicate nearest */
5808 if (i <= ((m+1) << 1))
5809 (*q).opacity=(*pixels).opacity+0;
5811 (*q).opacity=(*n).opacity+0;
5815 else /* if (magn_methy == 3 || magn_methy == 5) */
5817 /* Replicate nearest */
5818 if (i <= ((m+1) << 1))
5824 if (magn_methy == 5)
5826 (*q).opacity=(QM) (((ssize_t) (2*i*((*n).opacity
5827 -(*pixels).opacity)+m))/((ssize_t) (m*2))
5828 +(*pixels).opacity);
5836 if (SyncAuthenticPixels(large_image,exception) == 0)
5842 prev=(PixelPacket *) RelinquishMagickMemory(prev);
5843 next=(PixelPacket *) RelinquishMagickMemory(next);
5845 length=image->columns;
5847 if (logging != MagickFalse)
5848 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5849 " Delete original image");
5851 DeleteImageFromList(&image);
5855 mng_info->image=image;
5857 /* magnify the columns */
5858 if (logging != MagickFalse)
5859 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5860 " Magnify the columns to %.20g",(double) image->columns);
5862 for (y=0; y < (ssize_t) image->rows; y++)
5864 register PixelPacket
5867 q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
5868 pixels=q+(image->columns-length);
5871 for (x=(ssize_t) (image->columns-length);
5872 x < (ssize_t) image->columns; x++)
5874 if (x == (ssize_t) (image->columns-length))
5875 m=(ssize_t) mng_info->magn_ml;
5877 else if (magn_methx > 1 && x == (ssize_t) image->columns-2)
5878 m=(ssize_t) mng_info->magn_mr;
5880 else if (magn_methx <= 1 && x == (ssize_t) image->columns-1)
5881 m=(ssize_t) mng_info->magn_mr;
5883 else if (magn_methx > 1 && x == (ssize_t) image->columns-1)
5887 m=(ssize_t) mng_info->magn_mx;
5889 for (i=0; i < m; i++)
5891 if (magn_methx <= 1)
5893 /* replicate previous */
5897 else if (magn_methx == 2 || magn_methx == 4)
5905 (*q).red=(QM) ((2*i*((*n).red
5907 /((ssize_t) (m*2))+(*pixels).red);
5908 (*q).green=(QM) ((2*i*((*n).green
5910 +m)/((ssize_t) (m*2))+(*pixels).green);
5911 (*q).blue=(QM) ((2*i*((*n).blue
5913 /((ssize_t) (m*2))+(*pixels).blue);
5914 if (image->matte != MagickFalse)
5915 (*q).opacity=(QM) ((2*i*((*n).opacity
5916 -(*pixels).opacity)+m)/((ssize_t) (m*2))
5917 +(*pixels).opacity);
5920 if (magn_methx == 4)
5922 /* Replicate nearest */
5923 if (i <= ((m+1) << 1))
5924 (*q).opacity=(*pixels).opacity+0;
5926 (*q).opacity=(*n).opacity+0;
5930 else /* if (magn_methx == 3 || magn_methx == 5) */
5932 /* Replicate nearest */
5933 if (i <= ((m+1) << 1))
5939 if (magn_methx == 5)
5942 (*q).opacity=(QM) ((2*i*((*n).opacity
5943 -(*pixels).opacity)+m) /((ssize_t) (m*2))
5944 +(*pixels).opacity);
5953 if (SyncAuthenticPixels(image,exception) == MagickFalse)
5956 #if (MAGICKCORE_QUANTUM_DEPTH == 32)
5957 if (magn_methx != 1 || magn_methy != 1)
5960 Rescale pixels to Quantum
5962 for (y=0; y < (ssize_t) image->rows; y++)
5964 q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
5966 for (x=(ssize_t) image->columns-1; x >= 0; x--)
5968 q->red=ScaleShortToQuantum(q->red);
5969 q->green=ScaleShortToQuantum(q->green);
5970 q->blue=ScaleShortToQuantum(q->blue);
5971 q->opacity=ScaleShortToQuantum(q->opacity);
5975 if (SyncAuthenticPixels(image,exception) == MagickFalse)
5980 if (logging != MagickFalse)
5981 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5982 " Finished MAGN processing");
5987 Crop_box is with respect to the upper left corner of the MNG.
5989 crop_box.left=mng_info->image_box.left+mng_info->x_off[object_id];
5990 crop_box.right=mng_info->image_box.right+mng_info->x_off[object_id];
5991 crop_box.top=mng_info->image_box.top+mng_info->y_off[object_id];
5992 crop_box.bottom=mng_info->image_box.bottom+mng_info->y_off[object_id];
5993 crop_box=mng_minimum_box(crop_box,mng_info->clip);
5994 crop_box=mng_minimum_box(crop_box,mng_info->frame);
5995 crop_box=mng_minimum_box(crop_box,mng_info->object_clip[object_id]);
5996 if ((crop_box.left != (mng_info->image_box.left
5997 +mng_info->x_off[object_id])) ||
5998 (crop_box.right != (mng_info->image_box.right
5999 +mng_info->x_off[object_id])) ||
6000 (crop_box.top != (mng_info->image_box.top
6001 +mng_info->y_off[object_id])) ||
6002 (crop_box.bottom != (mng_info->image_box.bottom
6003 +mng_info->y_off[object_id])))
6005 if (logging != MagickFalse)
6006 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6007 " Crop the PNG image");
6009 if ((crop_box.left < crop_box.right) &&
6010 (crop_box.top < crop_box.bottom))
6019 Crop_info is with respect to the upper left corner of
6022 crop_info.x=(crop_box.left-mng_info->x_off[object_id]);
6023 crop_info.y=(crop_box.top-mng_info->y_off[object_id]);
6024 crop_info.width=(size_t) (crop_box.right-crop_box.left);
6025 crop_info.height=(size_t) (crop_box.bottom-crop_box.top);
6026 image->page.width=image->columns;
6027 image->page.height=image->rows;
6030 im=CropImage(image,&crop_info,exception);
6032 if (im != (Image *) NULL)
6034 image->columns=im->columns;
6035 image->rows=im->rows;
6036 im=DestroyImage(im);
6037 image->page.width=image->columns;
6038 image->page.height=image->rows;
6039 image->page.x=crop_box.left;
6040 image->page.y=crop_box.top;
6047 No pixels in crop area. The MNG spec still requires
6048 a layer, though, so make a single transparent pixel in
6049 the top left corner.
6054 (void) SetImageBackgroundColor(image);
6055 image->page.width=1;
6056 image->page.height=1;
6061 #ifndef PNG_READ_EMPTY_PLTE_SUPPORTED
6062 image=mng_info->image;
6066 #if (MAGICKCORE_QUANTUM_DEPTH > 16)
6067 /* PNG does not handle depths greater than 16 so reduce it even
6070 if (image->depth > 16)
6074 #if (MAGICKCORE_QUANTUM_DEPTH >= 16)
6075 if (LosslessReduceDepthOK(image) != MagickFalse)
6079 GetImageException(image,exception);
6081 if (image_info->number_scenes != 0)
6083 if (mng_info->scenes_found >
6084 (ssize_t) (image_info->first_scene+image_info->number_scenes))
6088 if (logging != MagickFalse)
6089 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6090 " Finished reading image datastream.");
6092 } while (LocaleCompare(image_info->magick,"MNG") == 0);
6094 (void) CloseBlob(image);
6096 if (logging != MagickFalse)
6097 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6098 " Finished reading all image datastreams.");
6100 #if defined(MNG_INSERT_LAYERS)
6101 if (insert_layers && !mng_info->image_found && (mng_info->mng_width) &&
6102 (mng_info->mng_height))
6105 Insert a background layer if nothing else was found.
6107 if (logging != MagickFalse)
6108 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6109 " No images found. Inserting a background layer.");
6111 if (GetAuthenticPixelQueue(image) != (PixelPacket *) NULL)
6114 Allocate next image structure.
6116 AcquireNextImage(image_info,image);
6117 if (GetNextImageInList(image) == (Image *) NULL)
6119 image=DestroyImageList(image);
6120 MngInfoFreeStruct(mng_info,&have_mng_structure);
6122 if (logging != MagickFalse)
6123 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6124 " Allocation failed, returning NULL.");
6126 return((Image *) NULL);
6128 image=SyncNextImageInList(image);
6130 image->columns=mng_info->mng_width;
6131 image->rows=mng_info->mng_height;
6132 image->page.width=mng_info->mng_width;
6133 image->page.height=mng_info->mng_height;
6136 image->background_color=mng_background_color;
6137 image->matte=MagickFalse;
6139 if (image_info->ping == MagickFalse)
6140 (void) SetImageBackgroundColor(image);
6142 mng_info->image_found++;
6145 image->iterations=mng_iterations;
6147 if (mng_iterations == 1)
6148 image->start_loop=MagickTrue;
6150 while (GetPreviousImageInList(image) != (Image *) NULL)
6153 if (image_count > 10*mng_info->image_found)
6155 if (logging != MagickFalse)
6156 (void) LogMagickEvent(CoderEvent,GetMagickModule()," No beginning");
6158 (void) ThrowMagickException(&image->exception,GetMagickModule(),
6159 CoderError,"Linked list is corrupted, beginning of list not found",
6160 "`%s'",image_info->filename);
6162 return((Image *) NULL);
6165 image=GetPreviousImageInList(image);
6167 if (GetNextImageInList(image) == (Image *) NULL)
6169 if (logging != MagickFalse)
6170 (void) LogMagickEvent(CoderEvent,GetMagickModule()," Corrupt list");
6172 (void) ThrowMagickException(&image->exception,GetMagickModule(),
6173 CoderError,"Linked list is corrupted; next_image is NULL","`%s'",
6174 image_info->filename);
6178 if (mng_info->ticks_per_second && mng_info->image_found > 1 &&
6179 GetNextImageInList(image) ==
6182 if (logging != MagickFalse)
6183 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6184 " First image null");
6186 (void) ThrowMagickException(&image->exception,GetMagickModule(),
6187 CoderError,"image->next for first image is NULL but shouldn't be.",
6188 "`%s'",image_info->filename);
6191 if (mng_info->image_found == 0)
6193 if (logging != MagickFalse)
6194 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6195 " No visible images found.");
6197 (void) ThrowMagickException(&image->exception,GetMagickModule(),
6198 CoderError,"No visible images in file","`%s'",image_info->filename);
6200 if (image != (Image *) NULL)
6201 image=DestroyImageList(image);
6203 MngInfoFreeStruct(mng_info,&have_mng_structure);
6204 return((Image *) NULL);
6207 if (mng_info->ticks_per_second)
6208 final_delay=1UL*MagickMax(image->ticks_per_second,1L)*
6209 final_delay/mng_info->ticks_per_second;
6212 image->start_loop=MagickTrue;
6214 /* Find final nonzero image delay */
6215 final_image_delay=0;
6217 while (GetNextImageInList(image) != (Image *) NULL)
6220 final_image_delay=image->delay;
6222 image=GetNextImageInList(image);
6225 if (final_delay < final_image_delay)
6226 final_delay=final_image_delay;
6228 image->delay=final_delay;
6230 if (logging != MagickFalse)
6231 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6232 " image->delay=%.20g, final_delay=%.20g",(double) image->delay,
6233 (double) final_delay);
6235 if (logging != MagickFalse)
6241 image=GetFirstImageInList(image);
6243 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6244 " Before coalesce:");
6246 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6247 " scene 0 delay=%.20g",(double) image->delay);
6249 while (GetNextImageInList(image) != (Image *) NULL)
6251 image=GetNextImageInList(image);
6252 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6253 " scene %.20g delay=%.20g",(double) scene++,(double) image->delay);
6257 image=GetFirstImageInList(image);
6258 #ifdef MNG_COALESCE_LAYERS
6268 if (logging != MagickFalse)
6269 (void) LogMagickEvent(CoderEvent,GetMagickModule()," Coalesce Images");
6272 next_image=CoalesceImages(image,&image->exception);
6274 if (next_image == (Image *) NULL)
6275 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
6277 image=DestroyImageList(image);
6280 for (next=image; next != (Image *) NULL; next=next_image)
6282 next->page.width=mng_info->mng_width;
6283 next->page.height=mng_info->mng_height;
6286 next->scene=scene++;
6287 next_image=GetNextImageInList(next);
6289 if (next_image == (Image *) NULL)
6292 if (next->delay == 0)
6295 next_image->previous=GetPreviousImageInList(next);
6296 if (GetPreviousImageInList(next) == (Image *) NULL)
6299 next->previous->next=next_image;
6300 next=DestroyImage(next);
6306 while (GetNextImageInList(image) != (Image *) NULL)
6307 image=GetNextImageInList(image);
6309 image->dispose=BackgroundDispose;
6311 if (logging != MagickFalse)
6317 image=GetFirstImageInList(image);
6319 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6320 " After coalesce:");
6322 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6323 " scene 0 delay=%.20g dispose=%.20g",(double) image->delay,
6324 (double) image->dispose);
6326 while (GetNextImageInList(image) != (Image *) NULL)
6328 image=GetNextImageInList(image);
6330 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6331 " scene %.20g delay=%.20g dispose=%.20g",(double) scene++,
6332 (double) image->delay,(double) image->dispose);
6336 image=GetFirstImageInList(image);
6337 MngInfoFreeStruct(mng_info,&have_mng_structure);
6338 have_mng_structure=MagickFalse;
6340 if (logging != MagickFalse)
6341 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"exit ReadMNGImage()");
6343 return(GetFirstImageInList(image));
6345 #else /* PNG_LIBPNG_VER > 10011 */
6346 static Image *ReadPNGImage(const ImageInfo *image_info,ExceptionInfo *exception)
6348 printf("Your PNG library is too old: You have libpng-%s\n",
6349 PNG_LIBPNG_VER_STRING);
6351 (void) ThrowMagickException(exception,GetMagickModule(),CoderError,
6352 "PNG library is too old","`%s'",image_info->filename);
6354 return(Image *) NULL;
6357 static Image *ReadMNGImage(const ImageInfo *image_info,ExceptionInfo *exception)
6359 return(ReadPNGImage(image_info,exception));
6361 #endif /* PNG_LIBPNG_VER > 10011 */
6365 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6369 % R e g i s t e r P N G I m a g e %
6373 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6375 % RegisterPNGImage() adds properties for the PNG image format to
6376 % the list of supported formats. The properties include the image format
6377 % tag, a method to read and/or write the format, whether the format
6378 % supports the saving of more than one frame to the same file or blob,
6379 % whether the format supports native in-memory I/O, and a brief
6380 % description of the format.
6382 % The format of the RegisterPNGImage method is:
6384 % size_t RegisterPNGImage(void)
6387 ModuleExport size_t RegisterPNGImage(void)
6390 version[MaxTextExtent];
6398 "See http://www.libpng.org/ for details about the PNG format."
6403 "See http://www.libpng.org/pub/mng/ for details about the JNG\n"
6409 "See http://www.libpng.org/pub/mng/ for details about the MNG\n"
6415 #if defined(PNG_LIBPNG_VER_STRING)
6416 (void) ConcatenateMagickString(version,"libpng ",MaxTextExtent);
6417 (void) ConcatenateMagickString(version,PNG_LIBPNG_VER_STRING,MaxTextExtent);
6419 if (LocaleCompare(PNG_LIBPNG_VER_STRING,png_get_header_ver(NULL)) != 0)
6421 (void) ConcatenateMagickString(version,",",MaxTextExtent);
6422 (void) ConcatenateMagickString(version,png_get_libpng_ver(NULL),
6427 entry=SetMagickInfo("MNG");
6428 entry->seekable_stream=MagickTrue; /* To do: eliminate this. */
6430 #if defined(MAGICKCORE_PNG_DELEGATE)
6431 entry->decoder=(DecodeImageHandler *) ReadMNGImage;
6432 entry->encoder=(EncodeImageHandler *) WriteMNGImage;
6435 entry->magick=(IsImageFormatHandler *) IsMNG;
6436 entry->description=ConstantString("Multiple-image Network Graphics");
6438 if (*version != '\0')
6439 entry->version=ConstantString(version);
6441 entry->module=ConstantString("PNG");
6442 entry->note=ConstantString(MNGNote);
6443 (void) RegisterMagickInfo(entry);
6445 entry=SetMagickInfo("PNG");
6447 #if defined(MAGICKCORE_PNG_DELEGATE)
6448 entry->decoder=(DecodeImageHandler *) ReadPNGImage;
6449 entry->encoder=(EncodeImageHandler *) WritePNGImage;
6452 entry->magick=(IsImageFormatHandler *) IsPNG;
6453 entry->adjoin=MagickFalse;
6454 entry->description=ConstantString("Portable Network Graphics");
6455 entry->module=ConstantString("PNG");
6457 if (*version != '\0')
6458 entry->version=ConstantString(version);
6460 entry->note=ConstantString(PNGNote);
6461 (void) RegisterMagickInfo(entry);
6463 entry=SetMagickInfo("PNG8");
6465 #if defined(MAGICKCORE_PNG_DELEGATE)
6466 entry->decoder=(DecodeImageHandler *) ReadPNGImage;
6467 entry->encoder=(EncodeImageHandler *) WritePNGImage;
6470 entry->magick=(IsImageFormatHandler *) IsPNG;
6471 entry->adjoin=MagickFalse;
6472 entry->description=ConstantString(
6473 "8-bit indexed with optional binary transparency");
6474 entry->module=ConstantString("PNG");
6475 (void) RegisterMagickInfo(entry);
6477 entry=SetMagickInfo("PNG24");
6480 #if defined(ZLIB_VERSION)
6481 (void) ConcatenateMagickString(version,"zlib ",MaxTextExtent);
6482 (void) ConcatenateMagickString(version,ZLIB_VERSION,MaxTextExtent);
6484 if (LocaleCompare(ZLIB_VERSION,zlib_version) != 0)
6486 (void) ConcatenateMagickString(version,",",MaxTextExtent);
6487 (void) ConcatenateMagickString(version,zlib_version,MaxTextExtent);
6491 if (*version != '\0')
6492 entry->version=ConstantString(version);
6494 #if defined(MAGICKCORE_PNG_DELEGATE)
6495 entry->decoder=(DecodeImageHandler *) ReadPNGImage;
6496 entry->encoder=(EncodeImageHandler *) WritePNGImage;
6499 entry->magick=(IsImageFormatHandler *) IsPNG;
6500 entry->adjoin=MagickFalse;
6501 entry->description=ConstantString("opaque 24-bit RGB");
6502 entry->module=ConstantString("PNG");
6503 (void) RegisterMagickInfo(entry);
6505 entry=SetMagickInfo("PNG32");
6507 #if defined(MAGICKCORE_PNG_DELEGATE)
6508 entry->decoder=(DecodeImageHandler *) ReadPNGImage;
6509 entry->encoder=(EncodeImageHandler *) WritePNGImage;
6512 entry->magick=(IsImageFormatHandler *) IsPNG;
6513 entry->adjoin=MagickFalse;
6514 entry->description=ConstantString("opaque or transparent 32-bit RGBA");
6515 entry->module=ConstantString("PNG");
6516 (void) RegisterMagickInfo(entry);
6518 entry=SetMagickInfo("JNG");
6520 #if defined(JNG_SUPPORTED)
6521 #if defined(MAGICKCORE_PNG_DELEGATE)
6522 entry->decoder=(DecodeImageHandler *) ReadJNGImage;
6523 entry->encoder=(EncodeImageHandler *) WriteJNGImage;
6527 entry->magick=(IsImageFormatHandler *) IsJNG;
6528 entry->adjoin=MagickFalse;
6529 entry->description=ConstantString("JPEG Network Graphics");
6530 entry->module=ConstantString("PNG");
6531 entry->note=ConstantString(JNGNote);
6532 (void) RegisterMagickInfo(entry);
6534 #if defined(PNG_SETJMP_NOT_THREAD_SAFE)
6535 ping_semaphore=AllocateSemaphoreInfo();
6538 return(MagickImageCoderSignature);
6542 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6546 % U n r e g i s t e r P N G I m a g e %
6550 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6552 % UnregisterPNGImage() removes format registrations made by the
6553 % PNG module from the list of supported formats.
6555 % The format of the UnregisterPNGImage method is:
6557 % UnregisterPNGImage(void)
6560 ModuleExport void UnregisterPNGImage(void)
6562 (void) UnregisterMagickInfo("MNG");
6563 (void) UnregisterMagickInfo("PNG");
6564 (void) UnregisterMagickInfo("PNG8");
6565 (void) UnregisterMagickInfo("PNG24");
6566 (void) UnregisterMagickInfo("PNG32");
6567 (void) UnregisterMagickInfo("JNG");
6569 #if defined(PNG_SETJMP_NOT_THREAD_SAFE)
6570 if (ping_semaphore != (SemaphoreInfo *) NULL)
6571 DestroySemaphoreInfo(&ping_semaphore);
6575 #if defined(MAGICKCORE_PNG_DELEGATE)
6576 #if PNG_LIBPNG_VER > 10011
6578 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6582 % W r i t e M N G I m a g e %
6586 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6588 % WriteMNGImage() writes an image in the Portable Network Graphics
6589 % Group's "Multiple-image Network Graphics" encoded image format.
6591 % MNG support written by Glenn Randers-Pehrson, glennrp@image...
6593 % The format of the WriteMNGImage method is:
6595 % MagickBooleanType WriteMNGImage(const ImageInfo *image_info,Image *image)
6597 % A description of each parameter follows.
6599 % o image_info: the image info.
6601 % o image: The image.
6604 % To do (as of version 5.5.2, November 26, 2002 -- glennrp -- see also
6605 % "To do" under ReadPNGImage):
6607 % Preserve all unknown and not-yet-handled known chunks found in input
6608 % PNG file and copy them into output PNG files according to the PNG
6611 % Write the iCCP chunk at MNG level when (icc profile length > 0)
6613 % Improve selection of color type (use indexed-colour or indexed-colour
6614 % with tRNS when 256 or fewer unique RGBA values are present).
6616 % Figure out what to do with "dispose=<restore-to-previous>" (dispose == 3)
6617 % This will be complicated if we limit ourselves to generating MNG-LC
6618 % files. For now we ignore disposal method 3 and simply overlay the next
6621 % Check for identical PLTE's or PLTE/tRNS combinations and use a
6622 % global MNG PLTE or PLTE/tRNS combination when appropriate.
6623 % [mostly done 15 June 1999 but still need to take care of tRNS]
6625 % Check for identical sRGB and replace with a global sRGB (and remove
6626 % gAMA/cHRM if sRGB is found; check for identical gAMA/cHRM and
6627 % replace with global gAMA/cHRM (or with sRGB if appropriate; replace
6628 % local gAMA/cHRM with local sRGB if appropriate).
6630 % Check for identical sBIT chunks and write global ones.
6632 % Provide option to skip writing the signature tEXt chunks.
6634 % Use signatures to detect identical objects and reuse the first
6635 % instance of such objects instead of writing duplicate objects.
6637 % Use a smaller-than-32k value of compression window size when
6640 % Encode JNG datastreams. Mostly done as of 5.5.2; need to write
6641 % ancillary text chunks and save profiles.
6643 % Provide an option to force LC files (to ensure exact framing rate)
6646 % Provide an option to force VLC files instead of LC, even when offsets
6647 % are present. This will involve expanding the embedded images with a
6648 % transparent region at the top and/or left.
6652 Magick_png_write_raw_profile(const ImageInfo *image_info,png_struct *ping,
6653 png_info *ping_info, unsigned char *profile_type, unsigned char
6654 *profile_description, unsigned char *profile_data, png_uint_32 length)
6673 hex[16]={'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
6675 if (LocaleNCompare((char *) profile_type+1, "ng-chunk-",9) == 0)
6678 if (image_info->verbose)
6680 (void) printf("writing raw profile: type=%s, length=%.20g\n",
6681 (char *) profile_type, (double) length);
6684 text=(png_textp) png_malloc(ping,(png_uint_32) sizeof(png_text));
6685 description_length=(png_uint_32) strlen((const char *) profile_description);
6686 allocated_length=(png_uint_32) (length*2 + (length >> 5) + 20
6687 + description_length);
6688 text[0].text=(png_charp) png_malloc(ping,allocated_length);
6689 text[0].key=(png_charp) png_malloc(ping, (png_uint_32) 80);
6690 text[0].key[0]='\0';
6691 (void) ConcatenateMagickString(text[0].key,
6692 "Raw profile type ",MaxTextExtent);
6693 (void) ConcatenateMagickString(text[0].key,(const char *) profile_type,62);
6697 (void) CopyMagickString(dp,(const char *) profile_description,
6699 dp+=description_length;
6701 (void) FormatMagickString(dp,allocated_length-
6702 (png_size_t) (dp-text[0].text),"%8lu ",(unsigned long) length);
6705 for (i=0; i < (ssize_t) length; i++)
6709 *(dp++)=(char) hex[((*sp >> 4) & 0x0f)];
6710 *(dp++)=(char) hex[((*sp++ ) & 0x0f)];
6715 text[0].text_length=(png_size_t) (dp-text[0].text);
6716 text[0].compression=image_info->compression == NoCompression ||
6717 (image_info->compression == UndefinedCompression &&
6718 text[0].text_length < 128) ? -1 : 0;
6720 if (text[0].text_length <= allocated_length)
6721 png_set_text(ping,ping_info,text,1);
6723 png_free(ping,text[0].text);
6724 png_free(ping,text[0].key);
6725 png_free(ping,text);
6728 static MagickBooleanType Magick_png_write_chunk_from_profile(Image *image,
6729 const char *string, MagickBooleanType logging)
6742 ResetImageProfileIterator(image);
6744 for (name=GetNextImageProfile(image); name != (const char *) NULL; )
6746 profile=GetImageProfile(image,name);
6748 if (profile != (const StringInfo *) NULL)
6753 if (LocaleNCompare(name,string,11) == 0)
6755 if (logging != MagickFalse)
6756 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6757 " Found %s profile",name);
6759 ping_profile=CloneStringInfo(profile);
6760 data=GetStringInfoDatum(ping_profile),
6761 length=(png_uint_32) GetStringInfoLength(ping_profile);
6766 (void) WriteBlobMSBULong(image,length-5); /* data length */
6767 (void) WriteBlob(image,length-1,data+1);
6768 (void) WriteBlobMSBULong(image,crc32(0,data+1,(uInt) length-1));
6769 ping_profile=DestroyStringInfo(ping_profile);
6773 name=GetNextImageProfile(image);
6780 /* Write one PNG image */
6781 static MagickBooleanType WriteOnePNGImage(MngInfo *mng_info,
6782 const ImageInfo *IMimage_info,Image *IMimage)
6806 ping_trans_alpha[256];
6841 /* ping_exclude_EXIF, */
6844 /* ping_exclude_iTXt, */
6849 /* ping_exclude_tRNS, */
6851 ping_exclude_zCCP, /* hex-encoded iCCP */
6854 ping_need_colortype_warning,
6872 ping_interlace_method,
6873 ping_compression_method,
6889 number_semitransparent,
6891 ping_pHYs_unit_type;
6894 ping_pHYs_x_resolution,
6895 ping_pHYs_y_resolution;
6897 logging=LogMagickEvent(CoderEvent,GetMagickModule(),
6898 " enter WriteOnePNGImage()");
6900 image = CloneImage(IMimage,0,0,MagickFalse,&IMimage->exception);
6901 image_info=(ImageInfo *) CloneImageInfo(IMimage_info);
6903 if (mng_info->need_blob != MagickFalse)
6905 if (OpenBlob(image_info,image,WriteBinaryBlobMode,&image->exception) ==
6908 image_info=DestroyImageInfo(image_info);
6909 image=DestroyImage(image);
6910 return(MagickFalse);
6914 #if defined(PNG_SETJMP_NOT_THREAD_SAFE)
6915 LockSemaphoreInfo(ping_semaphore);
6918 /* Initialize some stuff */
6921 ping_interlace_method=0,
6922 ping_compression_method=0,
6923 ping_filter_method=0,
6926 ping_background.red = 0;
6927 ping_background.green = 0;
6928 ping_background.blue = 0;
6929 ping_background.gray = 0;
6930 ping_background.index = 0;
6932 ping_trans_color.red=0;
6933 ping_trans_color.green=0;
6934 ping_trans_color.blue=0;
6935 ping_trans_color.gray=0;
6937 ping_pHYs_unit_type = 0;
6938 ping_pHYs_x_resolution = 0;
6939 ping_pHYs_y_resolution = 0;
6941 ping_have_color=MagickTrue;
6942 ping_have_PLTE=MagickFalse;
6943 ping_have_bKGD=MagickFalse;
6944 ping_have_pHYs=MagickFalse;
6945 ping_have_tRNS=MagickFalse;
6947 ping_exclude_bKGD=mng_info->ping_exclude_bKGD;
6948 ping_exclude_cHRM=mng_info->ping_exclude_cHRM;
6949 /* ping_exclude_EXIF=mng_info->ping_exclude_EXIF; */
6950 ping_exclude_gAMA=mng_info->ping_exclude_gAMA;
6951 ping_exclude_cHRM=mng_info->ping_exclude_cHRM;
6952 ping_exclude_iCCP=mng_info->ping_exclude_iCCP;
6953 /* ping_exclude_iTXt=mng_info->ping_exclude_iTXt; */
6954 ping_exclude_oFFs=mng_info->ping_exclude_oFFs;
6955 ping_exclude_pHYs=mng_info->ping_exclude_pHYs;
6956 ping_exclude_sRGB=mng_info->ping_exclude_sRGB;
6957 ping_exclude_tEXt=mng_info->ping_exclude_tEXt;
6958 /* ping_exclude_tRNS=mng_info->ping_exclude_tRNS; */
6959 ping_exclude_vpAg=mng_info->ping_exclude_vpAg;
6960 ping_exclude_zCCP=mng_info->ping_exclude_zCCP; /* hex-encoded iCCP in zTXt */
6961 ping_exclude_zTXt=mng_info->ping_exclude_zTXt;
6963 ping_need_colortype_warning = MagickFalse;
6966 number_semitransparent = 0;
6967 number_transparent = 0;
6969 if (image->colorspace != RGBColorspace)
6970 (void) TransformImageColorspace(image,RGBColorspace);
6973 Sometimes we get PseudoClass images whose RGB values don't match
6974 the colors in the colormap. This code syncs the RGB values.
6976 if (image->depth <= 8 && image->taint && image->storage_class == PseudoClass)
6977 (void) SyncImage(image);
6979 #if (MAGICKCORE_QUANTUM_DEPTH == 8)
6980 if (image->depth > 8)
6982 if (logging != MagickFalse)
6983 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6984 " Reducing PNG bit depth to 8 since this is a Q8 build.");
6991 #if (MAGICKCORE_QUANTUM_DEPTH > 16)
6992 /* PNG does not handle depths greater than 16 so reduce it even
6995 if (image->depth > 16)
6999 #if (MAGICKCORE_QUANTUM_DEPTH >= 16)
7000 if (image->depth == 16 && mng_info->write_png_colortype != 16)
7001 if (mng_info->write_png8 || LosslessReduceDepthOK(image) != MagickFalse)
7005 #ifdef BUILD_PNG_PALETTE
7006 if (mng_info->write_png_colortype < 8 /* all */)
7009 * Sometimes we get DirectClass images that have 256 colors or fewer.
7010 * This code will build a colormap.
7012 * Also, sometimes we get PseudoClass images with an out-of-date
7013 * colormap. This code will replace the colormap with a new one.
7014 * Sometimes we get PseudoClass images that have more than 256 colors.
7015 * This code will delete the colormap and change the image to
7018 * If image->matte is MagickFalse, we ignore the opacity channel
7019 * even though it sometimes contains left-over non-opaque values.
7021 * Also we gather some information (number of opaque, transparent,
7022 * and semitransparent pixels, and whether the image has any non-gray
7023 * pixels) that we might need later. If the user wants to force
7024 * GrayAlpha or RGBA (colortype 4 or 6) we probably don't need any
7036 semitransparent[260],
7039 register IndexPacket
7042 register const PixelPacket
7045 if (logging != MagickFalse)
7046 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7047 " Enter BUILD_PALETTE:");
7049 if (logging != MagickFalse)
7051 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7052 " image->columns=%.20g",(double) image->columns);
7053 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7054 " image->rows=%.20g",(double) image->rows);
7055 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7056 " image->matte=%.20g",(double) image->matte);
7057 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7058 " image->depth=%.20g",(double) image->depth);
7060 if (image->colormap != NULL)
7062 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7063 " Original colormap:");
7064 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7065 " i (red,green,blue,opacity)");
7067 for (i=0; i < 256; i++)
7069 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7070 " %d (%d,%d,%d,%d)",
7072 (int) image->colormap[i].red,
7073 (int) image->colormap[i].green,
7074 (int) image->colormap[i].blue,
7075 (int) image->colormap[i].opacity);
7078 for (i=image->colors - 10; i < (ssize_t) image->colors; i++)
7082 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7083 " %d (%d,%d,%d,%d)",
7085 (int) image->colormap[i].red,
7086 (int) image->colormap[i].green,
7087 (int) image->colormap[i].blue,
7088 (int) image->colormap[i].opacity);
7093 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7094 " image->colors=%d",(int) image->colors);
7096 if (image->colors == 0)
7097 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7098 " (zero means unknown)");
7100 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7101 " Regenerate the colormap");
7104 exception=(&image->exception);
7106 ping_have_color=MagickFalse;
7109 for (y=0; y < (ssize_t) image->rows; y++)
7111 q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
7113 if (q == (PixelPacket *) NULL)
7116 for (x=0; x < (ssize_t) image->columns; x++)
7118 if (q->red != q->green || q->red != q->blue)
7119 ping_have_color=MagickTrue;
7121 if (image->matte == MagickFalse || q->opacity == OpaqueOpacity)
7123 if (number_opaque < 259)
7125 if (number_opaque == 0)
7128 opaque[0].opacity=OpaqueOpacity;
7132 for (i=0; i< (ssize_t) number_opaque; i++)
7134 if (IsColorEqual(opaque+i, (PixelPacket *) q))
7138 if (i == (ssize_t) number_opaque &&
7139 number_opaque < 259)
7143 opaque[i].opacity = OpaqueOpacity;
7147 else if (q->opacity == TransparentOpacity)
7149 if (number_transparent < 259)
7151 if (number_transparent == 0)
7154 ping_trans_color.red=(unsigned short)(q->red);
7155 ping_trans_color.green=(unsigned short) (q->green);
7156 ping_trans_color.blue=(unsigned short) (q->blue);
7157 ping_trans_color.gray=(unsigned short) (q->blue);
7158 number_transparent = 1;
7161 for (i=0; i< (ssize_t) number_transparent; i++)
7163 if (IsColorEqual(transparent+i, (PixelPacket *) q))
7167 if (i == (ssize_t) number_transparent &&
7168 number_transparent < 259)
7170 number_transparent++;
7171 transparent[i] = *q;
7177 if (number_semitransparent < 259)
7179 if (number_semitransparent == 0)
7181 semitransparent[0]=*q;
7182 number_semitransparent = 1;
7185 for (i=0; i< (ssize_t) number_semitransparent; i++)
7187 if (IsColorEqual(semitransparent+i,
7188 (PixelPacket *) q) &&
7189 q->opacity == semitransparent[i].opacity)
7193 if (i == (ssize_t) number_semitransparent &&
7194 number_semitransparent < 259)
7196 number_semitransparent++;
7197 semitransparent[i] = *q;
7205 image_colors=number_opaque+number_transparent+number_semitransparent;
7207 if (logging != MagickFalse)
7209 if (image_colors > 256)
7210 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7211 " image has more than 256 colors");
7214 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7215 " image has %d colors",image_colors);
7218 if (image_colors < 257)
7224 Initialize image colormap.
7227 if (logging != MagickFalse)
7228 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7229 " Sort the new colormap");
7231 /* Sort palette, transparent first */;
7235 for (i=0; i<number_transparent; i++)
7236 colormap[n++] = transparent[i];
7238 for (i=0; i<number_semitransparent; i++)
7239 colormap[n++] = semitransparent[i];
7241 for (i=0; i<number_opaque; i++)
7242 colormap[n++] = opaque[i];
7244 if (ping_exclude_bKGD == MagickFalse)
7246 /* Add the background color to the palette, if it
7247 * isn't already there.
7249 for (i=0; i<number_opaque; i++)
7251 if (IsColorEqual(opaque+i,
7252 &image->background_color))
7256 if (number_opaque < 257 && i == number_opaque)
7258 opaque[i]=image->background_color;
7259 opaque[i].opacity = OpaqueOpacity;
7264 if ((mng_info->ping_exclude_tRNS == MagickFalse ||
7265 (number_transparent == 0 && number_semitransparent == 0)) &&
7266 (((mng_info->write_png_colortype-1) ==
7267 PNG_COLOR_TYPE_PALETTE) ||
7268 (mng_info->write_png_colortype == 0)))
7270 if (logging != MagickFalse)
7272 if (n != (ssize_t) image_colors)
7273 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7274 " image_colors (%d) and n (%d) don't match",
7277 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7278 " AcquireImageColormap");
7281 image->colors = image_colors;
7283 if (AcquireImageColormap(image,image_colors) ==
7285 ThrowWriterException(ResourceLimitError,
7286 "MemoryAllocationFailed");
7288 for (i=0; i< (ssize_t) image_colors; i++)
7289 image->colormap[i] = colormap[i];
7291 if (logging != MagickFalse)
7293 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7294 " image->colors=%d (%d)",
7295 (int) image->colors, image_colors);
7297 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7298 " Update the pixel indexes");
7301 for (y=0; y < (ssize_t) image->rows; y++)
7303 q=GetAuthenticPixels(image,0,y,image->columns,1,
7306 if (q == (PixelPacket *) NULL)
7309 indexes=GetAuthenticIndexQueue(image);
7311 for (x=0; x < (ssize_t) image->columns; x++)
7313 for (i=0; i< (ssize_t) image_colors; i++)
7315 if ((image->matte == MagickFalse ||
7316 image->colormap[i].opacity == q->opacity) &&
7317 (IsColorEqual(&image->colormap[i],(PixelPacket *) q)))
7319 indexes[x]=(IndexPacket) i;
7326 if (SyncAuthenticPixels(image,exception) == MagickFalse)
7332 if (logging != MagickFalse)
7334 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7335 " image->colors=%d", (int) image->colors);
7337 if (image->colormap != NULL)
7339 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7340 " i (red,green,blue,opacity)");
7342 for (i=0; i < (ssize_t) image->colors; i++)
7344 if (i < 300 || i >= image->colors - 10)
7346 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7347 " %d (%d,%d,%d,%d)",
7349 (int) image->colormap[i].red,
7350 (int) image->colormap[i].green,
7351 (int) image->colormap[i].blue,
7352 (int) image->colormap[i].opacity);
7357 if (logging != MagickFalse)
7359 if (number_transparent < 257)
7360 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7361 " number_transparent = %d",
7362 number_transparent);
7365 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7366 " number_transparent > 256");
7368 if (number_opaque < 257)
7369 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7370 " number_opaque = %d",
7373 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7374 " number_opaque > 256");
7376 if (number_semitransparent < 257)
7377 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7378 " number_semitransparent = %d",
7379 number_semitransparent);
7382 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7383 " number_semitransparent > 256");
7386 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7387 " Exit BUILD_PALETTE:");
7390 #endif /* BUILD_PNG_PALETTE */
7392 if (mng_info->ping_exclude_tRNS != MagickFalse &&
7393 (number_transparent != 0 || number_semitransparent != 0))
7395 int colortype=mng_info->write_png_colortype;
7397 if (ping_have_color == MagickFalse)
7398 mng_info->write_png_colortype = 5;
7401 mng_info->write_png_colortype = 7;
7403 if (colortype != 0 && mng_info->write_png_colortype != (ssize_t) colortype)
7404 ping_need_colortype_warning=MagickTrue;
7408 image_depth=image->depth;
7410 quantum_info = (QuantumInfo *) NULL;
7412 image_colors=(int) image->colors;
7413 image_matte=image->matte;
7415 mng_info->IsPalette=image->storage_class == PseudoClass &&
7416 image_colors <= 256;
7419 Allocate the PNG structures
7421 #ifdef PNG_USER_MEM_SUPPORTED
7422 ping=png_create_write_struct_2(PNG_LIBPNG_VER_STRING,image,
7423 MagickPNGErrorHandler,MagickPNGWarningHandler,(void *) NULL,
7424 (png_malloc_ptr) Magick_png_malloc,(png_free_ptr) Magick_png_free);
7427 ping=png_create_write_struct(PNG_LIBPNG_VER_STRING,image,
7428 MagickPNGErrorHandler,MagickPNGWarningHandler);
7431 if (ping == (png_struct *) NULL)
7432 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
7434 ping_info=png_create_info_struct(ping);
7436 if (ping_info == (png_info *) NULL)
7438 png_destroy_write_struct(&ping,(png_info **) NULL);
7439 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
7442 png_set_write_fn(ping,image,png_put_data,png_flush_data);
7443 ping_pixels=(unsigned char *) NULL;
7445 if (setjmp(png_jmpbuf(ping)))
7451 if (image_info->verbose)
7452 (void) printf("PNG write has failed.\n");
7454 png_destroy_write_struct(&ping,&ping_info);
7455 #if defined(PNG_SETJMP_NOT_THREAD_SAFE)
7456 UnlockSemaphoreInfo(ping_semaphore);
7458 if (mng_info->need_blob != MagickFalse)
7459 (void) CloseBlob(image);
7460 image_info=DestroyImageInfo(image_info);
7461 image=DestroyImage(image);
7462 return(MagickFalse);
7465 Prepare PNG for writing.
7467 #if defined(PNG_MNG_FEATURES_SUPPORTED)
7468 if (mng_info->write_mng)
7469 (void) png_permit_mng_features(ping,PNG_ALL_MNG_FEATURES);
7472 # ifdef PNG_WRITE_EMPTY_PLTE_SUPPORTED
7473 if (mng_info->write_mng)
7474 png_permit_empty_plte(ping,MagickTrue);
7481 ping_width=(png_uint_32) image->columns;
7482 ping_height=(png_uint_32) image->rows;
7484 if (mng_info->write_png8 || mng_info->write_png24 || mng_info->write_png32)
7487 if (mng_info->write_png_depth != 0)
7488 image_depth=mng_info->write_png_depth;
7490 /* Adjust requested depth to next higher valid depth if necessary */
7491 if (image_depth > 8)
7494 if ((image_depth > 4) && (image_depth < 8))
7497 if (image_depth == 3)
7500 if (logging != MagickFalse)
7502 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7503 " width=%.20g",(double) ping_width);
7504 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7505 " height=%.20g",(double) ping_height);
7506 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7507 " image_matte=%.20g",(double) image->matte);
7508 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7509 " image->depth=%.20g",(double) image->depth);
7510 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7511 " Tentative ping_bit_depth=%.20g",(double) image_depth);
7514 save_image_depth=image_depth;
7515 ping_bit_depth=(png_byte) save_image_depth;
7518 #if defined(PNG_pHYs_SUPPORTED)
7519 if (ping_exclude_pHYs == MagickFalse)
7521 if ((image->x_resolution != 0) && (image->y_resolution != 0) &&
7522 (!mng_info->write_mng || !mng_info->equal_physs))
7524 if (logging != MagickFalse)
7525 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7526 " Setting up pHYs chunk");
7528 if (image->units == PixelsPerInchResolution)
7530 ping_pHYs_unit_type=PNG_RESOLUTION_METER;
7531 ping_pHYs_x_resolution=(png_uint_32) (100.0*image->x_resolution/2.54);
7532 ping_pHYs_y_resolution=(png_uint_32) (100.0*image->y_resolution/2.54);
7535 else if (image->units == PixelsPerCentimeterResolution)
7537 ping_pHYs_unit_type=PNG_RESOLUTION_METER;
7538 ping_pHYs_x_resolution=(png_uint_32) (100.0*image->x_resolution);
7539 ping_pHYs_y_resolution=(png_uint_32) (100.0*image->y_resolution);
7544 ping_pHYs_unit_type=PNG_RESOLUTION_UNKNOWN;
7545 ping_pHYs_x_resolution=(png_uint_32) image->x_resolution;
7546 ping_pHYs_y_resolution=(png_uint_32) image->y_resolution;
7549 ping_have_pHYs = MagickTrue;
7554 if (ping_exclude_bKGD == MagickFalse)
7556 if ((!mng_info->adjoin || !mng_info->equal_backgrounds))
7562 if (ping_bit_depth == 8)
7565 if (ping_bit_depth == 4)
7568 if (ping_bit_depth == 2)
7571 if (ping_bit_depth == 1)
7574 ping_background.red=(png_uint_16)
7575 (ScaleQuantumToShort(image->background_color.red) & mask);
7577 ping_background.green=(png_uint_16)
7578 (ScaleQuantumToShort(image->background_color.green) & mask);
7580 ping_background.blue=(png_uint_16)
7581 (ScaleQuantumToShort(image->background_color.blue) & mask);
7584 if (logging != MagickFalse)
7586 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7587 " Setting up bKGD chunk (1)");
7589 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7590 " ping_bit_depth=%d",ping_bit_depth);
7593 ping_have_bKGD = MagickTrue;
7597 Select the color type.
7602 if (mng_info->write_png8)
7605 /* TO DO: make this a function cause it's used twice, except
7606 for reducing the sample depth from 8. */
7608 number_colors=image_colors;
7610 ping_have_tRNS=MagickFalse;
7615 ping_color_type=(png_byte) PNG_COLOR_TYPE_PALETTE;
7617 if (logging != MagickFalse)
7618 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7619 " Setting up PLTE chunk with %d colors (%d)",
7620 number_colors, image_colors);
7622 for (i=0; i < (ssize_t) number_colors; i++)
7624 palette[i].red=ScaleQuantumToChar(image->colormap[i].red);
7625 palette[i].green=ScaleQuantumToChar(image->colormap[i].green);
7626 palette[i].blue=ScaleQuantumToChar(image->colormap[i].blue);
7627 if (logging != MagickFalse)
7628 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7629 #if MAGICKCORE_QUANTUM_DEPTH == 8
7630 " %3ld (%3d,%3d,%3d)",
7632 " %5ld (%5d,%5d,%5d)",
7634 (long) i,palette[i].red,palette[i].green,palette[i].blue);
7638 ping_have_PLTE=MagickTrue;
7639 image_depth=ping_bit_depth;
7642 if (matte != MagickFalse)
7645 Identify which colormap entry is transparent.
7647 assert(number_colors <= 256);
7648 assert(image->colormap != NULL);
7650 for (i=0; i < (ssize_t) number_transparent; i++)
7651 ping_trans_alpha[i]=0;
7653 /* PNG8 can't have semitransparent colors so we threshold them
7656 for (; i < (ssize_t) number_semitransparent; i++)
7657 ping_trans_alpha[i]=image->colormap[i].opacity >
7658 OpaqueOpacity/2 ? 0 : 255;
7660 ping_num_trans=(unsigned short) (number_transparent +
7661 number_semitransparent);
7663 if (ping_num_trans == 0)
7664 ping_have_tRNS=MagickFalse;
7667 ping_have_tRNS=MagickTrue;
7670 if (ping_exclude_bKGD == MagickFalse)
7673 * Identify which colormap entry is the background color.
7675 for (i=0; i < (ssize_t) MagickMax(1L*number_colors-1L,1L); i++)
7676 if (IsPNGColorEqual(ping_background,image->colormap[i]))
7679 ping_background.index=(png_byte) i;
7681 } /* end of write_png8 */
7683 else if (mng_info->write_png24)
7685 image_matte=MagickFalse;
7686 ping_color_type=(png_byte) PNG_COLOR_TYPE_RGB;
7689 else if (mng_info->write_png32)
7691 image_matte=MagickTrue;
7692 ping_color_type=(png_byte) PNG_COLOR_TYPE_RGB_ALPHA;
7695 else /* mng_info->write_pngNN not specified */
7697 image_depth=ping_bit_depth;
7699 if (mng_info->write_png_colortype != 0)
7701 ping_color_type=(png_byte) mng_info->write_png_colortype-1;
7703 if (ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA ||
7704 ping_color_type == PNG_COLOR_TYPE_RGB_ALPHA)
7705 image_matte=MagickTrue;
7708 image_matte=MagickFalse;
7711 else /* write_ping_colortype not specified */
7713 if (logging != MagickFalse)
7714 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7715 " Selecting PNG colortype:");
7717 ping_color_type=(png_byte) ((matte != MagickFalse)?
7718 PNG_COLOR_TYPE_RGB_ALPHA:PNG_COLOR_TYPE_RGB);
7720 if (image_info->type == TrueColorType)
7722 ping_color_type=(png_byte) PNG_COLOR_TYPE_RGB;
7723 image_matte=MagickFalse;
7726 if (image_info->type == TrueColorMatteType)
7728 ping_color_type=(png_byte) PNG_COLOR_TYPE_RGB_ALPHA;
7729 image_matte=MagickTrue;
7732 if (image_info->type == PaletteType ||
7733 image_info->type == PaletteMatteType)
7734 ping_color_type=(png_byte) PNG_COLOR_TYPE_PALETTE;
7736 if (image_info->type == UndefinedType ||
7737 image_info->type == OptimizeType)
7739 if (ping_have_color == MagickFalse)
7741 if (image_matte == MagickFalse)
7743 ping_color_type=(png_byte) PNG_COLOR_TYPE_GRAY;
7744 image_matte=MagickFalse;
7749 ping_color_type=(png_byte) PNG_COLOR_TYPE_GRAY_ALPHA;
7750 image_matte=MagickTrue;
7755 if (image_matte == MagickFalse)
7757 ping_color_type=(png_byte) PNG_COLOR_TYPE_RGB;
7758 image_matte=MagickFalse;
7763 ping_color_type=(png_byte) PNG_COLOR_TYPE_RGBA;
7764 image_matte=MagickTrue;
7771 if (logging != MagickFalse)
7772 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7773 " Selected PNG colortype=%d",ping_color_type);
7775 if (ping_bit_depth < 8)
7777 if (ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA ||
7778 ping_color_type == PNG_COLOR_TYPE_RGB ||
7779 ping_color_type == PNG_COLOR_TYPE_RGB_ALPHA)
7783 old_bit_depth=ping_bit_depth;
7785 if (ping_color_type == PNG_COLOR_TYPE_GRAY)
7787 if (image->matte == MagickFalse && image->colors < 256)
7789 if (ImageIsMonochrome(image))
7796 if (ping_color_type == PNG_COLOR_TYPE_PALETTE)
7801 if (image->colors == 0)
7804 (void) ThrowMagickException(&image->exception,
7805 GetMagickModule(),CoderError,
7806 "image has 0 colors", "`%s'","");
7809 while ((int) (one << ping_bit_depth) < (ssize_t) image_colors)
7810 ping_bit_depth <<= 1;
7813 if (logging != MagickFalse)
7815 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7816 " Number of colors: %.20g",(double) image_colors);
7818 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7819 " Tentative PNG bit depth: %d",ping_bit_depth);
7822 if (ping_bit_depth < (int) mng_info->write_png_depth)
7823 ping_bit_depth = mng_info->write_png_depth;
7826 image_depth=ping_bit_depth;
7828 if (logging != MagickFalse)
7830 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7831 " Tentative PNG color type: %.20g",(double) ping_color_type);
7833 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7834 " image_info->type: %.20g",(double) image_info->type);
7836 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7837 " image_depth: %.20g",(double) image_depth);
7839 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7841 " image->depth: %.20g",(double) image->depth);
7843 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7844 " ping_bit_depth: %.20g",(double) ping_bit_depth);
7847 if (matte != MagickFalse)
7849 if (mng_info->IsPalette)
7852 ping_color_type=PNG_COLOR_TYPE_GRAY_ALPHA;
7854 if (ping_have_color != MagickFalse)
7855 ping_color_type=PNG_COLOR_TYPE_RGBA;
7858 * Determine if there is any transparent color.
7860 if (number_transparent + number_semitransparent == 0)
7863 No transparent pixels are present. Change 4 or 6 to 0 or 2.
7866 image_matte=MagickFalse;
7867 ping_color_type&=0x03;
7877 if (ping_bit_depth == 8)
7880 if (ping_bit_depth == 4)
7883 if (ping_bit_depth == 2)
7886 if (ping_bit_depth == 1)
7889 ping_trans_color.red=(png_uint_16)
7890 (ScaleQuantumToShort(image->colormap[0].red) & mask);
7892 ping_trans_color.green=(png_uint_16)
7893 (ScaleQuantumToShort(image->colormap[0].green) & mask);
7895 ping_trans_color.blue=(png_uint_16)
7896 (ScaleQuantumToShort(image->colormap[0].blue) & mask);
7898 ping_trans_color.gray=(png_uint_16)
7899 (ScaleQuantumToShort(PixelIntensityToQuantum(
7900 image->colormap)) & mask);
7902 ping_trans_color.index=(png_byte) 0;
7904 ping_have_tRNS=MagickTrue;
7907 if (ping_have_tRNS != MagickFalse)
7910 Determine if there is one and only one transparent color
7911 and if so if it is fully transparent.
7913 if (logging != MagickFalse)
7914 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7915 " Is there a single fully transparent color?");
7917 if (number_transparent > 1 || number_semitransparent > 0)
7919 ping_have_tRNS = MagickFalse;
7920 if (logging != MagickFalse)
7921 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7926 if (logging != MagickFalse)
7927 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7928 " ... Yes: (%d,%d,%d), (gray: %d)",
7929 (int) ping_trans_color.red,
7930 (int) ping_trans_color.green,
7931 (int) ping_trans_color.blue,
7932 (int) ping_trans_color.gray);
7936 if (ping_have_tRNS != MagickFalse)
7938 ping_color_type &= 0x03; /* changes 4 or 6 to 0 or 2 */
7940 if (image_depth == 8)
7942 ping_trans_color.red&=0xff;
7943 ping_trans_color.green&=0xff;
7944 ping_trans_color.blue&=0xff;
7945 ping_trans_color.gray&=0xff;
7951 if (image_depth == 8)
7953 ping_trans_color.red&=0xff;
7954 ping_trans_color.green&=0xff;
7955 ping_trans_color.blue&=0xff;
7956 ping_trans_color.gray&=0xff;
7963 if (ping_have_tRNS != MagickFalse)
7964 image_matte=MagickFalse;
7966 if ((mng_info->IsPalette) &&
7967 mng_info->write_png_colortype-1 != PNG_COLOR_TYPE_PALETTE &&
7968 ImageIsGray(image) && (image_matte == MagickFalse || image_depth >= 8))
7972 if (image_matte != MagickFalse)
7973 ping_color_type=PNG_COLOR_TYPE_GRAY_ALPHA;
7977 ping_color_type=PNG_COLOR_TYPE_GRAY;
7979 if (save_image_depth == 16 && image_depth == 8)
7981 if (logging != MagickFalse)
7983 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7984 " Scaling ping_trans_color (0)");
7986 ping_trans_color.gray*=0x0101;
7990 if (image_depth > MAGICKCORE_QUANTUM_DEPTH)
7991 image_depth=MAGICKCORE_QUANTUM_DEPTH;
7993 if (image_colors == 0 || image_colors-1 > MaxColormapSize)
7994 image_colors=(int) (one << image_depth);
7996 if (image_depth > 8)
8002 if ((int) ping_color_type == PNG_COLOR_TYPE_PALETTE)
8004 if(!mng_info->write_png_depth)
8008 while ((int) (one << ping_bit_depth)
8009 < (ssize_t) image_colors)
8010 ping_bit_depth <<= 1;
8014 else if (ping_color_type ==
8015 PNG_COLOR_TYPE_GRAY && image_colors < 17 &&
8016 mng_info->IsPalette)
8019 /* Check if grayscale is reducible */
8021 depth_4_ok=MagickTrue,
8022 depth_2_ok=MagickTrue,
8023 depth_1_ok=MagickTrue;
8025 for (i=0; i < (ssize_t) image_colors; i++)
8030 intensity=ScaleQuantumToChar(image->colormap[i].red);
8032 if ((intensity & 0x0f) != ((intensity & 0xf0) >> 4))
8033 depth_4_ok=depth_2_ok=depth_1_ok=MagickFalse;
8035 else if ((intensity & 0x03) != ((intensity & 0x0c) >> 2))
8036 depth_2_ok=depth_1_ok=MagickFalse;
8038 else if ((intensity & 0x01) != ((intensity & 0x02) >> 1))
8039 depth_1_ok=MagickFalse;
8042 if (depth_1_ok && mng_info->write_png_depth <= 1)
8045 else if (depth_2_ok && mng_info->write_png_depth <= 2)
8048 else if (depth_4_ok && mng_info->write_png_depth <= 4)
8053 image_depth=ping_bit_depth;
8058 if (mng_info->IsPalette)
8060 number_colors=image_colors;
8062 if (image_depth <= 8)
8067 ping_color_type=(png_byte) PNG_COLOR_TYPE_PALETTE;
8069 if (mng_info->have_write_global_plte && matte == MagickFalse)
8071 png_set_PLTE(ping,ping_info,NULL,0);
8073 if (logging != MagickFalse)
8074 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8075 " Setting up empty PLTE chunk");
8080 for (i=0; i < (ssize_t) number_colors; i++)
8082 palette[i].red=ScaleQuantumToChar(image->colormap[i].red);
8083 palette[i].green=ScaleQuantumToChar(image->colormap[i].green);
8084 palette[i].blue=ScaleQuantumToChar(image->colormap[i].blue);
8087 if (logging != MagickFalse)
8088 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8089 " Setting up PLTE chunk with %d colors",
8092 ping_have_PLTE=MagickTrue;
8095 /* color_type is PNG_COLOR_TYPE_PALETTE */
8096 if (mng_info->write_png_depth == 0)
8104 while ((one << ping_bit_depth) < number_colors)
8105 ping_bit_depth <<= 1;
8110 if (matte != MagickFalse)
8113 * Set up trans_colors array.
8115 assert(number_colors <= 256);
8117 ping_num_trans=(unsigned short) (number_transparent +
8118 number_semitransparent);
8120 if (ping_num_trans == 0)
8121 ping_have_tRNS=MagickFalse;
8125 if (logging != MagickFalse)
8127 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8128 " Scaling ping_trans_color (1)");
8130 ping_have_tRNS=MagickTrue;
8132 for (i=0; i < ping_num_trans; i++)
8134 ping_trans_alpha[i]= (png_byte) (255-
8135 ScaleQuantumToChar(image->colormap[i].opacity));
8145 if (image_depth < 8)
8148 if ((save_image_depth == 16) && (image_depth == 8))
8150 if (logging != MagickFalse)
8152 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8153 " Scaling ping_trans_color from (%d,%d,%d)",
8154 (int) ping_trans_color.red,
8155 (int) ping_trans_color.green,
8156 (int) ping_trans_color.blue);
8159 ping_trans_color.red*=0x0101;
8160 ping_trans_color.green*=0x0101;
8161 ping_trans_color.blue*=0x0101;
8162 ping_trans_color.gray*=0x0101;
8164 if (logging != MagickFalse)
8166 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8168 (int) ping_trans_color.red,
8169 (int) ping_trans_color.green,
8170 (int) ping_trans_color.blue);
8175 if (ping_bit_depth < (ssize_t) mng_info->write_png_depth)
8176 ping_bit_depth = (ssize_t) mng_info->write_png_depth;
8179 Adjust background and transparency samples in sub-8-bit grayscale files.
8181 if (ping_bit_depth < 8 && ping_color_type ==
8182 PNG_COLOR_TYPE_GRAY)
8190 maxval=(png_uint_16) ((one << ping_bit_depth)-1);
8192 if (ping_exclude_bKGD == MagickFalse)
8195 ping_background.gray=(png_uint_16)
8196 (QuantumScale*(maxval*(PixelIntensity(&image->background_color))));
8198 if (logging != MagickFalse)
8199 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8200 " Setting up bKGD chunk (2)");
8202 ping_have_bKGD = MagickTrue;
8205 ping_trans_color.gray=(png_uint_16) (QuantumScale*(maxval*
8206 ping_trans_color.gray));
8209 if (ping_exclude_bKGD == MagickFalse)
8211 if ((int) ping_color_type == PNG_COLOR_TYPE_PALETTE)
8214 Identify which colormap entry is the background color.
8217 number_colors=image_colors;
8219 for (i=0; i < (ssize_t) MagickMax(1L*number_colors,1L); i++)
8220 if (IsPNGColorEqual(image->background_color,image->colormap[i]))
8223 ping_background.index=(png_byte) i;
8225 if (logging != MagickFalse)
8227 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8228 " Setting up bKGD chunk with index=%d",(int) i);
8231 if (i < (ssize_t) number_colors)
8233 ping_have_bKGD = MagickTrue;
8235 if (logging != MagickFalse)
8237 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8238 " background =(%d,%d,%d)",
8239 (int) ping_background.red,
8240 (int) ping_background.green,
8241 (int) ping_background.blue);
8245 else /* Can't happen */
8247 if (logging != MagickFalse)
8248 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8249 " No room in PLTE to add bKGD color");
8250 ping_have_bKGD = MagickFalse;
8255 if (logging != MagickFalse)
8256 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8257 " PNG color type: %d",ping_color_type);
8259 Initialize compression level and filtering.
8261 if (logging != MagickFalse)
8263 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8264 " Setting up deflate compression");
8266 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8267 " Compression buffer size: 32768");
8270 png_set_compression_buffer_size(ping,32768L);
8272 if (logging != MagickFalse)
8273 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8274 " Compression mem level: 9");
8276 png_set_compression_mem_level(ping, 9);
8278 quality=image->quality == UndefinedCompressionQuality ? 75UL :
8286 level=(int) MagickMin((ssize_t) quality/10,9);
8288 if (logging != MagickFalse)
8289 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8290 " Compression level: %d",level);
8292 png_set_compression_level(ping,level);
8297 if (logging != MagickFalse)
8298 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8299 " Compression strategy: Z_HUFFMAN_ONLY");
8301 png_set_compression_strategy(ping, Z_HUFFMAN_ONLY);
8304 if (logging != MagickFalse)
8305 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8306 " Setting up filtering");
8308 #if defined(PNG_MNG_FEATURES_SUPPORTED) && defined(PNG_INTRAPIXEL_DIFFERENCING)
8309 /* This became available in libpng-1.0.9. Output must be a MNG. */
8310 if (mng_info->write_mng && ((quality % 10) == 7))
8312 if (logging != MagickFalse)
8313 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8314 " Filter_type: PNG_INTRAPIXEL_DIFFERENCING");
8316 ping_filter_method=PNG_INTRAPIXEL_DIFFERENCING;
8320 if (logging != MagickFalse)
8321 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8329 if ((quality % 10) > 5)
8330 base_filter=PNG_ALL_FILTERS;
8333 if ((quality % 10) != 5)
8334 base_filter=(int) quality % 10;
8337 if (((int) ping_color_type == PNG_COLOR_TYPE_GRAY) ||
8338 ((int) ping_color_type == PNG_COLOR_TYPE_PALETTE) ||
8340 base_filter=PNG_NO_FILTERS;
8343 base_filter=PNG_ALL_FILTERS;
8345 if (logging != MagickFalse)
8347 if (base_filter == PNG_ALL_FILTERS)
8348 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8349 " Base filter method: ADAPTIVE");
8351 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8352 " Base filter method: NONE");
8355 png_set_filter(ping,PNG_FILTER_TYPE_BASE,base_filter);
8358 if (ping_exclude_iCCP == MagickFalse || ping_exclude_zCCP == MagickFalse)
8360 ResetImageProfileIterator(image);
8361 for (name=GetNextImageProfile(image); name != (const char *) NULL; )
8363 profile=GetImageProfile(image,name);
8365 if (profile != (StringInfo *) NULL)
8367 #ifdef PNG_WRITE_iCCP_SUPPORTED
8368 if ((LocaleCompare(name,"ICC") == 0) ||
8369 (LocaleCompare(name,"ICM") == 0))
8372 if (ping_exclude_iCCP == MagickFalse)
8374 png_set_iCCP(ping,ping_info,(const png_charp) name,0,
8375 #if (PNG_LIBPNG_VER < 10500)
8376 (png_charp) GetStringInfoDatum(profile),
8378 (png_const_bytep) GetStringInfoDatum(profile),
8380 (png_uint_32) GetStringInfoLength(profile));
8386 if (ping_exclude_zCCP == MagickFalse)
8388 Magick_png_write_raw_profile(image_info,ping,ping_info,
8389 (unsigned char *) name,(unsigned char *) name,
8390 GetStringInfoDatum(profile),
8391 (png_uint_32) GetStringInfoLength(profile));
8395 if (logging != MagickFalse)
8396 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8397 " Setting up text chunk with %s profile",name);
8399 name=GetNextImageProfile(image);
8403 #if defined(PNG_WRITE_sRGB_SUPPORTED)
8404 if ((mng_info->have_write_global_srgb == 0) &&
8405 ((image->rendering_intent != UndefinedIntent) ||
8406 (image->colorspace == sRGBColorspace)))
8408 if (ping_exclude_sRGB == MagickFalse)
8411 Note image rendering intent.
8413 if (logging != MagickFalse)
8414 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8415 " Setting up sRGB chunk");
8417 (void) png_set_sRGB(ping,ping_info,(
8418 Magick_RenderingIntent_to_PNG_RenderingIntent(
8419 image->rendering_intent)));
8421 if (ping_exclude_gAMA == MagickFalse)
8422 png_set_gAMA(ping,ping_info,0.45455);
8426 if ((!mng_info->write_mng) || (!png_get_valid(ping,ping_info,PNG_INFO_sRGB)))
8429 if (ping_exclude_gAMA == MagickFalse &&
8430 (ping_exclude_sRGB == MagickFalse ||
8431 (image->gamma < .45 || image->gamma > .46)))
8433 if ((mng_info->have_write_global_gama == 0) && (image->gamma != 0.0))
8437 To do: check for cHRM+gAMA == sRGB, and write sRGB instead.
8439 if (logging != MagickFalse)
8440 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8441 " Setting up gAMA chunk");
8443 png_set_gAMA(ping,ping_info,image->gamma);
8447 if (ping_exclude_cHRM == MagickFalse)
8449 if ((mng_info->have_write_global_chrm == 0) &&
8450 (image->chromaticity.red_primary.x != 0.0))
8453 Note image chromaticity.
8454 To do: check for cHRM+gAMA == sRGB, and write sRGB instead.
8462 wp=image->chromaticity.white_point;
8463 rp=image->chromaticity.red_primary;
8464 gp=image->chromaticity.green_primary;
8465 bp=image->chromaticity.blue_primary;
8467 if (logging != MagickFalse)
8468 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8469 " Setting up cHRM chunk");
8471 png_set_cHRM(ping,ping_info,wp.x,wp.y,rp.x,rp.y,gp.x,gp.y,
8477 ping_interlace_method=image_info->interlace != NoInterlace;
8479 if (mng_info->write_mng)
8480 png_set_sig_bytes(ping,8);
8482 /* Bail out if cannot meet defined PNG:bit-depth or PNG:color-type */
8484 if (mng_info->write_png_colortype != 0)
8486 if (mng_info->write_png_colortype-1 == PNG_COLOR_TYPE_GRAY)
8487 if (ImageIsGray(image) == MagickFalse)
8489 ping_color_type = PNG_COLOR_TYPE_RGB;
8491 if (ping_bit_depth < 8)
8495 if (mng_info->write_png_colortype-1 == PNG_COLOR_TYPE_GRAY_ALPHA)
8496 if (ImageIsGray(image) == MagickFalse)
8497 ping_color_type = PNG_COLOR_TYPE_RGB_ALPHA;
8500 if (ping_need_colortype_warning != MagickFalse ||
8501 ((mng_info->write_png_depth &&
8502 (int) mng_info->write_png_depth != ping_bit_depth) ||
8503 (mng_info->write_png_colortype &&
8504 ((int) mng_info->write_png_colortype-1 != ping_color_type &&
8505 mng_info->write_png_colortype != 7 &&
8506 !(mng_info->write_png_colortype == 5 && ping_color_type == 0)))))
8508 if (logging != MagickFalse)
8510 if (ping_need_colortype_warning != MagickFalse)
8512 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8513 " Image has transparency but tRNS chunk was excluded");
8516 if (mng_info->write_png_depth)
8518 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8519 " Defined PNG:bit-depth=%u, Computed depth=%u",
8520 mng_info->write_png_depth,
8524 if (mng_info->write_png_colortype)
8526 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8527 " Defined PNG:color-type=%u, Computed color type=%u",
8528 mng_info->write_png_colortype-1,
8534 "Cannot write image with defined PNG:bit-depth or PNG:color-type.");
8537 if (image_matte != MagickFalse && image->matte == MagickFalse)
8539 /* Add an opaque matte channel */
8540 image->matte = MagickTrue;
8541 (void) SetImageOpacity(image,0);
8543 if (logging != MagickFalse)
8544 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8545 " Added an opaque matte channel");
8548 if (number_transparent != 0 || number_semitransparent != 0)
8550 if (ping_color_type < 4)
8552 ping_have_tRNS=MagickTrue;
8553 if (logging != MagickFalse)
8554 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8555 " Setting ping_have_tRNS=MagickTrue.");
8559 if (logging != MagickFalse)
8560 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8561 " Writing PNG header chunks");
8563 png_set_IHDR(ping,ping_info,ping_width,ping_height,
8564 ping_bit_depth,ping_color_type,
8565 ping_interlace_method,ping_compression_method,
8566 ping_filter_method);
8568 if (ping_color_type == 3 && ping_have_PLTE != MagickFalse)
8570 png_set_PLTE(ping,ping_info,palette,number_colors);
8572 if (logging != MagickFalse)
8574 for (i=0; i< (ssize_t) number_colors; i++)
8576 if (i < ping_num_trans)
8577 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8578 " PLTE[%d] = (%d,%d,%d), tRNS[%d] = (%d)",
8580 (int) palette[i].red,
8581 (int) palette[i].green,
8582 (int) palette[i].blue,
8584 (int) ping_trans_alpha[i]);
8586 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8587 " PLTE[%d] = (%d,%d,%d)",
8589 (int) palette[i].red,
8590 (int) palette[i].green,
8591 (int) palette[i].blue);
8596 if (ping_exclude_bKGD == MagickFalse)
8598 if (ping_have_bKGD != MagickFalse)
8599 png_set_bKGD(ping,ping_info,&ping_background);
8602 if (ping_exclude_pHYs == MagickFalse)
8604 if (ping_have_pHYs != MagickFalse)
8606 png_set_pHYs(ping,ping_info,
8607 ping_pHYs_x_resolution,
8608 ping_pHYs_y_resolution,
8609 ping_pHYs_unit_type);
8613 #if defined(PNG_oFFs_SUPPORTED)
8614 if (ping_exclude_oFFs == MagickFalse)
8616 if (image->page.x || image->page.y)
8618 png_set_oFFs(ping,ping_info,(png_int_32) image->page.x,
8619 (png_int_32) image->page.y, 0);
8621 if (logging != MagickFalse)
8622 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8623 " Setting up oFFs chunk with x=%d, y=%d, units=0",
8624 (int) image->page.x, (int) image->page.y);
8629 png_write_info_before_PLTE(ping, ping_info);
8631 if (ping_have_tRNS != MagickFalse && ping_color_type < 4)
8633 if (logging != MagickFalse)
8635 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8636 " Calling png_set_tRNS with num_trans=%d",ping_num_trans);
8639 if (ping_color_type == 3)
8640 (void) png_set_tRNS(ping, ping_info,
8647 (void) png_set_tRNS(ping, ping_info,
8652 if (logging != MagickFalse)
8654 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8655 " tRNS color =(%d,%d,%d)",
8656 (int) ping_trans_color.red,
8657 (int) ping_trans_color.green,
8658 (int) ping_trans_color.blue);
8663 /* write any png-chunk-b profiles */
8664 (void) Magick_png_write_chunk_from_profile(image,"PNG-chunk-b",logging);
8665 png_write_info(ping,ping_info);
8667 /* write any PNG-chunk-m profiles */
8668 (void) Magick_png_write_chunk_from_profile(image,"PNG-chunk-m",logging);
8670 if (ping_exclude_vpAg == MagickFalse)
8672 if ((image->page.width != 0 && image->page.width != image->columns) ||
8673 (image->page.height != 0 && image->page.height != image->rows))
8678 (void) WriteBlobMSBULong(image,9L); /* data length=8 */
8679 PNGType(chunk,mng_vpAg);
8680 LogPNGChunk(logging,mng_vpAg,9L);
8681 PNGLong(chunk+4,(png_uint_32) image->page.width);
8682 PNGLong(chunk+8,(png_uint_32) image->page.height);
8683 chunk[12]=0; /* unit = pixels */
8684 (void) WriteBlob(image,13,chunk);
8685 (void) WriteBlobMSBULong(image,crc32(0,chunk,13));
8689 #if (PNG_LIBPNG_VER == 10206)
8690 /* avoid libpng-1.2.6 bug by setting PNG_HAVE_IDAT flag */
8691 #define PNG_HAVE_IDAT 0x04
8692 ping->mode |= PNG_HAVE_IDAT;
8693 #undef PNG_HAVE_IDAT
8696 png_set_packing(ping);
8700 rowbytes=image->columns;
8701 if (image_depth > 8)
8703 switch (ping_color_type)
8705 case PNG_COLOR_TYPE_RGB:
8709 case PNG_COLOR_TYPE_GRAY_ALPHA:
8713 case PNG_COLOR_TYPE_RGBA:
8721 if (logging != MagickFalse)
8723 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8724 " Writing PNG image data");
8726 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8727 " Allocating %.20g bytes of memory for pixels",(double) rowbytes);
8729 ping_pixels=(unsigned char *) AcquireQuantumMemory(rowbytes,
8730 sizeof(*ping_pixels));
8732 if (ping_pixels == (unsigned char *) NULL)
8733 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
8736 Initialize image scanlines.
8738 if (setjmp(png_jmpbuf(ping)))
8744 if (image_info->verbose)
8745 (void) printf("PNG write has failed.\n");
8747 png_destroy_write_struct(&ping,&ping_info);
8748 if (quantum_info != (QuantumInfo *) NULL)
8749 quantum_info=DestroyQuantumInfo(quantum_info);
8750 if (ping_pixels != (unsigned char *) NULL)
8751 ping_pixels=(unsigned char *) RelinquishMagickMemory(ping_pixels);
8752 #if defined(PNG_SETJMP_NOT_THREAD_SAFE)
8753 UnlockSemaphoreInfo(ping_semaphore);
8755 if (mng_info->need_blob != MagickFalse)
8756 (void) CloseBlob(image);
8757 image_info=DestroyImageInfo(image_info);
8758 image=DestroyImage(image);
8759 return(MagickFalse);
8761 quantum_info=AcquireQuantumInfo(image_info,image);
8762 if (quantum_info == (QuantumInfo *) NULL)
8763 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
8764 quantum_info->format=UndefinedQuantumFormat;
8765 quantum_info->depth=image_depth;
8766 num_passes=png_set_interlace_handling(ping);
8768 if ((!mng_info->write_png8 && !mng_info->write_png24 &&
8769 !mng_info->write_png32) &&
8770 (mng_info->IsPalette ||
8771 (image_info->type == BilevelType)) &&
8772 image_matte == MagickFalse && ImageIsMonochrome(image))
8774 /* Palette, Bilevel, or Opaque Monochrome */
8775 register const PixelPacket
8778 quantum_info->depth=8;
8779 for (pass=0; pass < num_passes; pass++)
8782 Convert PseudoClass image to a PNG monochrome image.
8784 for (y=0; y < (ssize_t) image->rows; y++)
8787 if (logging != MagickFalse)
8788 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8789 " Writing row of pixels (0)");
8791 p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception);
8793 if (p == (const PixelPacket *) NULL)
8796 if (mng_info->IsPalette)
8798 (void) ExportQuantumPixels(image,(const CacheView *) NULL,
8799 quantum_info,GrayQuantum,ping_pixels,&image->exception);
8800 if (mng_info->write_png_colortype-1 == PNG_COLOR_TYPE_PALETTE &&
8801 mng_info->write_png_depth &&
8802 mng_info->write_png_depth != old_bit_depth)
8804 /* Undo pixel scaling */
8805 for (i=0; i < (ssize_t) image->columns; i++)
8806 *(ping_pixels+i)=(unsigned char) (*(ping_pixels+i)
8807 >> (8-old_bit_depth));
8813 (void) ExportQuantumPixels(image,(const CacheView *) NULL,
8814 quantum_info,RedQuantum,ping_pixels,&image->exception);
8817 if (mng_info->write_png_colortype-1 != PNG_COLOR_TYPE_PALETTE)
8818 for (i=0; i < (ssize_t) image->columns; i++)
8819 *(ping_pixels+i)=(unsigned char) ((*(ping_pixels+i) > 127) ?
8822 if (logging != MagickFalse && y == 0)
8823 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8824 " Writing row of pixels (1)");
8826 png_write_row(ping,ping_pixels);
8828 if (image->previous == (Image *) NULL)
8830 status=SetImageProgress(image,LoadImageTag,pass,num_passes);
8831 if (status == MagickFalse)
8837 else /* Not Palette, Bilevel, or Opaque Monochrome */
8839 if ((!mng_info->write_png8 && !mng_info->write_png24 &&
8840 !mng_info->write_png32) &&
8841 (image_matte != MagickFalse ||
8842 (ping_bit_depth >= MAGICKCORE_QUANTUM_DEPTH)) &&
8843 (mng_info->IsPalette) && ImageIsGray(image))
8845 register const PixelPacket
8848 for (pass=0; pass < num_passes; pass++)
8851 for (y=0; y < (ssize_t) image->rows; y++)
8853 p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception);
8855 if (p == (const PixelPacket *) NULL)
8858 if (ping_color_type == PNG_COLOR_TYPE_GRAY)
8860 if (mng_info->IsPalette)
8861 (void) ExportQuantumPixels(image,(const CacheView *) NULL,
8862 quantum_info,GrayQuantum,ping_pixels,&image->exception);
8865 (void) ExportQuantumPixels(image,(const CacheView *) NULL,
8866 quantum_info,RedQuantum,ping_pixels,&image->exception);
8868 if (logging != MagickFalse && y == 0)
8869 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8870 " Writing GRAY PNG pixels (2)");
8873 else /* PNG_COLOR_TYPE_GRAY_ALPHA */
8875 if (logging != MagickFalse && y == 0)
8876 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8877 " Writing GRAY_ALPHA PNG pixels (2)");
8879 (void) ExportQuantumPixels(image,(const CacheView *) NULL,
8880 quantum_info,GrayAlphaQuantum,ping_pixels,&image->exception);
8883 if (logging != MagickFalse && y == 0)
8884 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8885 " Writing row of pixels (2)");
8887 png_write_row(ping,ping_pixels);
8890 if (image->previous == (Image *) NULL)
8892 status=SetImageProgress(image,LoadImageTag,pass,num_passes);
8893 if (status == MagickFalse)
8901 register const PixelPacket
8904 for (pass=0; pass < num_passes; pass++)
8906 if ((image_depth > 8) || (mng_info->write_png24 ||
8907 mng_info->write_png32 ||
8908 (!mng_info->write_png8 && !mng_info->IsPalette)))
8910 for (y=0; y < (ssize_t) image->rows; y++)
8912 p=GetVirtualPixels(image,0,y,image->columns,1,
8915 if (p == (const PixelPacket *) NULL)
8918 if (ping_color_type == PNG_COLOR_TYPE_GRAY)
8920 if (image->storage_class == DirectClass)
8921 (void) ExportQuantumPixels(image,(const CacheView *) NULL,
8922 quantum_info,RedQuantum,ping_pixels,&image->exception);
8925 (void) ExportQuantumPixels(image,(const CacheView *) NULL,
8926 quantum_info,GrayQuantum,ping_pixels,&image->exception);
8929 else if (ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
8931 (void) ExportQuantumPixels(image,(const CacheView *) NULL,
8932 quantum_info,GrayAlphaQuantum,ping_pixels,
8935 if (logging != MagickFalse && y == 0)
8936 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8937 " Writing GRAY_ALPHA PNG pixels (3)");
8940 else if (image_matte != MagickFalse)
8941 (void) ExportQuantumPixels(image,(const CacheView *) NULL,
8942 quantum_info,RGBAQuantum,ping_pixels,&image->exception);
8945 (void) ExportQuantumPixels(image,(const CacheView *) NULL,
8946 quantum_info,RGBQuantum,ping_pixels,&image->exception);
8948 if (logging != MagickFalse && y == 0)
8949 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8950 " Writing row of pixels (3)");
8952 png_write_row(ping,ping_pixels);
8957 /* not ((image_depth > 8) || (mng_info->write_png24 ||
8958 mng_info->write_png32 ||
8959 (!mng_info->write_png8 && !mng_info->IsPalette))) */
8961 if ((ping_color_type != PNG_COLOR_TYPE_GRAY) &&
8962 (ping_color_type != PNG_COLOR_TYPE_GRAY_ALPHA))
8964 if (logging != MagickFalse)
8965 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8966 " pass %d, Image Is not GRAY or GRAY_ALPHA",pass);
8968 quantum_info->depth=8;
8972 for (y=0; y < (ssize_t) image->rows; y++)
8974 if (logging != MagickFalse && y == 0)
8975 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8976 " pass %d, Image Is RGB, 16-bit GRAY, or GRAY_ALPHA",pass);
8978 p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception);
8980 if (p == (const PixelPacket *) NULL)
8983 if (ping_color_type == PNG_COLOR_TYPE_GRAY)
8984 (void) ExportQuantumPixels(image,(const CacheView *) NULL,
8985 quantum_info,GrayQuantum,ping_pixels,&image->exception);
8987 else if (ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
8989 if (logging != MagickFalse && y == 0)
8990 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8991 " Writing GRAY_ALPHA PNG pixels (4)");
8993 (void) ExportQuantumPixels(image,(const CacheView *) NULL,
8994 quantum_info,GrayAlphaQuantum,ping_pixels,
8999 (void) ExportQuantumPixels(image,(const CacheView *) NULL,
9000 quantum_info,IndexQuantum,ping_pixels,&image->exception);
9002 if (logging != MagickFalse && y <= 2)
9004 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9005 " Writing row of pixels (4)");
9007 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9008 " ping_pixels[0]=%d,ping_pixels[1]=%d",
9009 (int)ping_pixels[0],(int)ping_pixels[1]);
9011 png_write_row(ping,ping_pixels);
9015 if (image->previous == (Image *) NULL)
9017 status=SetImageProgress(image,LoadImageTag,pass,num_passes);
9018 if (status == MagickFalse)
9025 if (quantum_info != (QuantumInfo *) NULL)
9026 quantum_info=DestroyQuantumInfo(quantum_info);
9028 if (logging != MagickFalse)
9030 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9031 " Wrote PNG image data");
9033 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9034 " Width: %.20g",(double) ping_width);
9036 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9037 " Height: %.20g",(double) ping_height);
9039 if (mng_info->write_png_depth)
9041 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9042 " Defined PNG:bit-depth: %d",mng_info->write_png_depth);
9045 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9046 " PNG bit-depth written: %d",ping_bit_depth);
9048 if (mng_info->write_png_colortype)
9050 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9051 " Defined PNG:color-type: %d",mng_info->write_png_colortype-1);
9054 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9055 " PNG color-type written: %d",ping_color_type);
9057 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9058 " PNG Interlace method: %d",ping_interlace_method);
9061 Generate text chunks.
9063 if (ping_exclude_tEXt == MagickFalse && ping_exclude_zTXt == MagickFalse)
9065 ResetImagePropertyIterator(image);
9066 property=GetNextImageProperty(image);
9067 while (property != (const char *) NULL)
9072 value=GetImageProperty(image,property);
9073 if (value != (const char *) NULL)
9075 text=(png_textp) png_malloc(ping,(png_uint_32) sizeof(png_text));
9076 text[0].key=(char *) property;
9077 text[0].text=(char *) value;
9078 text[0].text_length=strlen(value);
9080 if (ping_exclude_tEXt != MagickFalse)
9081 text[0].compression=PNG_TEXT_COMPRESSION_zTXt;
9083 else if (ping_exclude_zTXt != MagickFalse)
9084 text[0].compression=PNG_TEXT_COMPRESSION_NONE;
9088 text[0].compression=image_info->compression == NoCompression ||
9089 (image_info->compression == UndefinedCompression &&
9090 text[0].text_length < 128) ? PNG_TEXT_COMPRESSION_NONE :
9091 PNG_TEXT_COMPRESSION_zTXt ;
9094 if (logging != MagickFalse)
9096 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9097 " Setting up text chunk");
9099 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9100 " keyword: %s",text[0].key);
9103 png_set_text(ping,ping_info,text,1);
9104 png_free(ping,text);
9106 property=GetNextImageProperty(image);
9110 /* write any PNG-chunk-e profiles */
9111 (void) Magick_png_write_chunk_from_profile(image,"PNG-chunk-e",logging);
9113 if (logging != MagickFalse)
9114 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9115 " Writing PNG end info");
9117 png_write_end(ping,ping_info);
9119 if (mng_info->need_fram && (int) image->dispose == BackgroundDispose)
9121 if (mng_info->page.x || mng_info->page.y ||
9122 (ping_width != mng_info->page.width) ||
9123 (ping_height != mng_info->page.height))
9129 Write FRAM 4 with clipping boundaries followed by FRAM 1.
9131 (void) WriteBlobMSBULong(image,27L); /* data length=27 */
9132 PNGType(chunk,mng_FRAM);
9133 LogPNGChunk(logging,mng_FRAM,27L);
9135 chunk[5]=0; /* frame name separator (no name) */
9136 chunk[6]=1; /* flag for changing delay, for next frame only */
9137 chunk[7]=0; /* flag for changing frame timeout */
9138 chunk[8]=1; /* flag for changing frame clipping for next frame */
9139 chunk[9]=0; /* flag for changing frame sync_id */
9140 PNGLong(chunk+10,(png_uint_32) (0L)); /* temporary 0 delay */
9141 chunk[14]=0; /* clipping boundaries delta type */
9142 PNGLong(chunk+15,(png_uint_32) (mng_info->page.x)); /* left cb */
9144 (png_uint_32) (mng_info->page.x + ping_width));
9145 PNGLong(chunk+23,(png_uint_32) (mng_info->page.y)); /* top cb */
9147 (png_uint_32) (mng_info->page.y + ping_height));
9148 (void) WriteBlob(image,31,chunk);
9149 (void) WriteBlobMSBULong(image,crc32(0,chunk,31));
9150 mng_info->old_framing_mode=4;
9151 mng_info->framing_mode=1;
9155 mng_info->framing_mode=3;
9157 if (mng_info->write_mng && !mng_info->need_fram &&
9158 ((int) image->dispose == 3))
9159 (void) ThrowMagickException(&image->exception,GetMagickModule(),
9160 CoderError,"Cannot convert GIF with disposal method 3 to MNG-LC",
9161 "`%s'",image->filename);
9167 png_destroy_write_struct(&ping,&ping_info);
9169 ping_pixels=(unsigned char *) RelinquishMagickMemory(ping_pixels);
9171 #if defined(PNG_SETJMP_NOT_THREAD_SAFE)
9172 UnlockSemaphoreInfo(ping_semaphore);
9175 if (mng_info->need_blob != MagickFalse)
9176 (void) CloseBlob(image);
9178 image_info=DestroyImageInfo(image_info);
9179 image=DestroyImage(image);
9181 /* Store bit depth actually written */
9182 s[0]=(char) ping_bit_depth;
9185 (void) SetImageProperty(IMimage,"png:bit-depth-written",s);
9187 if (logging != MagickFalse)
9188 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9189 " exit WriteOnePNGImage()");
9192 /* End write one PNG image */
9196 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
9200 % W r i t e P N G I m a g e %
9204 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
9206 % WritePNGImage() writes a Portable Network Graphics (PNG) or
9207 % Multiple-image Network Graphics (MNG) image file.
9209 % MNG support written by Glenn Randers-Pehrson, glennrp@image...
9211 % The format of the WritePNGImage method is:
9213 % MagickBooleanType WritePNGImage(const ImageInfo *image_info,Image *image)
9215 % A description of each parameter follows:
9217 % o image_info: the image info.
9219 % o image: The image.
9221 % Returns MagickTrue on success, MagickFalse on failure.
9223 % Communicating with the PNG encoder:
9225 % While the datastream written is always in PNG format and normally would
9226 % be given the "png" file extension, this method also writes the following
9227 % pseudo-formats which are subsets of PNG:
9229 % o PNG8: An 8-bit indexed PNG datastream is written. If transparency
9230 % is present, the tRNS chunk must only have values 0 and 255
9231 % (i.e., transparency is binary: fully opaque or fully
9232 % transparent). The pixels contain 8-bit indices even if
9233 % they could be represented with 1, 2, or 4 bits. Note: grayscale
9234 % images will be written as indexed PNG files even though the
9235 % PNG grayscale type might be slightly more efficient.
9237 % o PNG24: An 8-bit per sample RGB PNG datastream is written. The tRNS
9238 % chunk can be present to convey binary transparency by naming
9239 % one of the colors as transparent.
9241 % o PNG32: An 8-bit per sample RGBA PNG is written. Partial
9242 % transparency is permitted, i.e., the alpha sample for
9243 % each pixel can have any value from 0 to 255. The alpha
9244 % channel is present even if the image is fully opaque.
9246 % o -define: For more precise control of the PNG output, you can use the
9247 % Image options "png:bit-depth" and "png:color-type". These
9248 % can be set from the commandline with "-define" and also
9249 % from the application programming interfaces. The options
9250 % are case-independent and are converted to lowercase before
9251 % being passed to this encoder.
9253 % png:color-type can be 0, 2, 3, 4, or 6.
9255 % When png:color-type is 0 (Grayscale), png:bit-depth can
9256 % be 1, 2, 4, 8, or 16.
9258 % When png:color-type is 2 (RGB), png:bit-depth can
9261 % When png:color-type is 3 (Indexed), png:bit-depth can
9262 % be 1, 2, 4, or 8. This refers to the number of bits
9263 % used to store the index. The color samples always have
9264 % bit-depth 8 in indexed PNG files.
9266 % When png:color-type is 4 (Gray-Matte) or 6 (RGB-Matte),
9267 % png:bit-depth can be 8 or 16.
9269 % If the image cannot be written without loss in the requested PNG8, PNG24,
9270 % or PNG32 format or with the requested bit-depth and color-type without loss,
9271 % a PNG file will not be written, and the encoder will return MagickFalse.
9272 % Since image encoders should not be responsible for the "heavy lifting",
9273 % the user should make sure that ImageMagick has already reduced the
9274 % image depth and number of colors and limit transparency to binary
9275 % transparency prior to attempting to write the image in a format that
9276 % is subject to depth, color, or transparency limitations.
9278 % TODO: Enforce the previous paragraph.
9280 % Note that another definition, "png:bit-depth-written" exists, but it
9281 % is not intended for external use. It is only used internally by the
9282 % PNG encoder to inform the JNG encoder of the depth of the alpha channel.
9284 % It is possible to request that the PNG encoder write previously-formatted
9285 % ancillary chunks in the output PNG file, using the "-profile" commandline
9286 % option as shown below or by setting the profile via a programming
9289 % -profile PNG-chunk-x:<file>
9291 % where x is a location flag and <file> is a file containing the chunk
9292 % name in the first 4 bytes, then a colon (":"), followed by the chunk data.
9293 % This encoder will compute the chunk length and CRC, so those must not
9294 % be included in the file.
9296 % "x" can be "b" (before PLTE), "m" (middle, i.e., between PLTE and IDAT),
9297 % or "e" (end, i.e., after IDAT). If you want to write multiple chunks
9298 % of the same type, then add a short unique string after the "x" to prevent
9299 % subsequent profiles from overwriting the preceding ones, e.g.,
9301 % -profile PNG-chunk-b01:file01 -profile PNG-chunk-b02:file02
9303 % As of version 6.6.6 the following optimizations are always done:
9305 % o 32-bit depth is reduced to 16.
9306 % o 16-bit depth is reduced to 8 if all pixels contain samples whose
9307 % high byte and low byte are identical.
9308 % o Palette is sorted to remove unused entries and to put a
9309 % transparent color first, if BUILD_PNG_PALETTE is defined.
9310 % o Opaque matte channel is removed when writing an indexed PNG.
9311 % o Grayscale images are reduced to 1, 2, or 4 bit depth if
9312 % this can be done without loss and a larger bit depth N was not
9313 % requested via the "-define PNG:bit-depth=N" option.
9314 % o If matte channel is present but only one transparent color is
9315 % present, RGB+tRNS is written instead of RGBA
9316 % o Opaque matte channel is removed (or added, if color-type 4 or 6
9317 % was requested when converting an opaque image).
9319 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
9321 static MagickBooleanType WritePNGImage(const ImageInfo *image_info,
9343 assert(image_info != (const ImageInfo *) NULL);
9344 assert(image_info->signature == MagickSignature);
9345 assert(image != (Image *) NULL);
9346 assert(image->signature == MagickSignature);
9347 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
9348 logging=LogMagickEvent(CoderEvent,GetMagickModule(),"enter WritePNGImage()");
9350 Allocate a MngInfo structure.
9352 have_mng_structure=MagickFalse;
9353 mng_info=(MngInfo *) AcquireMagickMemory(sizeof(MngInfo));
9355 if (mng_info == (MngInfo *) NULL)
9356 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
9359 Initialize members of the MngInfo structure.
9361 (void) ResetMagickMemory(mng_info,0,sizeof(MngInfo));
9362 mng_info->image=image;
9363 mng_info->equal_backgrounds=MagickTrue;
9364 have_mng_structure=MagickTrue;
9366 /* See if user has requested a specific PNG subformat */
9368 mng_info->write_png8=LocaleCompare(image_info->magick,"PNG8") == 0;
9369 mng_info->write_png24=LocaleCompare(image_info->magick,"PNG24") == 0;
9370 mng_info->write_png32=LocaleCompare(image_info->magick,"PNG32") == 0;
9372 if (mng_info->write_png8)
9374 mng_info->write_png_colortype = /* 3 */ 4;
9375 mng_info->write_png_depth = 8;
9379 if (mng_info->write_png24)
9381 mng_info->write_png_colortype = /* 2 */ 3;
9382 mng_info->write_png_depth = 8;
9385 if (image->matte == MagickTrue)
9386 (void) SetImageType(image,TrueColorMatteType);
9389 (void) SetImageType(image,TrueColorType);
9391 (void) SyncImage(image);
9394 if (mng_info->write_png32)
9396 mng_info->write_png_colortype = /* 6 */ 7;
9397 mng_info->write_png_depth = 8;
9400 if (image->matte == MagickTrue)
9401 (void) SetImageType(image,TrueColorMatteType);
9404 (void) SetImageType(image,TrueColorType);
9406 (void) SyncImage(image);
9409 value=GetImageOption(image_info,"png:bit-depth");
9411 if (value != (char *) NULL)
9413 if (LocaleCompare(value,"1") == 0)
9414 mng_info->write_png_depth = 1;
9416 else if (LocaleCompare(value,"2") == 0)
9417 mng_info->write_png_depth = 2;
9419 else if (LocaleCompare(value,"4") == 0)
9420 mng_info->write_png_depth = 4;
9422 else if (LocaleCompare(value,"8") == 0)
9423 mng_info->write_png_depth = 8;
9425 else if (LocaleCompare(value,"16") == 0)
9426 mng_info->write_png_depth = 16;
9429 (void) ThrowMagickException(&image->exception,
9430 GetMagickModule(),CoderWarning,
9431 "ignoring invalid defined png:bit-depth",
9434 if (logging != MagickFalse)
9435 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9436 " png:bit-depth=%d was defined.\n",mng_info->write_png_depth);
9439 value=GetImageOption(image_info,"png:color-type");
9441 if (value != (char *) NULL)
9443 /* We must store colortype+1 because 0 is a valid colortype */
9444 if (LocaleCompare(value,"0") == 0)
9445 mng_info->write_png_colortype = 1;
9447 else if (LocaleCompare(value,"2") == 0)
9448 mng_info->write_png_colortype = 3;
9450 else if (LocaleCompare(value,"3") == 0)
9451 mng_info->write_png_colortype = 4;
9453 else if (LocaleCompare(value,"4") == 0)
9454 mng_info->write_png_colortype = 5;
9456 else if (LocaleCompare(value,"6") == 0)
9457 mng_info->write_png_colortype = 7;
9460 (void) ThrowMagickException(&image->exception,
9461 GetMagickModule(),CoderWarning,
9462 "ignoring invalid defined png:color-type",
9465 if (logging != MagickFalse)
9466 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9467 " png:color-type=%d was defined.\n",mng_info->write_png_colortype-1);
9470 /* Check for chunks to be excluded:
9472 * The default is to not exclude any known chunks except for any
9473 * listed in the "unused_chunks" array, above.
9475 * Chunks can be listed for exclusion via a "PNG:exclude-chunk"
9476 * define (in the image properties or in the image artifacts)
9477 * or via a mng_info member. For convenience, in addition
9478 * to or instead of a comma-separated list of chunks, the
9479 * "exclude-chunk" string can be simply "all" or "none".
9481 * The exclude-chunk define takes priority over the mng_info.
9483 * A "PNG:include-chunk" define takes priority over both the
9484 * mng_info and the "PNG:exclude-chunk" define. Like the
9485 * "exclude-chunk" string, it can define "all" or "none" as
9486 * well as a comma-separated list. Chunks that are unknown to
9487 * ImageMagick are always excluded, regardless of their "copy-safe"
9488 * status according to the PNG specification, and even if they
9489 * appear in the "include-chunk" list.
9491 * Finally, all chunks listed in the "unused_chunks" array are
9492 * automatically excluded, regardless of the other instructions
9495 * if you exclude sRGB but not gAMA (recommended), then sRGB chunk
9496 * will not be written and the gAMA chunk will only be written if it
9497 * is not between .45 and .46, or approximately (1.0/2.2).
9499 * If you exclude tRNS and the image has transparency, the colortype
9500 * is forced to be 4 or 6 (GRAY_ALPHA or RGB_ALPHA).
9502 * The -strip option causes StripImage() to set the png:include-chunk
9503 * artifact to "none,gama".
9506 mng_info->ping_exclude_bKGD=MagickFalse;
9507 mng_info->ping_exclude_cHRM=MagickFalse;
9508 mng_info->ping_exclude_EXIF=MagickFalse; /* hex-encoded EXIF in zTXt */
9509 mng_info->ping_exclude_gAMA=MagickFalse;
9510 mng_info->ping_exclude_cHRM=MagickFalse;
9511 mng_info->ping_exclude_iCCP=MagickFalse;
9512 /* mng_info->ping_exclude_iTXt=MagickFalse; */
9513 mng_info->ping_exclude_oFFs=MagickFalse;
9514 mng_info->ping_exclude_pHYs=MagickFalse;
9515 mng_info->ping_exclude_sRGB=MagickFalse;
9516 mng_info->ping_exclude_tEXt=MagickFalse;
9517 mng_info->ping_exclude_tRNS=MagickFalse;
9518 mng_info->ping_exclude_vpAg=MagickFalse;
9519 mng_info->ping_exclude_zCCP=MagickFalse; /* hex-encoded iCCP in zTXt */
9520 mng_info->ping_exclude_zTXt=MagickFalse;
9522 excluding=MagickFalse;
9524 for (source=0; source<1; source++)
9528 value=GetImageArtifact(image,"png:exclude-chunk");
9531 value=GetImageArtifact(image,"png:exclude-chunks");
9535 value=GetImageOption(image_info,"png:exclude-chunk");
9538 value=GetImageOption(image_info,"png:exclude-chunks");
9547 excluding=MagickTrue;
9549 if (logging != MagickFalse)
9552 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9553 " png:exclude-chunk=%s found in image artifacts.\n", value);
9555 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9556 " png:exclude-chunk=%s found in image properties.\n", value);
9561 for (i=0; i<(int) last; i+=5)
9564 if (LocaleNCompare(value+i,"all",3) == 0)
9566 mng_info->ping_exclude_bKGD=MagickTrue;
9567 mng_info->ping_exclude_cHRM=MagickTrue;
9568 mng_info->ping_exclude_EXIF=MagickTrue;
9569 mng_info->ping_exclude_gAMA=MagickTrue;
9570 mng_info->ping_exclude_iCCP=MagickTrue;
9571 /* mng_info->ping_exclude_iTXt=MagickTrue; */
9572 mng_info->ping_exclude_oFFs=MagickTrue;
9573 mng_info->ping_exclude_pHYs=MagickTrue;
9574 mng_info->ping_exclude_sRGB=MagickTrue;
9575 mng_info->ping_exclude_tEXt=MagickTrue;
9576 mng_info->ping_exclude_tRNS=MagickTrue;
9577 mng_info->ping_exclude_vpAg=MagickTrue;
9578 mng_info->ping_exclude_zCCP=MagickTrue;
9579 mng_info->ping_exclude_zTXt=MagickTrue;
9583 if (LocaleNCompare(value+i,"none",4) == 0)
9585 mng_info->ping_exclude_bKGD=MagickFalse;
9586 mng_info->ping_exclude_cHRM=MagickFalse;
9587 mng_info->ping_exclude_EXIF=MagickFalse;
9588 mng_info->ping_exclude_gAMA=MagickFalse;
9589 mng_info->ping_exclude_iCCP=MagickFalse;
9590 /* mng_info->ping_exclude_iTXt=MagickFalse; */
9591 mng_info->ping_exclude_oFFs=MagickFalse;
9592 mng_info->ping_exclude_pHYs=MagickFalse;
9593 mng_info->ping_exclude_sRGB=MagickFalse;
9594 mng_info->ping_exclude_tEXt=MagickFalse;
9595 mng_info->ping_exclude_tRNS=MagickFalse;
9596 mng_info->ping_exclude_vpAg=MagickFalse;
9597 mng_info->ping_exclude_zCCP=MagickFalse;
9598 mng_info->ping_exclude_zTXt=MagickFalse;
9601 if (LocaleNCompare(value+i,"bkgd",4) == 0)
9602 mng_info->ping_exclude_bKGD=MagickTrue;
9604 if (LocaleNCompare(value+i,"chrm",4) == 0)
9605 mng_info->ping_exclude_cHRM=MagickTrue;
9607 if (LocaleNCompare(value+i,"exif",4) == 0)
9608 mng_info->ping_exclude_EXIF=MagickTrue;
9610 if (LocaleNCompare(value+i,"gama",4) == 0)
9611 mng_info->ping_exclude_gAMA=MagickTrue;
9613 if (LocaleNCompare(value+i,"iccp",4) == 0)
9614 mng_info->ping_exclude_iCCP=MagickTrue;
9617 if (LocaleNCompare(value+i,"itxt",4) == 0)
9618 mng_info->ping_exclude_iTXt=MagickTrue;
9621 if (LocaleNCompare(value+i,"gama",4) == 0)
9622 mng_info->ping_exclude_gAMA=MagickTrue;
9624 if (LocaleNCompare(value+i,"offs",4) == 0)
9625 mng_info->ping_exclude_oFFs=MagickTrue;
9627 if (LocaleNCompare(value+i,"phys",4) == 0)
9628 mng_info->ping_exclude_pHYs=MagickTrue;
9630 if (LocaleNCompare(value+i,"srgb",4) == 0)
9631 mng_info->ping_exclude_sRGB=MagickTrue;
9633 if (LocaleNCompare(value+i,"text",4) == 0)
9634 mng_info->ping_exclude_tEXt=MagickTrue;
9636 if (LocaleNCompare(value+i,"trns",4) == 0)
9637 mng_info->ping_exclude_tRNS=MagickTrue;
9639 if (LocaleNCompare(value+i,"vpag",4) == 0)
9640 mng_info->ping_exclude_vpAg=MagickTrue;
9642 if (LocaleNCompare(value+i,"zccp",4) == 0)
9643 mng_info->ping_exclude_zCCP=MagickTrue;
9645 if (LocaleNCompare(value+i,"ztxt",4) == 0)
9646 mng_info->ping_exclude_zTXt=MagickTrue;
9652 for (source=0; source<1; source++)
9656 value=GetImageArtifact(image,"png:include-chunk");
9659 value=GetImageArtifact(image,"png:include-chunks");
9663 value=GetImageOption(image_info,"png:include-chunk");
9666 value=GetImageOption(image_info,"png:include-chunks");
9674 excluding=MagickTrue;
9676 if (logging != MagickFalse)
9679 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9680 " png:include-chunk=%s found in image artifacts.\n", value);
9682 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9683 " png:include-chunk=%s found in image properties.\n", value);
9688 for (i=0; i<(int) last; i+=5)
9690 if (LocaleNCompare(value+i,"all",3) == 0)
9692 mng_info->ping_exclude_bKGD=MagickFalse;
9693 mng_info->ping_exclude_cHRM=MagickFalse;
9694 mng_info->ping_exclude_EXIF=MagickFalse;
9695 mng_info->ping_exclude_gAMA=MagickFalse;
9696 mng_info->ping_exclude_iCCP=MagickFalse;
9697 /* mng_info->ping_exclude_iTXt=MagickFalse; */
9698 mng_info->ping_exclude_oFFs=MagickFalse;
9699 mng_info->ping_exclude_pHYs=MagickFalse;
9700 mng_info->ping_exclude_sRGB=MagickFalse;
9701 mng_info->ping_exclude_tEXt=MagickFalse;
9702 mng_info->ping_exclude_tRNS=MagickFalse;
9703 mng_info->ping_exclude_vpAg=MagickFalse;
9704 mng_info->ping_exclude_zCCP=MagickFalse;
9705 mng_info->ping_exclude_zTXt=MagickFalse;
9709 if (LocaleNCompare(value+i,"none",4) == 0)
9711 mng_info->ping_exclude_bKGD=MagickTrue;
9712 mng_info->ping_exclude_cHRM=MagickTrue;
9713 mng_info->ping_exclude_EXIF=MagickTrue;
9714 mng_info->ping_exclude_gAMA=MagickTrue;
9715 mng_info->ping_exclude_iCCP=MagickTrue;
9716 /* mng_info->ping_exclude_iTXt=MagickTrue; */
9717 mng_info->ping_exclude_oFFs=MagickTrue;
9718 mng_info->ping_exclude_pHYs=MagickTrue;
9719 mng_info->ping_exclude_sRGB=MagickTrue;
9720 mng_info->ping_exclude_tEXt=MagickTrue;
9721 mng_info->ping_exclude_tRNS=MagickTrue;
9722 mng_info->ping_exclude_vpAg=MagickTrue;
9723 mng_info->ping_exclude_zCCP=MagickTrue;
9724 mng_info->ping_exclude_zTXt=MagickTrue;
9727 if (LocaleNCompare(value+i,"bkgd",4) == 0)
9728 mng_info->ping_exclude_bKGD=MagickFalse;
9730 if (LocaleNCompare(value+i,"chrm",4) == 0)
9731 mng_info->ping_exclude_cHRM=MagickFalse;
9733 if (LocaleNCompare(value+i,"exif",4) == 0)
9734 mng_info->ping_exclude_EXIF=MagickFalse;
9736 if (LocaleNCompare(value+i,"gama",4) == 0)
9737 mng_info->ping_exclude_gAMA=MagickFalse;
9739 if (LocaleNCompare(value+i,"iccp",4) == 0)
9740 mng_info->ping_exclude_iCCP=MagickFalse;
9743 if (LocaleNCompare(value+i,"itxt",4) == 0)
9744 mng_info->ping_exclude_iTXt=MagickFalse;
9747 if (LocaleNCompare(value+i,"gama",4) == 0)
9748 mng_info->ping_exclude_gAMA=MagickFalse;
9750 if (LocaleNCompare(value+i,"offs",4) == 0)
9751 mng_info->ping_exclude_oFFs=MagickFalse;
9753 if (LocaleNCompare(value+i,"phys",4) == 0)
9754 mng_info->ping_exclude_pHYs=MagickFalse;
9756 if (LocaleNCompare(value+i,"srgb",4) == 0)
9757 mng_info->ping_exclude_sRGB=MagickFalse;
9759 if (LocaleNCompare(value+i,"text",4) == 0)
9760 mng_info->ping_exclude_tEXt=MagickFalse;
9762 if (LocaleNCompare(value+i,"trns",4) == 0)
9763 mng_info->ping_exclude_tRNS=MagickFalse;
9765 if (LocaleNCompare(value+i,"vpag",4) == 0)
9766 mng_info->ping_exclude_vpAg=MagickFalse;
9768 if (LocaleNCompare(value+i,"zccp",4) == 0)
9769 mng_info->ping_exclude_zCCP=MagickFalse;
9771 if (LocaleNCompare(value+i,"ztxt",4) == 0)
9772 mng_info->ping_exclude_zTXt=MagickFalse;
9778 if (excluding != MagickFalse && logging != MagickFalse)
9780 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9781 " Chunks to be excluded from the output PNG:");
9782 if (mng_info->ping_exclude_bKGD != MagickFalse)
9783 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9785 if (mng_info->ping_exclude_cHRM != MagickFalse)
9786 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9788 if (mng_info->ping_exclude_EXIF != MagickFalse)
9789 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9791 if (mng_info->ping_exclude_gAMA != MagickFalse)
9792 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9794 if (mng_info->ping_exclude_iCCP != MagickFalse)
9795 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9798 if (mng_info->ping_exclude_iTXt != MagickFalse)
9799 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9802 if (mng_info->ping_exclude_oFFs != MagickFalse)
9803 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9805 if (mng_info->ping_exclude_pHYs != MagickFalse)
9806 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9808 if (mng_info->ping_exclude_sRGB != MagickFalse)
9809 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9811 if (mng_info->ping_exclude_tEXt != MagickFalse)
9812 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9814 if (mng_info->ping_exclude_tRNS != MagickFalse)
9815 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9817 if (mng_info->ping_exclude_vpAg != MagickFalse)
9818 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9820 if (mng_info->ping_exclude_zCCP != MagickFalse)
9821 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9823 if (mng_info->ping_exclude_zTXt != MagickFalse)
9824 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9828 mng_info->need_blob = MagickTrue;
9830 status=WriteOnePNGImage(mng_info,image_info,image);
9832 MngInfoFreeStruct(mng_info,&have_mng_structure);
9834 if (logging != MagickFalse)
9835 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"exit WritePNGImage()");
9840 #if defined(JNG_SUPPORTED)
9842 /* Write one JNG image */
9843 static MagickBooleanType WriteOneJNGImage(MngInfo *mng_info,
9844 const ImageInfo *image_info,Image *image)
9865 jng_alpha_compression_method,
9866 jng_alpha_sample_depth,
9873 logging=LogMagickEvent(CoderEvent,GetMagickModule(),
9874 " enter WriteOneJNGImage()");
9876 blob=(unsigned char *) NULL;
9877 jpeg_image=(Image *) NULL;
9878 jpeg_image_info=(ImageInfo *) NULL;
9881 transparent=image_info->type==GrayscaleMatteType ||
9882 image_info->type==TrueColorMatteType;
9884 jng_alpha_sample_depth=0;
9885 jng_quality=image_info->quality == 0UL ? 75UL : image_info->quality;
9886 jng_alpha_compression_method=0;
9888 if (image->matte != MagickFalse)
9890 /* if any pixels are transparent */
9891 transparent=MagickTrue;
9892 if (image_info->compression==JPEGCompression)
9893 jng_alpha_compression_method=8;
9900 /* Create JPEG blob, image, and image_info */
9901 if (logging != MagickFalse)
9902 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9903 " Creating jpeg_image_info for opacity.");
9905 jpeg_image_info=(ImageInfo *) CloneImageInfo(image_info);
9907 if (jpeg_image_info == (ImageInfo *) NULL)
9908 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
9910 if (logging != MagickFalse)
9911 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9912 " Creating jpeg_image.");
9914 jpeg_image=CloneImage(image,0,0,MagickTrue,&image->exception);
9916 if (jpeg_image == (Image *) NULL)
9917 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
9919 (void) CopyMagickString(jpeg_image->magick,"JPEG",MaxTextExtent);
9920 status=SeparateImageChannel(jpeg_image,OpacityChannel);
9921 status=NegateImage(jpeg_image,MagickFalse);
9922 jpeg_image->matte=MagickFalse;
9924 if (jng_quality >= 1000)
9925 jpeg_image_info->quality=jng_quality/1000;
9928 jpeg_image_info->quality=jng_quality;
9930 jpeg_image_info->type=GrayscaleType;
9931 (void) SetImageType(jpeg_image,GrayscaleType);
9932 (void) AcquireUniqueFilename(jpeg_image->filename);
9933 (void) FormatMagickString(jpeg_image_info->filename,MaxTextExtent,
9934 "%s",jpeg_image->filename);
9937 /* To do: check bit depth of PNG alpha channel */
9939 /* Check if image is grayscale. */
9940 if (image_info->type != TrueColorMatteType && image_info->type !=
9941 TrueColorType && ImageIsGray(image))
9946 if (jng_alpha_compression_method==0)
9951 /* Encode opacity as a grayscale PNG blob */
9952 status=OpenBlob(jpeg_image_info,jpeg_image,WriteBinaryBlobMode,
9954 if (logging != MagickFalse)
9955 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9956 " Creating PNG blob.");
9959 (void) CopyMagickString(jpeg_image_info->magick,"PNG",MaxTextExtent);
9960 (void) CopyMagickString(jpeg_image->magick,"PNG",MaxTextExtent);
9961 jpeg_image_info->interlace=NoInterlace;
9963 blob=ImageToBlob(jpeg_image_info,jpeg_image,&length,
9966 /* Retrieve sample depth used */
9967 value=GetImageProperty(jpeg_image,"png:bit-depth-written");
9968 if (value != (char *) NULL)
9969 jng_alpha_sample_depth= (unsigned int) value[0];
9973 /* Encode opacity as a grayscale JPEG blob */
9975 status=OpenBlob(jpeg_image_info,jpeg_image,WriteBinaryBlobMode,
9978 (void) CopyMagickString(jpeg_image_info->magick,"JPEG",MaxTextExtent);
9979 (void) CopyMagickString(jpeg_image->magick,"JPEG",MaxTextExtent);
9980 jpeg_image_info->interlace=NoInterlace;
9981 if (logging != MagickFalse)
9982 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9984 blob=ImageToBlob(jpeg_image_info,jpeg_image,&length,
9986 jng_alpha_sample_depth=8;
9988 if (logging != MagickFalse)
9989 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9990 " Successfully read jpeg_image into a blob, length=%.20g.",
9994 /* Destroy JPEG image and image_info */
9995 jpeg_image=DestroyImage(jpeg_image);
9996 (void) RelinquishUniqueFileResource(jpeg_image_info->filename);
9997 jpeg_image_info=DestroyImageInfo(jpeg_image_info);
10000 /* Write JHDR chunk */
10001 (void) WriteBlobMSBULong(image,16L); /* chunk data length=16 */
10002 PNGType(chunk,mng_JHDR);
10003 LogPNGChunk(logging,mng_JHDR,16L);
10004 PNGLong(chunk+4,(png_uint_32) image->columns);
10005 PNGLong(chunk+8,(png_uint_32) image->rows);
10006 chunk[12]=jng_color_type;
10007 chunk[13]=8; /* sample depth */
10008 chunk[14]=8; /*jng_image_compression_method */
10009 chunk[15]=(unsigned char) (image_info->interlace == NoInterlace ? 0 : 8);
10010 chunk[16]=jng_alpha_sample_depth;
10011 chunk[17]=jng_alpha_compression_method;
10012 chunk[18]=0; /*jng_alpha_filter_method */
10013 chunk[19]=0; /*jng_alpha_interlace_method */
10014 (void) WriteBlob(image,20,chunk);
10015 (void) WriteBlobMSBULong(image,crc32(0,chunk,20));
10016 if (logging != MagickFalse)
10018 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10019 " JNG width:%15lu",(unsigned long) image->columns);
10021 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10022 " JNG height:%14lu",(unsigned long) image->rows);
10024 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10025 " JNG color type:%10d",jng_color_type);
10027 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10028 " JNG sample depth:%8d",8);
10030 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10031 " JNG compression:%9d",8);
10033 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10034 " JNG interlace:%11d",0);
10036 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10037 " JNG alpha depth:%9d",jng_alpha_sample_depth);
10039 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10040 " JNG alpha compression:%3d",jng_alpha_compression_method);
10042 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10043 " JNG alpha filter:%8d",0);
10045 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10046 " JNG alpha interlace:%5d",0);
10049 /* Write any JNG-chunk-b profiles */
10050 (void) Magick_png_write_chunk_from_profile(image,"JNG-chunk-b",logging);
10053 Write leading ancillary chunks
10059 Write JNG bKGD chunk
10070 if (jng_color_type == 8 || jng_color_type == 12)
10074 (void) WriteBlobMSBULong(image,(size_t) (num_bytes-4L));
10075 PNGType(chunk,mng_bKGD);
10076 LogPNGChunk(logging,mng_bKGD,(size_t) (num_bytes-4L));
10077 red=ScaleQuantumToChar(image->background_color.red);
10078 green=ScaleQuantumToChar(image->background_color.green);
10079 blue=ScaleQuantumToChar(image->background_color.blue);
10086 (void) WriteBlob(image,(size_t) num_bytes,chunk);
10087 (void) WriteBlobMSBULong(image,crc32(0,chunk,(uInt) num_bytes));
10090 if ((image->colorspace == sRGBColorspace || image->rendering_intent))
10093 Write JNG sRGB chunk
10095 (void) WriteBlobMSBULong(image,1L);
10096 PNGType(chunk,mng_sRGB);
10097 LogPNGChunk(logging,mng_sRGB,1L);
10099 if (image->rendering_intent != UndefinedIntent)
10100 chunk[4]=(unsigned char)
10101 Magick_RenderingIntent_to_PNG_RenderingIntent(
10102 (image->rendering_intent));
10105 chunk[4]=(unsigned char)
10106 Magick_RenderingIntent_to_PNG_RenderingIntent(
10107 (PerceptualIntent));
10109 (void) WriteBlob(image,5,chunk);
10110 (void) WriteBlobMSBULong(image,crc32(0,chunk,5));
10114 if (image->gamma != 0.0)
10117 Write JNG gAMA chunk
10119 (void) WriteBlobMSBULong(image,4L);
10120 PNGType(chunk,mng_gAMA);
10121 LogPNGChunk(logging,mng_gAMA,4L);
10122 PNGLong(chunk+4,(png_uint_32) (100000*image->gamma+0.5));
10123 (void) WriteBlob(image,8,chunk);
10124 (void) WriteBlobMSBULong(image,crc32(0,chunk,8));
10127 if ((mng_info->equal_chrms == MagickFalse) &&
10128 (image->chromaticity.red_primary.x != 0.0))
10134 Write JNG cHRM chunk
10136 (void) WriteBlobMSBULong(image,32L);
10137 PNGType(chunk,mng_cHRM);
10138 LogPNGChunk(logging,mng_cHRM,32L);
10139 primary=image->chromaticity.white_point;
10140 PNGLong(chunk+4,(png_uint_32) (100000*primary.x+0.5));
10141 PNGLong(chunk+8,(png_uint_32) (100000*primary.y+0.5));
10142 primary=image->chromaticity.red_primary;
10143 PNGLong(chunk+12,(png_uint_32) (100000*primary.x+0.5));
10144 PNGLong(chunk+16,(png_uint_32) (100000*primary.y+0.5));
10145 primary=image->chromaticity.green_primary;
10146 PNGLong(chunk+20,(png_uint_32) (100000*primary.x+0.5));
10147 PNGLong(chunk+24,(png_uint_32) (100000*primary.y+0.5));
10148 primary=image->chromaticity.blue_primary;
10149 PNGLong(chunk+28,(png_uint_32) (100000*primary.x+0.5));
10150 PNGLong(chunk+32,(png_uint_32) (100000*primary.y+0.5));
10151 (void) WriteBlob(image,36,chunk);
10152 (void) WriteBlobMSBULong(image,crc32(0,chunk,36));
10156 if (image->x_resolution && image->y_resolution && !mng_info->equal_physs)
10159 Write JNG pHYs chunk
10161 (void) WriteBlobMSBULong(image,9L);
10162 PNGType(chunk,mng_pHYs);
10163 LogPNGChunk(logging,mng_pHYs,9L);
10164 if (image->units == PixelsPerInchResolution)
10166 PNGLong(chunk+4,(png_uint_32)
10167 (image->x_resolution*100.0/2.54+0.5));
10169 PNGLong(chunk+8,(png_uint_32)
10170 (image->y_resolution*100.0/2.54+0.5));
10177 if (image->units == PixelsPerCentimeterResolution)
10179 PNGLong(chunk+4,(png_uint_32)
10180 (image->x_resolution*100.0+0.5));
10182 PNGLong(chunk+8,(png_uint_32)
10183 (image->y_resolution*100.0+0.5));
10190 PNGLong(chunk+4,(png_uint_32) (image->x_resolution+0.5));
10191 PNGLong(chunk+8,(png_uint_32) (image->y_resolution+0.5));
10195 (void) WriteBlob(image,13,chunk);
10196 (void) WriteBlobMSBULong(image,crc32(0,chunk,13));
10199 if (mng_info->write_mng == 0 && (image->page.x || image->page.y))
10202 Write JNG oFFs chunk
10204 (void) WriteBlobMSBULong(image,9L);
10205 PNGType(chunk,mng_oFFs);
10206 LogPNGChunk(logging,mng_oFFs,9L);
10207 PNGsLong(chunk+4,(ssize_t) (image->page.x));
10208 PNGsLong(chunk+8,(ssize_t) (image->page.y));
10210 (void) WriteBlob(image,13,chunk);
10211 (void) WriteBlobMSBULong(image,crc32(0,chunk,13));
10213 if (mng_info->write_mng == 0 && (image->page.width || image->page.height))
10215 (void) WriteBlobMSBULong(image,9L); /* data length=8 */
10216 PNGType(chunk,mng_vpAg);
10217 LogPNGChunk(logging,mng_vpAg,9L);
10218 PNGLong(chunk+4,(png_uint_32) image->page.width);
10219 PNGLong(chunk+8,(png_uint_32) image->page.height);
10220 chunk[12]=0; /* unit = pixels */
10221 (void) WriteBlob(image,13,chunk);
10222 (void) WriteBlobMSBULong(image,crc32(0,chunk,13));
10228 if (jng_alpha_compression_method==0)
10236 /* Write IDAT chunk header */
10237 if (logging != MagickFalse)
10238 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10239 " Write IDAT chunks from blob, length=%.20g.",(double)
10242 /* Copy IDAT chunks */
10245 for (i=8; i<(ssize_t) length; i+=len+12)
10247 len=(*p<<24)|((*(p+1))<<16)|((*(p+2))<<8)|(*(p+3));
10250 if (*(p)==73 && *(p+1)==68 && *(p+2)==65 && *(p+3)==84) /* IDAT */
10252 /* Found an IDAT chunk. */
10253 (void) WriteBlobMSBULong(image,(size_t) len);
10254 LogPNGChunk(logging,mng_IDAT,(size_t) len);
10255 (void) WriteBlob(image,(size_t) len+4,p);
10256 (void) WriteBlobMSBULong(image,
10257 crc32(0,p,(uInt) len+4));
10262 if (logging != MagickFalse)
10263 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10264 " Skipping %c%c%c%c chunk, length=%.20g.",
10265 *(p),*(p+1),*(p+2),*(p+3),(double) len);
10272 /* Write JDAA chunk header */
10273 if (logging != MagickFalse)
10274 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10275 " Write JDAA chunk, length=%.20g.",(double) length);
10276 (void) WriteBlobMSBULong(image,(size_t) length);
10277 PNGType(chunk,mng_JDAA);
10278 LogPNGChunk(logging,mng_JDAA,length);
10279 /* Write JDAT chunk(s) data */
10280 (void) WriteBlob(image,4,chunk);
10281 (void) WriteBlob(image,length,blob);
10282 (void) WriteBlobMSBULong(image,crc32(crc32(0,chunk,4),blob,
10285 blob=(unsigned char *) RelinquishMagickMemory(blob);
10288 /* Encode image as a JPEG blob */
10289 if (logging != MagickFalse)
10290 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10291 " Creating jpeg_image_info.");
10292 jpeg_image_info=(ImageInfo *) CloneImageInfo(image_info);
10293 if (jpeg_image_info == (ImageInfo *) NULL)
10294 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
10296 if (logging != MagickFalse)
10297 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10298 " Creating jpeg_image.");
10300 jpeg_image=CloneImage(image,0,0,MagickTrue,&image->exception);
10301 if (jpeg_image == (Image *) NULL)
10302 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
10303 (void) CopyMagickString(jpeg_image->magick,"JPEG",MaxTextExtent);
10305 (void) AcquireUniqueFilename(jpeg_image->filename);
10306 (void) FormatMagickString(jpeg_image_info->filename,MaxTextExtent,"%s",
10307 jpeg_image->filename);
10309 status=OpenBlob(jpeg_image_info,jpeg_image,WriteBinaryBlobMode,
10310 &image->exception);
10312 if (logging != MagickFalse)
10313 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10314 " Created jpeg_image, %.20g x %.20g.",(double) jpeg_image->columns,
10315 (double) jpeg_image->rows);
10317 if (jng_color_type == 8 || jng_color_type == 12)
10318 jpeg_image_info->type=GrayscaleType;
10320 jpeg_image_info->quality=jng_quality % 1000;
10321 (void) CopyMagickString(jpeg_image_info->magick,"JPEG",MaxTextExtent);
10322 (void) CopyMagickString(jpeg_image->magick,"JPEG",MaxTextExtent);
10324 if (logging != MagickFalse)
10325 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10326 " Creating blob.");
10328 blob=ImageToBlob(jpeg_image_info,jpeg_image,&length,&image->exception);
10330 if (logging != MagickFalse)
10332 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10333 " Successfully read jpeg_image into a blob, length=%.20g.",
10336 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10337 " Write JDAT chunk, length=%.20g.",(double) length);
10340 /* Write JDAT chunk(s) */
10341 (void) WriteBlobMSBULong(image,(size_t) length);
10342 PNGType(chunk,mng_JDAT);
10343 LogPNGChunk(logging,mng_JDAT,length);
10344 (void) WriteBlob(image,4,chunk);
10345 (void) WriteBlob(image,length,blob);
10346 (void) WriteBlobMSBULong(image,crc32(crc32(0,chunk,4),blob,(uInt) length));
10348 jpeg_image=DestroyImage(jpeg_image);
10349 (void) RelinquishUniqueFileResource(jpeg_image_info->filename);
10350 jpeg_image_info=DestroyImageInfo(jpeg_image_info);
10351 blob=(unsigned char *) RelinquishMagickMemory(blob);
10353 /* Write any JNG-chunk-e profiles */
10354 (void) Magick_png_write_chunk_from_profile(image,"JNG-chunk-e",logging);
10356 /* Write IEND chunk */
10357 (void) WriteBlobMSBULong(image,0L);
10358 PNGType(chunk,mng_IEND);
10359 LogPNGChunk(logging,mng_IEND,0);
10360 (void) WriteBlob(image,4,chunk);
10361 (void) WriteBlobMSBULong(image,crc32(0,chunk,4));
10363 if (logging != MagickFalse)
10364 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10365 " exit WriteOneJNGImage()");
10372 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
10376 % W r i t e J N G I m a g e %
10380 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
10382 % WriteJNGImage() writes a JPEG Network Graphics (JNG) image file.
10384 % JNG support written by Glenn Randers-Pehrson, glennrp@image...
10386 % The format of the WriteJNGImage method is:
10388 % MagickBooleanType WriteJNGImage(const ImageInfo *image_info,Image *image)
10390 % A description of each parameter follows:
10392 % o image_info: the image info.
10394 % o image: The image.
10396 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
10398 static MagickBooleanType WriteJNGImage(const ImageInfo *image_info,Image *image)
10401 have_mng_structure,
10411 assert(image_info != (const ImageInfo *) NULL);
10412 assert(image_info->signature == MagickSignature);
10413 assert(image != (Image *) NULL);
10414 assert(image->signature == MagickSignature);
10415 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
10416 logging=LogMagickEvent(CoderEvent,GetMagickModule(),"enter WriteJNGImage()");
10417 status=OpenBlob(image_info,image,WriteBinaryBlobMode,&image->exception);
10418 if (status == MagickFalse)
10422 Allocate a MngInfo structure.
10424 have_mng_structure=MagickFalse;
10425 mng_info=(MngInfo *) AcquireMagickMemory(sizeof(MngInfo));
10426 if (mng_info == (MngInfo *) NULL)
10427 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
10429 Initialize members of the MngInfo structure.
10431 (void) ResetMagickMemory(mng_info,0,sizeof(MngInfo));
10432 mng_info->image=image;
10433 have_mng_structure=MagickTrue;
10435 (void) WriteBlob(image,8,(const unsigned char *) "\213JNG\r\n\032\n");
10437 status=WriteOneJNGImage(mng_info,image_info,image);
10438 (void) CloseBlob(image);
10440 (void) CatchImageException(image);
10441 MngInfoFreeStruct(mng_info,&have_mng_structure);
10442 if (logging != MagickFalse)
10443 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"exit WriteJNGImage()");
10450 static MagickBooleanType WriteMNGImage(const ImageInfo *image_info,Image *image)
10459 have_mng_structure,
10462 volatile MagickBooleanType
10474 #if defined(PNG_WRITE_EMPTY_PLTE_SUPPORTED) || \
10475 defined(PNG_MNG_FEATURES_SUPPORTED)
10478 all_images_are_gray,
10488 volatile unsigned int
10499 #if (PNG_LIBPNG_VER < 10200)
10500 if (image_info->verbose)
10501 printf("Your PNG library (libpng-%s) is rather old.\n",
10502 PNG_LIBPNG_VER_STRING);
10508 assert(image_info != (const ImageInfo *) NULL);
10509 assert(image_info->signature == MagickSignature);
10510 assert(image != (Image *) NULL);
10511 assert(image->signature == MagickSignature);
10512 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
10513 logging=LogMagickEvent(CoderEvent,GetMagickModule(),"enter WriteMNGImage()");
10514 status=OpenBlob(image_info,image,WriteBinaryBlobMode,&image->exception);
10515 if (status == MagickFalse)
10519 Allocate a MngInfo structure.
10521 have_mng_structure=MagickFalse;
10522 mng_info=(MngInfo *) AcquireMagickMemory(sizeof(MngInfo));
10523 if (mng_info == (MngInfo *) NULL)
10524 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
10526 Initialize members of the MngInfo structure.
10528 (void) ResetMagickMemory(mng_info,0,sizeof(MngInfo));
10529 mng_info->image=image;
10530 have_mng_structure=MagickTrue;
10531 write_mng=LocaleCompare(image_info->magick,"MNG") == 0;
10534 * See if user has requested a specific PNG subformat to be used
10535 * for all of the PNGs in the MNG being written, e.g.,
10537 * convert *.png png8:animation.mng
10539 * To do: check -define png:bit_depth and png:color_type as well,
10540 * or perhaps use mng:bit_depth and mng:color_type instead for
10544 mng_info->write_png8=LocaleCompare(image_info->magick,"PNG8") == 0;
10545 mng_info->write_png24=LocaleCompare(image_info->magick,"PNG24") == 0;
10546 mng_info->write_png32=LocaleCompare(image_info->magick,"PNG32") == 0;
10548 write_jng=MagickFalse;
10549 if (image_info->compression == JPEGCompression)
10550 write_jng=MagickTrue;
10552 mng_info->adjoin=image_info->adjoin &&
10553 (GetNextImageInList(image) != (Image *) NULL) && write_mng;
10555 if (logging != MagickFalse)
10557 /* Log some info about the input */
10561 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10562 " Checking input image(s)");
10564 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10565 " Image_info depth: %.20g",(double) image_info->depth);
10567 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10568 " Type: %d",image_info->type);
10571 for (p=image; p != (Image *) NULL; p=GetNextImageInList(p))
10573 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10574 " Scene: %.20g",(double) scene++);
10576 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10577 " Image depth: %.20g",(double) p->depth);
10580 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10584 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10587 if (p->storage_class == PseudoClass)
10588 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10589 " Storage class: PseudoClass");
10592 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10593 " Storage class: DirectClass");
10596 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10597 " Number of colors: %.20g",(double) p->colors);
10600 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10601 " Number of colors: unspecified");
10603 if (mng_info->adjoin == MagickFalse)
10608 use_global_plte=MagickFalse;
10609 all_images_are_gray=MagickFalse;
10610 #ifdef PNG_WRITE_EMPTY_PLTE_SUPPORTED
10611 need_local_plte=MagickTrue;
10613 need_defi=MagickFalse;
10614 need_matte=MagickFalse;
10615 mng_info->framing_mode=1;
10616 mng_info->old_framing_mode=1;
10619 if (image_info->page != (char *) NULL)
10622 Determine image bounding box.
10624 SetGeometry(image,&mng_info->page);
10625 (void) ParseMetaGeometry(image_info->page,&mng_info->page.x,
10626 &mng_info->page.y,&mng_info->page.width,&mng_info->page.height);
10638 mng_info->page=image->page;
10639 need_geom=MagickTrue;
10640 if (mng_info->page.width || mng_info->page.height)
10641 need_geom=MagickFalse;
10643 Check all the scenes.
10645 initial_delay=image->delay;
10646 need_iterations=MagickFalse;
10647 mng_info->equal_chrms=image->chromaticity.red_primary.x != 0.0;
10648 mng_info->equal_physs=MagickTrue,
10649 mng_info->equal_gammas=MagickTrue;
10650 mng_info->equal_srgbs=MagickTrue;
10651 mng_info->equal_backgrounds=MagickTrue;
10653 #if defined(PNG_WRITE_EMPTY_PLTE_SUPPORTED) || \
10654 defined(PNG_MNG_FEATURES_SUPPORTED)
10655 all_images_are_gray=MagickTrue;
10656 mng_info->equal_palettes=MagickFalse;
10657 need_local_plte=MagickFalse;
10659 for (next_image=image; next_image != (Image *) NULL; )
10663 if ((next_image->columns+next_image->page.x) > mng_info->page.width)
10664 mng_info->page.width=next_image->columns+next_image->page.x;
10666 if ((next_image->rows+next_image->page.y) > mng_info->page.height)
10667 mng_info->page.height=next_image->rows+next_image->page.y;
10670 if (next_image->page.x || next_image->page.y)
10671 need_defi=MagickTrue;
10673 if (next_image->matte)
10674 need_matte=MagickTrue;
10676 if ((int) next_image->dispose >= BackgroundDispose)
10677 if (next_image->matte || next_image->page.x || next_image->page.y ||
10678 ((next_image->columns < mng_info->page.width) &&
10679 (next_image->rows < mng_info->page.height)))
10680 mng_info->need_fram=MagickTrue;
10682 if (next_image->iterations)
10683 need_iterations=MagickTrue;
10685 final_delay=next_image->delay;
10687 if (final_delay != initial_delay || final_delay > 1UL*
10688 next_image->ticks_per_second)
10689 mng_info->need_fram=1;
10691 #if defined(PNG_WRITE_EMPTY_PLTE_SUPPORTED) || \
10692 defined(PNG_MNG_FEATURES_SUPPORTED)
10694 check for global palette possibility.
10696 if (image->matte != MagickFalse)
10697 need_local_plte=MagickTrue;
10699 if (need_local_plte == 0)
10701 if (ImageIsGray(image) == MagickFalse)
10702 all_images_are_gray=MagickFalse;
10703 mng_info->equal_palettes=PalettesAreEqual(image,next_image);
10704 if (use_global_plte == 0)
10705 use_global_plte=mng_info->equal_palettes;
10706 need_local_plte=!mng_info->equal_palettes;
10709 if (GetNextImageInList(next_image) != (Image *) NULL)
10711 if (next_image->background_color.red !=
10712 next_image->next->background_color.red ||
10713 next_image->background_color.green !=
10714 next_image->next->background_color.green ||
10715 next_image->background_color.blue !=
10716 next_image->next->background_color.blue)
10717 mng_info->equal_backgrounds=MagickFalse;
10719 if (next_image->gamma != next_image->next->gamma)
10720 mng_info->equal_gammas=MagickFalse;
10722 if (next_image->rendering_intent !=
10723 next_image->next->rendering_intent)
10724 mng_info->equal_srgbs=MagickFalse;
10726 if ((next_image->units != next_image->next->units) ||
10727 (next_image->x_resolution != next_image->next->x_resolution) ||
10728 (next_image->y_resolution != next_image->next->y_resolution))
10729 mng_info->equal_physs=MagickFalse;
10731 if (mng_info->equal_chrms)
10733 if (next_image->chromaticity.red_primary.x !=
10734 next_image->next->chromaticity.red_primary.x ||
10735 next_image->chromaticity.red_primary.y !=
10736 next_image->next->chromaticity.red_primary.y ||
10737 next_image->chromaticity.green_primary.x !=
10738 next_image->next->chromaticity.green_primary.x ||
10739 next_image->chromaticity.green_primary.y !=
10740 next_image->next->chromaticity.green_primary.y ||
10741 next_image->chromaticity.blue_primary.x !=
10742 next_image->next->chromaticity.blue_primary.x ||
10743 next_image->chromaticity.blue_primary.y !=
10744 next_image->next->chromaticity.blue_primary.y ||
10745 next_image->chromaticity.white_point.x !=
10746 next_image->next->chromaticity.white_point.x ||
10747 next_image->chromaticity.white_point.y !=
10748 next_image->next->chromaticity.white_point.y)
10749 mng_info->equal_chrms=MagickFalse;
10753 next_image=GetNextImageInList(next_image);
10755 if (image_count < 2)
10757 mng_info->equal_backgrounds=MagickFalse;
10758 mng_info->equal_chrms=MagickFalse;
10759 mng_info->equal_gammas=MagickFalse;
10760 mng_info->equal_srgbs=MagickFalse;
10761 mng_info->equal_physs=MagickFalse;
10762 use_global_plte=MagickFalse;
10763 #ifdef PNG_WRITE_EMPTY_PLTE_SUPPORTED
10764 need_local_plte=MagickTrue;
10766 need_iterations=MagickFalse;
10769 if (mng_info->need_fram == MagickFalse)
10772 Only certain framing rates 100/n are exactly representable without
10773 the FRAM chunk but we'll allow some slop in VLC files
10775 if (final_delay == 0)
10777 if (need_iterations != MagickFalse)
10780 It's probably a GIF with loop; don't run it *too* fast.
10782 if (mng_info->adjoin)
10785 (void) ThrowMagickException(&image->exception,
10786 GetMagickModule(),CoderWarning,
10787 "input has zero delay between all frames; assuming",
10792 mng_info->ticks_per_second=0;
10794 if (final_delay != 0)
10795 mng_info->ticks_per_second=(png_uint_32)
10796 (image->ticks_per_second/final_delay);
10797 if (final_delay > 50)
10798 mng_info->ticks_per_second=2;
10800 if (final_delay > 75)
10801 mng_info->ticks_per_second=1;
10803 if (final_delay > 125)
10804 mng_info->need_fram=MagickTrue;
10806 if (need_defi && final_delay > 2 && (final_delay != 4) &&
10807 (final_delay != 5) && (final_delay != 10) && (final_delay != 20) &&
10808 (final_delay != 25) && (final_delay != 50) && (final_delay !=
10809 1UL*image->ticks_per_second))
10810 mng_info->need_fram=MagickTrue; /* make it exact; cannot be VLC */
10813 if (mng_info->need_fram != MagickFalse)
10814 mng_info->ticks_per_second=1UL*image->ticks_per_second;
10816 If pseudocolor, we should also check to see if all the
10817 palettes are identical and write a global PLTE if they are.
10821 Write the MNG version 1.0 signature and MHDR chunk.
10823 (void) WriteBlob(image,8,(const unsigned char *) "\212MNG\r\n\032\n");
10824 (void) WriteBlobMSBULong(image,28L); /* chunk data length=28 */
10825 PNGType(chunk,mng_MHDR);
10826 LogPNGChunk(logging,mng_MHDR,28L);
10827 PNGLong(chunk+4,(png_uint_32) mng_info->page.width);
10828 PNGLong(chunk+8,(png_uint_32) mng_info->page.height);
10829 PNGLong(chunk+12,mng_info->ticks_per_second);
10830 PNGLong(chunk+16,0L); /* layer count=unknown */
10831 PNGLong(chunk+20,0L); /* frame count=unknown */
10832 PNGLong(chunk+24,0L); /* play time=unknown */
10837 if (need_defi || mng_info->need_fram || use_global_plte)
10838 PNGLong(chunk+28,27L); /* simplicity=LC+JNG */
10841 PNGLong(chunk+28,25L); /* simplicity=VLC+JNG */
10846 if (need_defi || mng_info->need_fram || use_global_plte)
10847 PNGLong(chunk+28,19L); /* simplicity=LC+JNG, no transparency */
10850 PNGLong(chunk+28,17L); /* simplicity=VLC+JNG, no transparency */
10858 if (need_defi || mng_info->need_fram || use_global_plte)
10859 PNGLong(chunk+28,11L); /* simplicity=LC */
10862 PNGLong(chunk+28,9L); /* simplicity=VLC */
10867 if (need_defi || mng_info->need_fram || use_global_plte)
10868 PNGLong(chunk+28,3L); /* simplicity=LC, no transparency */
10871 PNGLong(chunk+28,1L); /* simplicity=VLC, no transparency */
10874 (void) WriteBlob(image,32,chunk);
10875 (void) WriteBlobMSBULong(image,crc32(0,chunk,32));
10876 option=GetImageOption(image_info,"mng:need-cacheoff");
10877 if (option != (const char *) NULL)
10883 Write "nEED CACHEOFF" to turn playback caching off for streaming MNG.
10885 PNGType(chunk,mng_nEED);
10886 length=CopyMagickString((char *) chunk+4,"CACHEOFF",20);
10887 (void) WriteBlobMSBULong(image,(size_t) length);
10888 LogPNGChunk(logging,mng_nEED,(size_t) length);
10890 (void) WriteBlob(image,length,chunk);
10891 (void) WriteBlobMSBULong(image,crc32(0,chunk,(uInt) length));
10893 if ((GetPreviousImageInList(image) == (Image *) NULL) &&
10894 (GetNextImageInList(image) != (Image *) NULL) &&
10895 (image->iterations != 1))
10898 Write MNG TERM chunk
10900 (void) WriteBlobMSBULong(image,10L); /* data length=10 */
10901 PNGType(chunk,mng_TERM);
10902 LogPNGChunk(logging,mng_TERM,10L);
10903 chunk[4]=3; /* repeat animation */
10904 chunk[5]=0; /* show last frame when done */
10905 PNGLong(chunk+6,(png_uint_32) (mng_info->ticks_per_second*
10906 final_delay/MagickMax(image->ticks_per_second,1)));
10908 if (image->iterations == 0)
10909 PNGLong(chunk+10,PNG_UINT_31_MAX);
10912 PNGLong(chunk+10,(png_uint_32) image->iterations);
10914 if (logging != MagickFalse)
10916 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10917 " TERM delay: %.20g",(double) (mng_info->ticks_per_second*
10918 final_delay/MagickMax(image->ticks_per_second,1)));
10920 if (image->iterations == 0)
10921 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10922 " TERM iterations: %.20g",(double) PNG_UINT_31_MAX);
10925 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10926 " Image iterations: %.20g",(double) image->iterations);
10928 (void) WriteBlob(image,14,chunk);
10929 (void) WriteBlobMSBULong(image,crc32(0,chunk,14));
10932 To do: check for cHRM+gAMA == sRGB, and write sRGB instead.
10934 if ((image->colorspace == sRGBColorspace || image->rendering_intent) &&
10935 mng_info->equal_srgbs)
10938 Write MNG sRGB chunk
10940 (void) WriteBlobMSBULong(image,1L);
10941 PNGType(chunk,mng_sRGB);
10942 LogPNGChunk(logging,mng_sRGB,1L);
10944 if (image->rendering_intent != UndefinedIntent)
10945 chunk[4]=(unsigned char)
10946 Magick_RenderingIntent_to_PNG_RenderingIntent(
10947 (image->rendering_intent));
10950 chunk[4]=(unsigned char)
10951 Magick_RenderingIntent_to_PNG_RenderingIntent(
10952 (PerceptualIntent));
10954 (void) WriteBlob(image,5,chunk);
10955 (void) WriteBlobMSBULong(image,crc32(0,chunk,5));
10956 mng_info->have_write_global_srgb=MagickTrue;
10961 if (image->gamma && mng_info->equal_gammas)
10964 Write MNG gAMA chunk
10966 (void) WriteBlobMSBULong(image,4L);
10967 PNGType(chunk,mng_gAMA);
10968 LogPNGChunk(logging,mng_gAMA,4L);
10969 PNGLong(chunk+4,(png_uint_32) (100000*image->gamma+0.5));
10970 (void) WriteBlob(image,8,chunk);
10971 (void) WriteBlobMSBULong(image,crc32(0,chunk,8));
10972 mng_info->have_write_global_gama=MagickTrue;
10974 if (mng_info->equal_chrms)
10980 Write MNG cHRM chunk
10982 (void) WriteBlobMSBULong(image,32L);
10983 PNGType(chunk,mng_cHRM);
10984 LogPNGChunk(logging,mng_cHRM,32L);
10985 primary=image->chromaticity.white_point;
10986 PNGLong(chunk+4,(png_uint_32) (100000*primary.x+0.5));
10987 PNGLong(chunk+8,(png_uint_32) (100000*primary.y+0.5));
10988 primary=image->chromaticity.red_primary;
10989 PNGLong(chunk+12,(png_uint_32) (100000*primary.x+0.5));
10990 PNGLong(chunk+16,(png_uint_32) (100000*primary.y+0.5));
10991 primary=image->chromaticity.green_primary;
10992 PNGLong(chunk+20,(png_uint_32) (100000*primary.x+0.5));
10993 PNGLong(chunk+24,(png_uint_32) (100000*primary.y+0.5));
10994 primary=image->chromaticity.blue_primary;
10995 PNGLong(chunk+28,(png_uint_32) (100000*primary.x+0.5));
10996 PNGLong(chunk+32,(png_uint_32) (100000*primary.y+0.5));
10997 (void) WriteBlob(image,36,chunk);
10998 (void) WriteBlobMSBULong(image,crc32(0,chunk,36));
10999 mng_info->have_write_global_chrm=MagickTrue;
11002 if (image->x_resolution && image->y_resolution && mng_info->equal_physs)
11005 Write MNG pHYs chunk
11007 (void) WriteBlobMSBULong(image,9L);
11008 PNGType(chunk,mng_pHYs);
11009 LogPNGChunk(logging,mng_pHYs,9L);
11011 if (image->units == PixelsPerInchResolution)
11013 PNGLong(chunk+4,(png_uint_32)
11014 (image->x_resolution*100.0/2.54+0.5));
11016 PNGLong(chunk+8,(png_uint_32)
11017 (image->y_resolution*100.0/2.54+0.5));
11024 if (image->units == PixelsPerCentimeterResolution)
11026 PNGLong(chunk+4,(png_uint_32)
11027 (image->x_resolution*100.0+0.5));
11029 PNGLong(chunk+8,(png_uint_32)
11030 (image->y_resolution*100.0+0.5));
11037 PNGLong(chunk+4,(png_uint_32) (image->x_resolution+0.5));
11038 PNGLong(chunk+8,(png_uint_32) (image->y_resolution+0.5));
11042 (void) WriteBlob(image,13,chunk);
11043 (void) WriteBlobMSBULong(image,crc32(0,chunk,13));
11046 Write MNG BACK chunk and global bKGD chunk, if the image is transparent
11047 or does not cover the entire frame.
11049 if (write_mng && (image->matte || image->page.x > 0 ||
11050 image->page.y > 0 || (image->page.width &&
11051 (image->page.width+image->page.x < mng_info->page.width))
11052 || (image->page.height && (image->page.height+image->page.y
11053 < mng_info->page.height))))
11055 (void) WriteBlobMSBULong(image,6L);
11056 PNGType(chunk,mng_BACK);
11057 LogPNGChunk(logging,mng_BACK,6L);
11058 red=ScaleQuantumToShort(image->background_color.red);
11059 green=ScaleQuantumToShort(image->background_color.green);
11060 blue=ScaleQuantumToShort(image->background_color.blue);
11061 PNGShort(chunk+4,red);
11062 PNGShort(chunk+6,green);
11063 PNGShort(chunk+8,blue);
11064 (void) WriteBlob(image,10,chunk);
11065 (void) WriteBlobMSBULong(image,crc32(0,chunk,10));
11066 if (mng_info->equal_backgrounds)
11068 (void) WriteBlobMSBULong(image,6L);
11069 PNGType(chunk,mng_bKGD);
11070 LogPNGChunk(logging,mng_bKGD,6L);
11071 (void) WriteBlob(image,10,chunk);
11072 (void) WriteBlobMSBULong(image,crc32(0,chunk,10));
11076 #ifdef PNG_WRITE_EMPTY_PLTE_SUPPORTED
11077 if ((need_local_plte == MagickFalse) &&
11078 (image->storage_class == PseudoClass) &&
11079 (all_images_are_gray == MagickFalse))
11085 Write MNG PLTE chunk
11087 data_length=3*image->colors;
11088 (void) WriteBlobMSBULong(image,data_length);
11089 PNGType(chunk,mng_PLTE);
11090 LogPNGChunk(logging,mng_PLTE,data_length);
11092 for (i=0; i < (ssize_t) image->colors; i++)
11094 chunk[4+i*3]=ScaleQuantumToChar(image->colormap[i].red) & 0xff;
11095 chunk[5+i*3]=ScaleQuantumToChar(image->colormap[i].green) & 0xff;
11096 chunk[6+i*3]=ScaleQuantumToChar(image->colormap[i].blue) & 0xff;
11099 (void) WriteBlob(image,data_length+4,chunk);
11100 (void) WriteBlobMSBULong(image,crc32(0,chunk,(uInt) (data_length+4)));
11101 mng_info->have_write_global_plte=MagickTrue;
11107 #if defined(PNG_WRITE_EMPTY_PLTE_SUPPORTED) || \
11108 defined(PNG_MNG_FEATURES_SUPPORTED)
11109 mng_info->equal_palettes=MagickFalse;
11113 if (mng_info->adjoin)
11115 #if defined(PNG_WRITE_EMPTY_PLTE_SUPPORTED) || \
11116 defined(PNG_MNG_FEATURES_SUPPORTED)
11118 If we aren't using a global palette for the entire MNG, check to
11119 see if we can use one for two or more consecutive images.
11121 if (need_local_plte && use_global_plte && !all_images_are_gray)
11123 if (mng_info->IsPalette)
11126 When equal_palettes is true, this image has the same palette
11127 as the previous PseudoClass image
11129 mng_info->have_write_global_plte=mng_info->equal_palettes;
11130 mng_info->equal_palettes=PalettesAreEqual(image,image->next);
11131 if (mng_info->equal_palettes && !mng_info->have_write_global_plte)
11134 Write MNG PLTE chunk
11139 data_length=3*image->colors;
11140 (void) WriteBlobMSBULong(image,data_length);
11141 PNGType(chunk,mng_PLTE);
11142 LogPNGChunk(logging,mng_PLTE,data_length);
11144 for (i=0; i < (ssize_t) image->colors; i++)
11146 chunk[4+i*3]=ScaleQuantumToChar(image->colormap[i].red);
11147 chunk[5+i*3]=ScaleQuantumToChar(image->colormap[i].green);
11148 chunk[6+i*3]=ScaleQuantumToChar(image->colormap[i].blue);
11151 (void) WriteBlob(image,data_length+4,chunk);
11152 (void) WriteBlobMSBULong(image,crc32(0,chunk,
11153 (uInt) (data_length+4)));
11154 mng_info->have_write_global_plte=MagickTrue;
11158 mng_info->have_write_global_plte=MagickFalse;
11169 previous_x=mng_info->page.x;
11170 previous_y=mng_info->page.y;
11177 mng_info->page=image->page;
11178 if ((mng_info->page.x != previous_x) ||
11179 (mng_info->page.y != previous_y))
11181 (void) WriteBlobMSBULong(image,12L); /* data length=12 */
11182 PNGType(chunk,mng_DEFI);
11183 LogPNGChunk(logging,mng_DEFI,12L);
11184 chunk[4]=0; /* object 0 MSB */
11185 chunk[5]=0; /* object 0 LSB */
11186 chunk[6]=0; /* visible */
11187 chunk[7]=0; /* abstract */
11188 PNGLong(chunk+8,(png_uint_32) mng_info->page.x);
11189 PNGLong(chunk+12,(png_uint_32) mng_info->page.y);
11190 (void) WriteBlob(image,16,chunk);
11191 (void) WriteBlobMSBULong(image,crc32(0,chunk,16));
11196 mng_info->write_mng=write_mng;
11198 if ((int) image->dispose >= 3)
11199 mng_info->framing_mode=3;
11201 if (mng_info->need_fram && mng_info->adjoin &&
11202 ((image->delay != mng_info->delay) ||
11203 (mng_info->framing_mode != mng_info->old_framing_mode)))
11205 if (image->delay == mng_info->delay)
11208 Write a MNG FRAM chunk with the new framing mode.
11210 (void) WriteBlobMSBULong(image,1L); /* data length=1 */
11211 PNGType(chunk,mng_FRAM);
11212 LogPNGChunk(logging,mng_FRAM,1L);
11213 chunk[4]=(unsigned char) mng_info->framing_mode;
11214 (void) WriteBlob(image,5,chunk);
11215 (void) WriteBlobMSBULong(image,crc32(0,chunk,5));
11220 Write a MNG FRAM chunk with the delay.
11222 (void) WriteBlobMSBULong(image,10L); /* data length=10 */
11223 PNGType(chunk,mng_FRAM);
11224 LogPNGChunk(logging,mng_FRAM,10L);
11225 chunk[4]=(unsigned char) mng_info->framing_mode;
11226 chunk[5]=0; /* frame name separator (no name) */
11227 chunk[6]=2; /* flag for changing default delay */
11228 chunk[7]=0; /* flag for changing frame timeout */
11229 chunk[8]=0; /* flag for changing frame clipping */
11230 chunk[9]=0; /* flag for changing frame sync_id */
11231 PNGLong(chunk+10,(png_uint_32)
11232 ((mng_info->ticks_per_second*
11233 image->delay)/MagickMax(image->ticks_per_second,1)));
11234 (void) WriteBlob(image,14,chunk);
11235 (void) WriteBlobMSBULong(image,crc32(0,chunk,14));
11236 mng_info->delay=(png_uint_32) image->delay;
11238 mng_info->old_framing_mode=mng_info->framing_mode;
11241 #if defined(JNG_SUPPORTED)
11242 if (image_info->compression == JPEGCompression)
11247 if (logging != MagickFalse)
11248 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11249 " Writing JNG object.");
11250 /* To do: specify the desired alpha compression method. */
11251 write_info=CloneImageInfo(image_info);
11252 write_info->compression=UndefinedCompression;
11253 status=WriteOneJNGImage(mng_info,write_info,image);
11254 write_info=DestroyImageInfo(write_info);
11259 if (logging != MagickFalse)
11260 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11261 " Writing PNG object.");
11263 mng_info->need_blob = MagickFalse;
11265 /* We don't want any ancillary chunks written */
11266 mng_info->ping_exclude_bKGD=MagickTrue;
11267 mng_info->ping_exclude_cHRM=MagickTrue;
11268 mng_info->ping_exclude_EXIF=MagickTrue;
11269 mng_info->ping_exclude_gAMA=MagickTrue;
11270 mng_info->ping_exclude_cHRM=MagickTrue;
11271 mng_info->ping_exclude_iCCP=MagickTrue;
11272 /* mng_info->ping_exclude_iTXt=MagickTrue; */
11273 mng_info->ping_exclude_oFFs=MagickTrue;
11274 mng_info->ping_exclude_pHYs=MagickTrue;
11275 mng_info->ping_exclude_sRGB=MagickTrue;
11276 mng_info->ping_exclude_tEXt=MagickTrue;
11277 mng_info->ping_exclude_tRNS=MagickTrue;
11278 mng_info->ping_exclude_vpAg=MagickTrue;
11279 mng_info->ping_exclude_zCCP=MagickTrue;
11280 mng_info->ping_exclude_zTXt=MagickTrue;
11282 status=WriteOnePNGImage(mng_info,image_info,image);
11285 if (status == MagickFalse)
11287 MngInfoFreeStruct(mng_info,&have_mng_structure);
11288 (void) CloseBlob(image);
11289 return(MagickFalse);
11291 (void) CatchImageException(image);
11292 if (GetNextImageInList(image) == (Image *) NULL)
11294 image=SyncNextImageInList(image);
11295 status=SetImageProgress(image,SaveImagesTag,scene++,
11296 GetImageListLength(image));
11298 if (status == MagickFalse)
11301 } while (mng_info->adjoin);
11305 while (GetPreviousImageInList(image) != (Image *) NULL)
11306 image=GetPreviousImageInList(image);
11308 Write the MEND chunk.
11310 (void) WriteBlobMSBULong(image,0x00000000L);
11311 PNGType(chunk,mng_MEND);
11312 LogPNGChunk(logging,mng_MEND,0L);
11313 (void) WriteBlob(image,4,chunk);
11314 (void) WriteBlobMSBULong(image,crc32(0,chunk,4));
11317 Relinquish resources.
11319 (void) CloseBlob(image);
11320 MngInfoFreeStruct(mng_info,&have_mng_structure);
11322 if (logging != MagickFalse)
11323 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"exit WriteMNGImage()");
11325 return(MagickTrue);
11327 #else /* PNG_LIBPNG_VER > 10011 */
11329 static MagickBooleanType WritePNGImage(const ImageInfo *image_info,Image *image)
11332 printf("Your PNG library is too old: You have libpng-%s\n",
11333 PNG_LIBPNG_VER_STRING);
11335 ThrowBinaryException(CoderError,"PNG library is too old",
11336 image_info->filename);
11339 static MagickBooleanType WriteMNGImage(const ImageInfo *image_info,Image *image)
11341 return(WritePNGImage(image_info,image));
11343 #endif /* PNG_LIBPNG_VER > 10011 */