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 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1449 " length: %lu",(unsigned long) length);
1451 while (*sp != ' ' && *sp != '\n')
1454 /* allocate space */
1457 (void) ThrowMagickException(&image->exception,GetMagickModule(),
1458 CoderWarning,"UnableToCopyProfile","`%s'","invalid profile length");
1459 return(MagickFalse);
1462 profile=AcquireStringInfo(length);
1464 if (profile == (StringInfo *) NULL)
1466 (void) ThrowMagickException(&image->exception,GetMagickModule(),
1467 ResourceLimitError,"MemoryAllocationFailed","`%s'",
1468 "unable to copy profile");
1469 return(MagickFalse);
1472 /* copy profile, skipping white space and column 1 "=" signs */
1473 dp=GetStringInfoDatum(profile);
1476 for (i=0; i < (ssize_t) nibbles; i++)
1478 while (*sp < '0' || (*sp > '9' && *sp < 'a') || *sp > 'f')
1482 (void) ThrowMagickException(&image->exception,GetMagickModule(),
1483 CoderWarning,"UnableToCopyProfile","`%s'","ran out of data");
1484 profile=DestroyStringInfo(profile);
1485 return(MagickFalse);
1491 *dp=(unsigned char) (16*unhex[(int) *sp++]);
1494 (*dp++)+=unhex[(int) *sp++];
1497 We have already read "Raw profile type.
1499 (void) SetImageProfile(image,&text[ii].key[17],profile);
1500 profile=DestroyStringInfo(profile);
1502 if (image_info->verbose)
1503 (void) printf(" Found a generic profile, type %s\n",&text[ii].key[17]);
1508 #if defined(PNG_UNKNOWN_CHUNKS_SUPPORTED)
1509 static int read_vpag_chunk_callback(png_struct *ping, png_unknown_chunkp chunk)
1515 /* The unknown chunk structure contains the chunk data:
1520 Note that libpng has already taken care of the CRC handling.
1524 if (chunk->name[0] != 118 || chunk->name[1] != 112 ||
1525 chunk->name[2] != 65 ||chunk-> name[3] != 103)
1526 return(0); /* Did not recognize */
1528 /* recognized vpAg */
1530 if (chunk->size != 9)
1531 return(-1); /* Error return */
1533 if (chunk->data[8] != 0)
1534 return(0); /* ImageMagick requires pixel units */
1536 image=(Image *) png_get_user_chunk_ptr(ping);
1538 image->page.width=(size_t) ((chunk->data[0] << 24) |
1539 (chunk->data[1] << 16) | (chunk->data[2] << 8) | chunk->data[3]);
1541 image->page.height=(size_t) ((chunk->data[4] << 24) |
1542 (chunk->data[5] << 16) | (chunk->data[6] << 8) | chunk->data[7]);
1544 /* Return one of the following: */
1545 /* return(-n); chunk had an error */
1546 /* return(0); did not recognize */
1547 /* return(n); success */
1555 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1559 % R e a d O n e P N G I m a g e %
1563 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1565 % ReadOnePNGImage() reads a Portable Network Graphics (PNG) image file
1566 % (minus the 8-byte signature) and returns it. It allocates the memory
1567 % necessary for the new Image structure and returns a pointer to the new
1570 % The format of the ReadOnePNGImage method is:
1572 % Image *ReadOnePNGImage(MngInfo *mng_info, const ImageInfo *image_info,
1573 % ExceptionInfo *exception)
1575 % A description of each parameter follows:
1577 % o mng_info: Specifies a pointer to a MngInfo structure.
1579 % o image_info: the image info.
1581 % o exception: return any errors or warnings in this structure.
1584 static Image *ReadOnePNGImage(MngInfo *mng_info,
1585 const ImageInfo *image_info, ExceptionInfo *exception)
1587 /* Read one PNG image */
1598 ping_interlace_method,
1599 ping_compression_method,
1641 register unsigned char
1644 register IndexPacket
1651 register PixelPacket
1658 #if defined(PNG_UNKNOWN_CHUNKS_SUPPORTED)
1659 png_byte unused_chunks[]=
1661 104, 73, 83, 84, (png_byte) '\0', /* hIST */
1662 105, 84, 88, 116, (png_byte) '\0', /* iTXt */
1663 112, 67, 65, 76, (png_byte) '\0', /* pCAL */
1664 115, 67, 65, 76, (png_byte) '\0', /* sCAL */
1665 115, 80, 76, 84, (png_byte) '\0', /* sPLT */
1666 116, 73, 77, 69, (png_byte) '\0', /* tIME */
1670 logging=LogMagickEvent(CoderEvent,GetMagickModule(),
1671 " enter ReadOnePNGImage()");
1673 #if defined(PNG_SETJMP_NOT_THREAD_SAFE)
1674 LockSemaphoreInfo(ping_semaphore);
1677 #if (PNG_LIBPNG_VER < 10200)
1678 if (image_info->verbose)
1679 printf("Your PNG library (libpng-%s) is rather old.\n",
1680 PNG_LIBPNG_VER_STRING);
1683 #if (PNG_LIBPNG_VER >= 10400)
1684 # ifndef PNG_TRANSFORM_GRAY_TO_RGB /* Added at libpng-1.4.0beta67 */
1685 if (image_info->verbose)
1687 printf("Your PNG library (libpng-%s) is an old beta version.\n",
1688 PNG_LIBPNG_VER_STRING);
1689 printf("Please update it.\n");
1695 quantum_info = (QuantumInfo *) NULL;
1696 image=mng_info->image;
1698 if (logging != MagickFalse)
1699 (void)LogMagickEvent(CoderEvent,GetMagickModule(),
1700 " image->matte=%d",(int) image->matte);
1702 /* Set to an out-of-range color unless tRNS chunk is present */
1703 transparent_color.red=65537;
1704 transparent_color.green=65537;
1705 transparent_color.blue=65537;
1706 transparent_color.opacity=65537;
1709 Allocate the PNG structures
1711 #ifdef PNG_USER_MEM_SUPPORTED
1712 ping=png_create_read_struct_2(PNG_LIBPNG_VER_STRING, image,
1713 MagickPNGErrorHandler,MagickPNGWarningHandler, NULL,
1714 (png_malloc_ptr) Magick_png_malloc,(png_free_ptr) Magick_png_free);
1716 ping=png_create_read_struct(PNG_LIBPNG_VER_STRING,image,
1717 MagickPNGErrorHandler,MagickPNGWarningHandler);
1719 if (ping == (png_struct *) NULL)
1720 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1722 ping_info=png_create_info_struct(ping);
1724 if (ping_info == (png_info *) NULL)
1726 png_destroy_read_struct(&ping,(png_info **) NULL,(png_info **) NULL);
1727 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1730 end_info=png_create_info_struct(ping);
1732 if (end_info == (png_info *) NULL)
1734 png_destroy_read_struct(&ping,&ping_info,(png_info **) NULL);
1735 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1738 ping_pixels=(unsigned char *) NULL;
1740 if (setjmp(png_jmpbuf(ping)))
1743 PNG image is corrupt.
1745 png_destroy_read_struct(&ping,&ping_info,&end_info);
1746 #if defined(PNG_SETJMP_NOT_THREAD_SAFE)
1747 UnlockSemaphoreInfo(ping_semaphore);
1749 if (logging != MagickFalse)
1750 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1751 " exit ReadOnePNGImage() with error.");
1753 if (image != (Image *) NULL)
1755 InheritException(exception,&image->exception);
1759 return(GetFirstImageInList(image));
1762 Prepare PNG for reading.
1765 mng_info->image_found++;
1766 png_set_sig_bytes(ping,8);
1768 if (LocaleCompare(image_info->magick,"MNG") == 0)
1770 #if defined(PNG_MNG_FEATURES_SUPPORTED)
1771 (void) png_permit_mng_features(ping,PNG_ALL_MNG_FEATURES);
1772 png_set_read_fn(ping,image,png_get_data);
1774 #if defined(PNG_READ_EMPTY_PLTE_SUPPORTED)
1775 png_permit_empty_plte(ping,MagickTrue);
1776 png_set_read_fn(ping,image,png_get_data);
1778 mng_info->image=image;
1779 mng_info->bytes_in_read_buffer=0;
1780 mng_info->found_empty_plte=MagickFalse;
1781 mng_info->have_saved_bkgd_index=MagickFalse;
1782 png_set_read_fn(ping,mng_info,mng_get_data);
1788 png_set_read_fn(ping,image,png_get_data);
1790 #if defined(PNG_UNKNOWN_CHUNKS_SUPPORTED)
1791 /* Ignore unused chunks and all unknown chunks except for vpAg */
1792 png_set_keep_unknown_chunks(ping, 1, NULL, 0);
1793 png_set_keep_unknown_chunks(ping, 2, mng_vpAg, 1);
1794 png_set_keep_unknown_chunks(ping, 1, unused_chunks,
1795 (int)sizeof(unused_chunks)/5);
1796 /* Callback for other unknown chunks */
1797 png_set_read_user_chunk_fn(ping, image, read_vpag_chunk_callback);
1800 #if (PNG_LIBPNG_VER < 10400)
1801 # if defined(PNG_USE_PNGGCCRD) && defined(PNG_ASSEMBLER_CODE_SUPPORTED) && \
1802 (PNG_LIBPNG_VER >= 10200) && (PNG_LIBPNG_VER < 10220) && defined(__i386__)
1803 /* Disable thread-unsafe features of pnggccrd */
1804 if (png_access_version_number() >= 10200)
1806 png_uint_32 mmx_disable_mask=0;
1807 png_uint_32 asm_flags;
1809 mmx_disable_mask |= ( PNG_ASM_FLAG_MMX_READ_COMBINE_ROW \
1810 | PNG_ASM_FLAG_MMX_READ_FILTER_SUB \
1811 | PNG_ASM_FLAG_MMX_READ_FILTER_AVG \
1812 | PNG_ASM_FLAG_MMX_READ_FILTER_PAETH );
1813 asm_flags=png_get_asm_flags(ping);
1814 png_set_asm_flags(ping, asm_flags & ~mmx_disable_mask);
1819 png_read_info(ping,ping_info);
1821 png_get_IHDR(ping,ping_info,&ping_width,&ping_height,
1822 &ping_bit_depth,&ping_color_type,
1823 &ping_interlace_method,&ping_compression_method,
1824 &ping_filter_method);
1826 (void) png_get_tRNS(ping, ping_info, &ping_trans_alpha, &ping_num_trans,
1829 (void) png_get_bKGD(ping, ping_info, &ping_background);
1831 if (ping_bit_depth < 8)
1833 if (((int) ping_color_type == PNG_COLOR_TYPE_PALETTE))
1835 png_set_packing(ping);
1840 image->depth=ping_bit_depth;
1841 image->depth=GetImageQuantumDepth(image,MagickFalse);
1842 image->interlace=ping_interlace_method != 0 ? PNGInterlace : NoInterlace;
1843 if (logging != MagickFalse)
1845 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1846 " PNG width: %.20g, height: %.20g",
1847 (double) ping_width, (double) ping_height);
1849 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1850 " PNG color_type: %d, bit_depth: %d",
1851 ping_color_type, ping_bit_depth);
1853 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1854 " PNG compression_method: %d",
1855 ping_compression_method);
1857 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1858 " PNG interlace_method: %d, filter_method: %d",
1859 ping_interlace_method,ping_filter_method);
1862 #ifdef PNG_READ_iCCP_SUPPORTED
1863 if (png_get_valid(ping,ping_info,PNG_INFO_iCCP))
1868 #if (PNG_LIBPNG_VER < 10500)
1882 (void) png_get_iCCP(ping,ping_info,&name,(int *) &compression,&info,
1885 if (profile_length != 0)
1890 if (logging != MagickFalse)
1891 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1892 " Reading PNG iCCP chunk.");
1893 profile=AcquireStringInfo(profile_length);
1894 SetStringInfoDatum(profile,(const unsigned char *) info);
1895 (void) SetImageProfile(image,"icc",profile);
1896 profile=DestroyStringInfo(profile);
1900 #if defined(PNG_READ_sRGB_SUPPORTED)
1905 if (mng_info->have_global_srgb)
1906 image->rendering_intent=Magick_RenderingIntent_from_PNG_RenderingIntent
1907 (mng_info->global_srgb_intent);
1909 if (png_get_sRGB(ping,ping_info,&intent))
1911 image->rendering_intent=Magick_RenderingIntent_from_PNG_RenderingIntent
1914 if (logging != MagickFalse)
1915 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1916 " Reading PNG sRGB chunk: rendering_intent: %d",intent);
1924 if (!png_get_gAMA(ping,ping_info,&file_gamma))
1925 if (mng_info->have_global_gama)
1926 png_set_gAMA(ping,ping_info,mng_info->global_gamma);
1928 if (png_get_gAMA(ping,ping_info,&file_gamma))
1930 image->gamma=(float) file_gamma;
1931 if (logging != MagickFalse)
1932 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1933 " Reading PNG gAMA chunk: gamma: %f",file_gamma);
1936 if (!png_get_valid(ping,ping_info,PNG_INFO_cHRM))
1938 if (mng_info->have_global_chrm != MagickFalse)
1940 (void) png_set_cHRM(ping,ping_info,
1941 mng_info->global_chrm.white_point.x,
1942 mng_info->global_chrm.white_point.y,
1943 mng_info->global_chrm.red_primary.x,
1944 mng_info->global_chrm.red_primary.y,
1945 mng_info->global_chrm.green_primary.x,
1946 mng_info->global_chrm.green_primary.y,
1947 mng_info->global_chrm.blue_primary.x,
1948 mng_info->global_chrm.blue_primary.y);
1952 if (png_get_valid(ping,ping_info,PNG_INFO_cHRM))
1954 (void) png_get_cHRM(ping,ping_info,
1955 &image->chromaticity.white_point.x,
1956 &image->chromaticity.white_point.y,
1957 &image->chromaticity.red_primary.x,
1958 &image->chromaticity.red_primary.y,
1959 &image->chromaticity.green_primary.x,
1960 &image->chromaticity.green_primary.y,
1961 &image->chromaticity.blue_primary.x,
1962 &image->chromaticity.blue_primary.y);
1964 if (logging != MagickFalse)
1965 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1966 " Reading PNG cHRM chunk.");
1969 if (image->rendering_intent != UndefinedIntent)
1971 png_set_sRGB(ping,ping_info,
1972 Magick_RenderingIntent_to_PNG_RenderingIntent
1973 (image->rendering_intent));
1974 png_set_gAMA(ping,ping_info,0.45455f);
1975 png_set_cHRM(ping,ping_info,
1976 0.6400f, 0.3300f, 0.3000f, 0.6000f,
1977 0.1500f, 0.0600f, 0.3127f, 0.3290f);
1979 #if defined(PNG_oFFs_SUPPORTED)
1980 if (png_get_valid(ping,ping_info,PNG_INFO_oFFs))
1982 image->page.x=(ssize_t) png_get_x_offset_pixels(ping, ping_info);
1983 image->page.y=(ssize_t) png_get_y_offset_pixels(ping, ping_info);
1985 if (logging != MagickFalse)
1986 if (image->page.x || image->page.y)
1987 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1988 " Reading PNG oFFs chunk: x: %.20g, y: %.20g.",(double)
1989 image->page.x,(double) image->page.y);
1992 #if defined(PNG_pHYs_SUPPORTED)
1993 if (!png_get_valid(ping,ping_info,PNG_INFO_pHYs))
1995 if (mng_info->have_global_phys)
1997 png_set_pHYs(ping,ping_info,
1998 mng_info->global_x_pixels_per_unit,
1999 mng_info->global_y_pixels_per_unit,
2000 mng_info->global_phys_unit_type);
2004 if (png_get_valid(ping,ping_info,PNG_INFO_pHYs))
2014 Set image resolution.
2016 (void) png_get_pHYs(ping,ping_info,&x_resolution,&y_resolution,
2018 image->x_resolution=(double) x_resolution;
2019 image->y_resolution=(double) y_resolution;
2021 if (unit_type == PNG_RESOLUTION_METER)
2023 image->units=PixelsPerCentimeterResolution;
2024 image->x_resolution=(double) x_resolution/100.0;
2025 image->y_resolution=(double) y_resolution/100.0;
2028 if (logging != MagickFalse)
2029 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2030 " Reading PNG pHYs chunk: xres: %.20g, yres: %.20g, units: %d.",
2031 (double) x_resolution,(double) y_resolution,unit_type);
2034 if (png_get_valid(ping,ping_info,PNG_INFO_PLTE))
2042 (void) png_get_PLTE(ping,ping_info,&palette,&number_colors);
2044 if ((number_colors == 0) &&
2045 ((int) ping_color_type == PNG_COLOR_TYPE_PALETTE))
2047 if (mng_info->global_plte_length)
2049 png_set_PLTE(ping,ping_info,mng_info->global_plte,
2050 (int) mng_info->global_plte_length);
2052 if (!png_get_valid(ping,ping_info,PNG_INFO_tRNS))
2053 if (mng_info->global_trns_length)
2055 if (mng_info->global_trns_length >
2056 mng_info->global_plte_length)
2057 (void) ThrowMagickException(&image->exception,
2058 GetMagickModule(),CoderError,
2059 "global tRNS has more entries than global PLTE",
2060 "`%s'",image_info->filename);
2061 png_set_tRNS(ping,ping_info,mng_info->global_trns,
2062 (int) mng_info->global_trns_length,NULL);
2064 #if defined(PNG_READ_bKGD_SUPPORTED)
2066 #ifndef PNG_READ_EMPTY_PLTE_SUPPORTED
2067 mng_info->have_saved_bkgd_index ||
2069 png_get_valid(ping,ping_info,PNG_INFO_bKGD))
2074 #ifndef PNG_READ_EMPTY_PLTE_SUPPORTED
2075 if (mng_info->have_saved_bkgd_index)
2076 background.index=mng_info->saved_bkgd_index;
2078 if (png_get_valid(ping, ping_info, PNG_INFO_bKGD))
2079 background.index=ping_background->index;
2081 background.red=(png_uint_16)
2082 mng_info->global_plte[background.index].red;
2084 background.green=(png_uint_16)
2085 mng_info->global_plte[background.index].green;
2087 background.blue=(png_uint_16)
2088 mng_info->global_plte[background.index].blue;
2090 png_set_bKGD(ping,ping_info,&background);
2095 (void) ThrowMagickException(&image->exception,GetMagickModule(),
2096 CoderError,"No global PLTE in file","`%s'",
2097 image_info->filename);
2101 #if defined(PNG_READ_bKGD_SUPPORTED)
2102 if (mng_info->have_global_bkgd &&
2103 (!png_get_valid(ping,ping_info,PNG_INFO_bKGD)))
2104 image->background_color=mng_info->mng_global_bkgd;
2106 if (png_get_valid(ping,ping_info,PNG_INFO_bKGD))
2109 Set image background color.
2111 if (logging != MagickFalse)
2112 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2113 " Reading PNG bKGD chunk.");
2115 if (ping_bit_depth == MAGICKCORE_QUANTUM_DEPTH)
2117 image->background_color.red=ping_background->red;
2118 image->background_color.green=ping_background->green;
2119 image->background_color.blue=ping_background->blue;
2122 else /* Scale background components to 16-bit */
2127 if (logging != MagickFalse)
2128 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2129 " raw ping_background=(%d,%d,%d).",ping_background->red,
2130 ping_background->green,ping_background->blue);
2134 if (ping_bit_depth == 1)
2137 else if (ping_bit_depth == 2)
2140 else if (ping_bit_depth == 4)
2143 if (ping_bit_depth <= 8)
2146 ping_background->red *= bkgd_scale;
2147 ping_background->green *= bkgd_scale;
2148 ping_background->blue *= bkgd_scale;
2150 if (logging != MagickFalse)
2152 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2153 " bkgd_scale=%d.",bkgd_scale);
2155 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2156 " ping_background=(%d,%d,%d).",ping_background->red,
2157 ping_background->green,ping_background->blue);
2160 image->background_color.red=
2161 ScaleShortToQuantum(ping_background->red);
2163 image->background_color.green=
2164 ScaleShortToQuantum(ping_background->green);
2166 image->background_color.blue=
2167 ScaleShortToQuantum(ping_background->blue);
2169 image->background_color.opacity=OpaqueOpacity;
2171 if (logging != MagickFalse)
2172 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2173 " image->background_color=(%.20g,%.20g,%.20g).",
2174 (double) image->background_color.red,
2175 (double) image->background_color.green,
2176 (double) image->background_color.blue);
2181 if (png_get_valid(ping,ping_info,PNG_INFO_tRNS))
2184 Image has a tRNS chunk.
2192 if (logging != MagickFalse)
2193 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2194 " Reading PNG tRNS chunk.");
2196 max_sample = (int) ((one << ping_bit_depth) - 1);
2198 if ((ping_color_type == PNG_COLOR_TYPE_GRAY &&
2199 (int)ping_trans_color->gray > max_sample) ||
2200 (ping_color_type == PNG_COLOR_TYPE_RGB &&
2201 ((int)ping_trans_color->red > max_sample ||
2202 (int)ping_trans_color->green > max_sample ||
2203 (int)ping_trans_color->blue > max_sample)))
2205 if (logging != MagickFalse)
2206 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2207 " Ignoring PNG tRNS chunk with out-of-range sample.");
2208 png_free_data(ping, ping_info, PNG_FREE_TRNS, 0);
2209 png_set_invalid(ping,ping_info,PNG_INFO_tRNS);
2210 image->matte=MagickFalse;
2217 scale_to_short = 65535L/((1UL << ping_bit_depth)-1);
2219 /* Scale transparent_color to short */
2220 transparent_color.red= scale_to_short*ping_trans_color->red;
2221 transparent_color.green= scale_to_short*ping_trans_color->green;
2222 transparent_color.blue= scale_to_short*ping_trans_color->blue;
2223 transparent_color.opacity= scale_to_short*ping_trans_color->gray;
2225 if (ping_color_type == PNG_COLOR_TYPE_GRAY)
2227 if (logging != MagickFalse)
2229 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2230 " Raw tRNS graylevel is %d.",ping_trans_color->gray);
2232 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2233 " scaled graylevel is %d.",transparent_color.opacity);
2235 transparent_color.red=transparent_color.opacity;
2236 transparent_color.green=transparent_color.opacity;
2237 transparent_color.blue=transparent_color.opacity;
2241 #if defined(PNG_READ_sBIT_SUPPORTED)
2242 if (mng_info->have_global_sbit)
2244 if (!png_get_valid(ping,ping_info,PNG_INFO_sBIT))
2245 png_set_sBIT(ping,ping_info,&mng_info->global_sbit);
2248 num_passes=png_set_interlace_handling(ping);
2250 png_read_update_info(ping,ping_info);
2252 ping_rowbytes=png_get_rowbytes(ping,ping_info);
2255 Initialize image structure.
2257 mng_info->image_box.left=0;
2258 mng_info->image_box.right=(ssize_t) ping_width;
2259 mng_info->image_box.top=0;
2260 mng_info->image_box.bottom=(ssize_t) ping_height;
2261 if (mng_info->mng_type == 0)
2263 mng_info->mng_width=ping_width;
2264 mng_info->mng_height=ping_height;
2265 mng_info->frame=mng_info->image_box;
2266 mng_info->clip=mng_info->image_box;
2271 image->page.y=mng_info->y_off[mng_info->object_id];
2274 image->compression=ZipCompression;
2275 image->columns=ping_width;
2276 image->rows=ping_height;
2277 if (((int) ping_color_type == PNG_COLOR_TYPE_PALETTE) ||
2278 ((int) ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA) ||
2279 ((int) ping_color_type == PNG_COLOR_TYPE_GRAY))
2284 image->storage_class=PseudoClass;
2286 image->colors=one << ping_bit_depth;
2287 #if (MAGICKCORE_QUANTUM_DEPTH == 8)
2288 if (image->colors > 256)
2291 if (image->colors > 65536L)
2292 image->colors=65536L;
2294 if ((int) ping_color_type == PNG_COLOR_TYPE_PALETTE)
2302 (void) png_get_PLTE(ping,ping_info,&palette,&number_colors);
2303 image->colors=(size_t) number_colors;
2305 if (logging != MagickFalse)
2306 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2307 " Reading PNG PLTE chunk: number_colors: %d.",number_colors);
2311 if (image->storage_class == PseudoClass)
2314 Initialize image colormap.
2316 if (AcquireImageColormap(image,image->colors) == MagickFalse)
2317 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
2319 if ((int) ping_color_type == PNG_COLOR_TYPE_PALETTE)
2327 (void) png_get_PLTE(ping,ping_info,&palette,&number_colors);
2329 for (i=0; i < (ssize_t) image->colors; i++)
2331 image->colormap[i].red=ScaleCharToQuantum(palette[i].red);
2332 image->colormap[i].green=ScaleCharToQuantum(palette[i].green);
2333 image->colormap[i].blue=ScaleCharToQuantum(palette[i].blue);
2342 scale=(QuantumRange/((1UL << ping_bit_depth)-1));
2347 for (i=0; i < (ssize_t) image->colors; i++)
2349 image->colormap[i].red=(Quantum) (i*scale);
2350 image->colormap[i].green=(Quantum) (i*scale);
2351 image->colormap[i].blue=(Quantum) (i*scale);
2356 Read image scanlines.
2358 if (image->delay != 0)
2359 mng_info->scenes_found++;
2361 if ((mng_info->mng_type == 0 && (image->ping != MagickFalse)) || (
2362 (image_info->number_scenes != 0) && (mng_info->scenes_found > (ssize_t)
2363 (image_info->first_scene+image_info->number_scenes))))
2365 if (logging != MagickFalse)
2366 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2367 " Skipping PNG image data for scene %.20g",(double)
2368 mng_info->scenes_found-1);
2369 png_destroy_read_struct(&ping,&ping_info,&end_info);
2370 #if defined(PNG_SETJMP_NOT_THREAD_SAFE)
2371 UnlockSemaphoreInfo(ping_semaphore);
2373 if (logging != MagickFalse)
2374 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2375 " exit ReadOnePNGImage().");
2380 if (logging != MagickFalse)
2381 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2382 " Reading PNG IDAT chunk(s)");
2385 ping_pixels=(unsigned char *) AcquireQuantumMemory(image->rows,
2386 ping_rowbytes*sizeof(*ping_pixels));
2389 ping_pixels=(unsigned char *) AcquireQuantumMemory(ping_rowbytes,
2390 sizeof(*ping_pixels));
2392 if (ping_pixels == (unsigned char *) NULL)
2393 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
2395 if (logging != MagickFalse)
2396 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2397 " Converting PNG pixels to pixel packets");
2399 Convert PNG pixels to pixel packets.
2401 if (setjmp(png_jmpbuf(ping)))
2404 PNG image is corrupt.
2406 png_destroy_read_struct(&ping,&ping_info,&end_info);
2407 #if defined(PNG_SETJMP_NOT_THREAD_SAFE)
2408 UnlockSemaphoreInfo(ping_semaphore);
2410 if (quantum_info != (QuantumInfo *) NULL)
2411 quantum_info = DestroyQuantumInfo(quantum_info);
2413 if (ping_pixels != (unsigned char *) NULL)
2414 ping_pixels=(unsigned char *) RelinquishMagickMemory(ping_pixels);
2416 if (logging != MagickFalse)
2417 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2418 " exit ReadOnePNGImage() with error.");
2420 if (image != (Image *) NULL)
2422 InheritException(exception,&image->exception);
2426 return(GetFirstImageInList(image));
2429 quantum_info=AcquireQuantumInfo(image_info,image);
2431 if (quantum_info == (QuantumInfo *) NULL)
2432 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
2437 found_transparent_pixel;
2439 found_transparent_pixel=MagickFalse;
2441 if (image->storage_class == DirectClass)
2443 for (pass=0; pass < num_passes; pass++)
2446 Convert image to DirectClass pixel packets.
2448 #if (MAGICKCORE_QUANTUM_DEPTH == 8)
2452 depth=(ssize_t) ping_bit_depth;
2454 image->matte=(((int) ping_color_type == PNG_COLOR_TYPE_RGB_ALPHA) ||
2455 ((int) ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA) ||
2456 (png_get_valid(ping,ping_info,PNG_INFO_tRNS))) ?
2457 MagickTrue : MagickFalse;
2459 for (y=0; y < (ssize_t) image->rows; y++)
2462 row_offset=ping_rowbytes*y;
2467 png_read_row(ping,ping_pixels+row_offset,NULL);
2468 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
2470 if (q == (PixelPacket *) NULL)
2473 #if (0 && (MAGICKCORE_QUANTUM_DEPTH == 8) && !defined(MAGICKCORE_HDRI_SUPPORT))
2474 /* code deleted from version 6.6.6-8 */
2475 #else /* (MAGICKCORE_QUANTUM_DEPTH != 8) */
2477 if ((int) ping_color_type == PNG_COLOR_TYPE_GRAY)
2478 (void) ImportQuantumPixels(image,(CacheView *) NULL,quantum_info,
2479 GrayQuantum,ping_pixels+row_offset,exception);
2481 else if ((int) ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
2482 (void) ImportQuantumPixels(image,(CacheView *) NULL,quantum_info,
2483 GrayAlphaQuantum,ping_pixels+row_offset,exception);
2485 else if ((int) ping_color_type == PNG_COLOR_TYPE_RGB_ALPHA)
2486 (void) ImportQuantumPixels(image,(CacheView *) NULL,quantum_info,
2487 RGBAQuantum,ping_pixels+row_offset,exception);
2489 else if ((int) ping_color_type == PNG_COLOR_TYPE_PALETTE)
2490 (void) ImportQuantumPixels(image,(CacheView *) NULL,quantum_info,
2491 IndexQuantum,ping_pixels+row_offset,exception);
2493 else /* ping_color_type == PNG_COLOR_TYPE_RGB */
2494 (void) ImportQuantumPixels(image,(CacheView *) NULL,quantum_info,
2495 RGBQuantum,ping_pixels+row_offset,exception);
2497 if (found_transparent_pixel == MagickFalse)
2499 /* Is there a transparent pixel in the row? */
2500 if (y== 0 && logging != MagickFalse)
2501 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2502 " Looking for cheap transparent pixel");
2504 for (x=(ssize_t) image->columns-1; x >= 0; x--)
2506 if ((ping_color_type == PNG_COLOR_TYPE_RGBA ||
2507 ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA) &&
2508 (q->opacity != OpaqueOpacity))
2510 if (logging != MagickFalse)
2511 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2514 found_transparent_pixel = MagickTrue;
2517 if ((ping_color_type == PNG_COLOR_TYPE_RGB ||
2518 ping_color_type == PNG_COLOR_TYPE_GRAY) &&
2519 (ScaleQuantumToShort(q->red) == transparent_color.red &&
2520 ScaleQuantumToShort(q->green) == transparent_color.green &&
2521 ScaleQuantumToShort(q->blue) == transparent_color.blue))
2523 if (logging != MagickFalse)
2524 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2526 found_transparent_pixel = MagickTrue;
2533 if ((image->previous == (Image *) NULL) && (num_passes == 1))
2535 status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
2538 if (status == MagickFalse)
2541 if (SyncAuthenticPixels(image,exception) == MagickFalse)
2545 if ((image->previous == (Image *) NULL) && (num_passes != 1))
2547 status=SetImageProgress(image,LoadImageTag,pass,num_passes);
2548 if (status == MagickFalse)
2554 else /* image->storage_class != DirectClass */
2556 for (pass=0; pass < num_passes; pass++)
2565 Convert grayscale image to PseudoClass pixel packets.
2567 image->matte=ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA ?
2568 MagickTrue : MagickFalse;
2570 quantum_scanline=(Quantum *) AcquireQuantumMemory(image->columns,
2571 (image->matte ? 2 : 1)*sizeof(*quantum_scanline));
2573 if (quantum_scanline == (Quantum *) NULL)
2574 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
2576 for (y=0; y < (ssize_t) image->rows; y++)
2579 row_offset=ping_rowbytes*y;
2584 png_read_row(ping,ping_pixels+row_offset,NULL);
2585 q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
2587 if (q == (PixelPacket *) NULL)
2590 indexes=GetAuthenticIndexQueue(image);
2591 p=ping_pixels+row_offset;
2594 switch (ping_bit_depth)
2601 for (x=(ssize_t) image->columns-7; x > 0; x-=8)
2603 for (bit=7; bit >= 0; bit--)
2604 *r++=(Quantum) ((*p) & (0x01 << bit) ? 0x01 : 0x00);
2608 if ((image->columns % 8) != 0)
2610 for (bit=7; bit >= (ssize_t) (8-(image->columns % 8)); bit--)
2611 *r++=(Quantum) ((*p) & (0x01 << bit) ? 0x01 : 0x00);
2619 for (x=(ssize_t) image->columns-3; x > 0; x-=4)
2621 *r++=(*p >> 6) & 0x03;
2622 *r++=(*p >> 4) & 0x03;
2623 *r++=(*p >> 2) & 0x03;
2627 if ((image->columns % 4) != 0)
2629 for (i=3; i >= (ssize_t) (4-(image->columns % 4)); i--)
2630 *r++=(Quantum) ((*p >> (i*2)) & 0x03);
2638 for (x=(ssize_t) image->columns-1; x > 0; x-=2)
2640 *r++=(*p >> 4) & 0x0f;
2644 if ((image->columns % 2) != 0)
2645 *r++=(*p++ >> 4) & 0x0f;
2652 if (ping_color_type == 4)
2653 for (x=(ssize_t) image->columns-1; x >= 0; x--)
2656 /* In image.h, OpaqueOpacity is 0
2657 * TransparentOpacity is QuantumRange
2658 * In a PNG datastream, Opaque is QuantumRange
2659 * and Transparent is 0.
2661 q->opacity=ScaleCharToQuantum((unsigned char) (255-(*p++)));
2662 if (q->opacity != OpaqueOpacity)
2663 found_transparent_pixel = MagickTrue;
2668 for (x=(ssize_t) image->columns-1; x >= 0; x--)
2676 for (x=(ssize_t) image->columns-1; x >= 0; x--)
2678 #if (MAGICKCORE_QUANTUM_DEPTH == 16)
2682 if (image->colors > 256)
2690 *r=(Quantum) quantum;
2693 if (ping_color_type == 4)
2695 quantum=((*p++) << 8);
2697 q->opacity=(Quantum) (QuantumRange-quantum);
2698 if (q->opacity != OpaqueOpacity)
2699 found_transparent_pixel = MagickTrue;
2703 #if (MAGICKCORE_QUANTUM_DEPTH == 32)
2707 if (image->colors > 256)
2718 if (ping_color_type == 4)
2720 q->opacity=(*p << 8) | *(p+1);
2722 q->opacity=(Quantum) GetAlphaPixelComponent(q);
2723 if (q->opacity != OpaqueOpacity)
2724 found_transparent_pixel = MagickTrue;
2729 #else /* MAGICKCORE_QUANTUM_DEPTH == 8 */
2731 p++; /* strip low byte */
2733 if (ping_color_type == 4)
2735 q->opacity=(Quantum) (QuantumRange-(*p++));
2736 if (q->opacity != OpaqueOpacity)
2737 found_transparent_pixel = MagickTrue;
2752 Transfer image scanline.
2756 for (x=0; x < (ssize_t) image->columns; x++)
2757 indexes[x]=(IndexPacket) (*r++);
2759 if (SyncAuthenticPixels(image,exception) == MagickFalse)
2762 if ((image->previous == (Image *) NULL) && (num_passes == 1))
2764 status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
2767 if (status == MagickFalse)
2772 if ((image->previous == (Image *) NULL) && (num_passes != 1))
2774 status=SetImageProgress(image,LoadImageTag,pass,num_passes);
2776 if (status == MagickFalse)
2780 quantum_scanline=(Quantum *) RelinquishMagickMemory(quantum_scanline);
2783 image->matte=found_transparent_pixel;
2785 if (logging != MagickFalse)
2787 if (found_transparent_pixel != MagickFalse)
2788 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2789 " Found transparent pixel");
2792 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2793 " No transparent pixel was found");
2795 ping_color_type&=0x03;
2800 if (quantum_info != (QuantumInfo *) NULL)
2801 quantum_info=DestroyQuantumInfo(quantum_info);
2803 if (image->storage_class == PseudoClass)
2809 image->matte=MagickFalse;
2810 (void) SyncImage(image);
2814 png_read_end(ping,ping_info);
2816 if (image_info->number_scenes != 0 && mng_info->scenes_found-1 <
2817 (ssize_t) image_info->first_scene && image->delay != 0)
2819 png_destroy_read_struct(&ping,&ping_info,&end_info);
2820 ping_pixels=(unsigned char *) RelinquishMagickMemory(ping_pixels);
2822 (void) SetImageBackgroundColor(image);
2823 #if defined(PNG_SETJMP_NOT_THREAD_SAFE)
2824 UnlockSemaphoreInfo(ping_semaphore);
2826 if (logging != MagickFalse)
2827 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2828 " exit ReadOnePNGImage() early.");
2832 if (png_get_valid(ping,ping_info,PNG_INFO_tRNS))
2838 Image has a transparent background.
2840 storage_class=image->storage_class;
2841 image->matte=MagickTrue;
2843 /* Balfour fix from imagemagick discourse server, 5 Feb 2010 */
2845 if (storage_class == PseudoClass)
2847 if ((int) ping_color_type == PNG_COLOR_TYPE_PALETTE)
2849 for (x=0; x < ping_num_trans; x++)
2851 image->colormap[x].opacity =
2852 ScaleCharToQuantum((unsigned char)(255-ping_trans_alpha[x]));
2856 else if (ping_color_type == PNG_COLOR_TYPE_GRAY)
2858 for (x=0; x < (int) image->colors; x++)
2860 if (ScaleQuantumToShort(image->colormap[x].red) ==
2861 transparent_color.opacity)
2863 image->colormap[x].opacity = (Quantum) TransparentOpacity;
2867 (void) SyncImage(image);
2870 #if 1 /* Should have already been done above, but glennrp problem P10
2875 for (y=0; y < (ssize_t) image->rows; y++)
2877 image->storage_class=storage_class;
2878 q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
2880 if (q == (PixelPacket *) NULL)
2883 indexes=GetAuthenticIndexQueue(image);
2885 /* Caution: on a Q8 build, this does not distinguish between
2886 * 16-bit colors that differ only in the low byte
2888 for (x=(ssize_t) image->columns-1; x >= 0; x--)
2890 if (ScaleQuantumToShort(q->red) == transparent_color.red &&
2891 ScaleQuantumToShort(q->green) == transparent_color.green &&
2892 ScaleQuantumToShort(q->blue) == transparent_color.blue)
2894 q->opacity=(Quantum) TransparentOpacity;
2897 #if 0 /* I have not found a case where this is needed. */
2900 q->opacity=(Quantum) OpaqueOpacity;
2907 if (SyncAuthenticPixels(image,exception) == MagickFalse)
2913 image->storage_class=DirectClass;
2916 if ((ping_color_type == PNG_COLOR_TYPE_GRAY) ||
2917 (ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA))
2918 image->colorspace=GRAYColorspace;
2920 if (png_get_text(ping,ping_info,&text,&num_text) != 0)
2921 for (i=0; i < (ssize_t) num_text; i++)
2923 /* Check for a profile */
2925 if (logging != MagickFalse)
2926 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2927 " Reading PNG text chunk");
2929 if (memcmp(text[i].key, "Raw profile type ",17) == 0)
2930 (void) Magick_png_read_raw_profile(image,image_info,text,(int) i);
2937 length=text[i].text_length;
2938 value=(char *) AcquireQuantumMemory(length+MaxTextExtent,
2940 if (value == (char *) NULL)
2942 (void) ThrowMagickException(&image->exception,GetMagickModule(),
2943 ResourceLimitError,"MemoryAllocationFailed","`%s'",
2948 (void) ConcatenateMagickString(value,text[i].text,length+2);
2949 (void) SetImageProperty(image,text[i].key,value);
2951 if (logging != MagickFalse)
2953 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2954 " length: %lu",(unsigned long) length);
2955 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2956 " Keyword: %s",text[i].key);
2959 value=DestroyString(value);
2963 #ifdef MNG_OBJECT_BUFFERS
2965 Store the object if necessary.
2967 if (object_id && !mng_info->frozen[object_id])
2969 if (mng_info->ob[object_id] == (MngBuffer *) NULL)
2972 create a new object buffer.
2974 mng_info->ob[object_id]=(MngBuffer *)
2975 AcquireMagickMemory(sizeof(MngBuffer));
2977 if (mng_info->ob[object_id] != (MngBuffer *) NULL)
2979 mng_info->ob[object_id]->image=(Image *) NULL;
2980 mng_info->ob[object_id]->reference_count=1;
2984 if ((mng_info->ob[object_id] == (MngBuffer *) NULL) ||
2985 mng_info->ob[object_id]->frozen)
2987 if (mng_info->ob[object_id] == (MngBuffer *) NULL)
2988 (void) ThrowMagickException(&image->exception,GetMagickModule(),
2989 ResourceLimitError,"MemoryAllocationFailed","`%s'",
2992 if (mng_info->ob[object_id]->frozen)
2993 (void) ThrowMagickException(&image->exception,GetMagickModule(),
2994 ResourceLimitError,"Cannot overwrite frozen MNG object buffer",
2995 "`%s'",image->filename);
3001 if (mng_info->ob[object_id]->image != (Image *) NULL)
3002 mng_info->ob[object_id]->image=DestroyImage
3003 (mng_info->ob[object_id]->image);
3005 mng_info->ob[object_id]->image=CloneImage(image,0,0,MagickTrue,
3008 if (mng_info->ob[object_id]->image != (Image *) NULL)
3009 mng_info->ob[object_id]->image->file=(FILE *) NULL;
3012 (void) ThrowMagickException(&image->exception,GetMagickModule(),
3013 ResourceLimitError,"Cloning image for object buffer failed",
3014 "`%s'",image->filename);
3016 if (ping_width > 250000L || ping_height > 250000L)
3017 png_error(ping,"PNG Image dimensions are too large.");
3019 mng_info->ob[object_id]->width=ping_width;
3020 mng_info->ob[object_id]->height=ping_height;
3021 mng_info->ob[object_id]->color_type=ping_color_type;
3022 mng_info->ob[object_id]->sample_depth=ping_bit_depth;
3023 mng_info->ob[object_id]->interlace_method=ping_interlace_method;
3024 mng_info->ob[object_id]->compression_method=
3025 ping_compression_method;
3026 mng_info->ob[object_id]->filter_method=ping_filter_method;
3028 if (png_get_valid(ping,ping_info,PNG_INFO_PLTE))
3037 Copy the PLTE to the object buffer.
3039 png_get_PLTE(ping,ping_info,&plte,&number_colors);
3040 mng_info->ob[object_id]->plte_length=number_colors;
3042 for (i=0; i < number_colors; i++)
3044 mng_info->ob[object_id]->plte[i]=plte[i];
3049 mng_info->ob[object_id]->plte_length=0;
3054 Relinquish resources.
3056 png_destroy_read_struct(&ping,&ping_info,&end_info);
3058 ping_pixels=(unsigned char *) RelinquishMagickMemory(ping_pixels);
3059 #if defined(PNG_SETJMP_NOT_THREAD_SAFE)
3060 UnlockSemaphoreInfo(ping_semaphore);
3063 if (logging != MagickFalse)
3064 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3065 " exit ReadOnePNGImage()");
3069 /* end of reading one PNG image */
3072 static Image *ReadPNGImage(const ImageInfo *image_info,ExceptionInfo *exception)
3087 magic_number[MaxTextExtent];
3095 assert(image_info != (const ImageInfo *) NULL);
3096 assert(image_info->signature == MagickSignature);
3098 if (image_info->debug != MagickFalse)
3099 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
3100 image_info->filename);
3102 assert(exception != (ExceptionInfo *) NULL);
3103 assert(exception->signature == MagickSignature);
3104 logging=LogMagickEvent(CoderEvent,GetMagickModule(),"enter ReadPNGImage()");
3105 image=AcquireImage(image_info);
3106 mng_info=(MngInfo *) NULL;
3107 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
3109 if (status == MagickFalse)
3110 ThrowReaderException(FileOpenError,"UnableToOpenFile");
3113 Verify PNG signature.
3115 count=ReadBlob(image,8,(unsigned char *) magic_number);
3117 if (count < 8 || memcmp(magic_number,"\211PNG\r\n\032\n",8) != 0)
3118 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
3121 Allocate a MngInfo structure.
3123 have_mng_structure=MagickFalse;
3124 mng_info=(MngInfo *) AcquireMagickMemory(sizeof(MngInfo));
3126 if (mng_info == (MngInfo *) NULL)
3127 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
3130 Initialize members of the MngInfo structure.
3132 (void) ResetMagickMemory(mng_info,0,sizeof(MngInfo));
3133 mng_info->image=image;
3134 have_mng_structure=MagickTrue;
3137 image=ReadOnePNGImage(mng_info,image_info,exception);
3138 MngInfoFreeStruct(mng_info,&have_mng_structure);
3140 if (image == (Image *) NULL)
3142 if (previous != (Image *) NULL)
3144 if (previous->signature != MagickSignature)
3145 ThrowReaderException(CorruptImageError,"CorruptImage");
3147 (void) CloseBlob(previous);
3148 (void) DestroyImageList(previous);
3151 if (logging != MagickFalse)
3152 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3153 "exit ReadPNGImage() with error");
3155 return((Image *) NULL);
3158 (void) CloseBlob(image);
3160 if ((image->columns == 0) || (image->rows == 0))
3162 if (logging != MagickFalse)
3163 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3164 "exit ReadPNGImage() with error.");
3166 ThrowReaderException(CorruptImageError,"CorruptImage");
3169 if (LocaleCompare(image_info->magick,"PNG8") == 0)
3171 (void) SetImageType(image,PaletteType);
3173 if (image->matte != MagickFalse)
3175 /* To do: Reduce to binary transparency */
3179 if (LocaleCompare(image_info->magick,"PNG24") == 0)
3181 (void) SetImageType(image,TrueColorType);
3182 image->matte=MagickFalse;
3185 if (LocaleCompare(image_info->magick,"PNG32") == 0)
3186 (void) SetImageType(image,TrueColorMatteType);
3188 if (logging != MagickFalse)
3189 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3190 " page.w: %.20g, page.h: %.20g,page.x: %.20g, page.y: %.20g.",
3191 (double) image->page.width,(double) image->page.height,
3192 (double) image->page.x,(double) image->page.y);
3194 if (logging != MagickFalse)
3195 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"exit ReadPNGImage()");
3202 #if defined(JNG_SUPPORTED)
3204 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3208 % R e a d O n e J N G I m a g e %
3212 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3214 % ReadOneJNGImage() reads a JPEG Network Graphics (JNG) image file
3215 % (minus the 8-byte signature) and returns it. It allocates the memory
3216 % necessary for the new Image structure and returns a pointer to the new
3219 % JNG support written by Glenn Randers-Pehrson, glennrp@image...
3221 % The format of the ReadOneJNGImage method is:
3223 % Image *ReadOneJNGImage(MngInfo *mng_info, const ImageInfo *image_info,
3224 % ExceptionInfo *exception)
3226 % A description of each parameter follows:
3228 % o mng_info: Specifies a pointer to a MngInfo structure.
3230 % o image_info: the image info.
3232 % o exception: return any errors or warnings in this structure.
3235 static Image *ReadOneJNGImage(MngInfo *mng_info,
3236 const ImageInfo *image_info, ExceptionInfo *exception)
3263 jng_image_sample_depth,
3264 jng_image_compression_method,
3265 jng_image_interlace_method,
3266 jng_alpha_sample_depth,
3267 jng_alpha_compression_method,
3268 jng_alpha_filter_method,
3269 jng_alpha_interlace_method;
3271 register const PixelPacket
3278 register PixelPacket
3281 register unsigned char
3292 jng_alpha_compression_method=0;
3293 jng_alpha_sample_depth=8;
3297 alpha_image=(Image *) NULL;
3298 color_image=(Image *) NULL;
3299 alpha_image_info=(ImageInfo *) NULL;
3300 color_image_info=(ImageInfo *) NULL;
3302 logging=LogMagickEvent(CoderEvent,GetMagickModule(),
3303 " enter ReadOneJNGImage()");
3305 image=mng_info->image;
3307 if (GetAuthenticPixelQueue(image) != (PixelPacket *) NULL)
3310 Allocate next image structure.
3312 if (logging != MagickFalse)
3313 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3314 " AcquireNextImage()");
3316 AcquireNextImage(image_info,image);
3318 if (GetNextImageInList(image) == (Image *) NULL)
3319 return((Image *) NULL);
3321 image=SyncNextImageInList(image);
3323 mng_info->image=image;
3326 Signature bytes have already been read.
3329 read_JSEP=MagickFalse;
3330 reading_idat=MagickFalse;
3331 skip_to_iend=MagickFalse;
3335 type[MaxTextExtent];
3344 Read a new JNG chunk.
3346 status=SetImageProgress(image,LoadImagesTag,TellBlob(image),
3347 2*GetBlobSize(image));
3349 if (status == MagickFalse)
3353 (void) ConcatenateMagickString(type,"errr",MaxTextExtent);
3354 length=ReadBlobMSBLong(image);
3355 count=(unsigned int) ReadBlob(image,4,(unsigned char *) type);
3357 if (logging != MagickFalse)
3358 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3359 " Reading JNG chunk type %c%c%c%c, length: %.20g",
3360 type[0],type[1],type[2],type[3],(double) length);
3362 if (length > PNG_UINT_31_MAX || count == 0)
3363 ThrowReaderException(CorruptImageError,"CorruptImage");
3366 chunk=(unsigned char *) NULL;
3370 chunk=(unsigned char *) AcquireQuantumMemory(length,sizeof(*chunk));
3372 if (chunk == (unsigned char *) NULL)
3373 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
3375 for (i=0; i < (ssize_t) length; i++)
3376 chunk[i]=(unsigned char) ReadBlobByte(image);
3381 (void) ReadBlobMSBLong(image); /* read crc word */
3386 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
3391 if (memcmp(type,mng_JHDR,4) == 0)
3395 jng_width=(size_t) ((p[0] << 24) | (p[1] << 16) |
3396 (p[2] << 8) | p[3]);
3397 jng_height=(size_t) ((p[4] << 24) | (p[5] << 16) |
3398 (p[6] << 8) | p[7]);
3399 jng_color_type=p[8];
3400 jng_image_sample_depth=p[9];
3401 jng_image_compression_method=p[10];
3402 jng_image_interlace_method=p[11];
3404 image->interlace=jng_image_interlace_method != 0 ? PNGInterlace :
3407 jng_alpha_sample_depth=p[12];
3408 jng_alpha_compression_method=p[13];
3409 jng_alpha_filter_method=p[14];
3410 jng_alpha_interlace_method=p[15];
3412 if (logging != MagickFalse)
3414 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3415 " jng_width: %16lu",(unsigned long) jng_width);
3417 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3418 " jng_width: %16lu",(unsigned long) jng_height);
3420 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3421 " jng_color_type: %16d",jng_color_type);
3423 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3424 " jng_image_sample_depth: %3d",
3425 jng_image_sample_depth);
3427 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3428 " jng_image_compression_method:%3d",
3429 jng_image_compression_method);
3431 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3432 " jng_image_interlace_method: %3d",
3433 jng_image_interlace_method);
3435 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3436 " jng_alpha_sample_depth: %3d",
3437 jng_alpha_sample_depth);
3439 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3440 " jng_alpha_compression_method:%3d",
3441 jng_alpha_compression_method);
3443 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3444 " jng_alpha_filter_method: %3d",
3445 jng_alpha_filter_method);
3447 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3448 " jng_alpha_interlace_method: %3d",
3449 jng_alpha_interlace_method);
3454 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
3460 if ((reading_idat == MagickFalse) && (read_JSEP == MagickFalse) &&
3461 ((memcmp(type,mng_JDAT,4) == 0) || (memcmp(type,mng_JdAA,4) == 0) ||
3462 (memcmp(type,mng_IDAT,4) == 0) || (memcmp(type,mng_JDAA,4) == 0)))
3465 o create color_image
3466 o open color_blob, attached to color_image
3467 o if (color type has alpha)
3468 open alpha_blob, attached to alpha_image
3471 color_image_info=(ImageInfo *)AcquireMagickMemory(sizeof(ImageInfo));
3473 if (color_image_info == (ImageInfo *) NULL)
3474 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
3476 GetImageInfo(color_image_info);
3477 color_image=AcquireImage(color_image_info);
3479 if (color_image == (Image *) NULL)
3480 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
3482 if (logging != MagickFalse)
3483 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3484 " Creating color_blob.");
3486 (void) AcquireUniqueFilename(color_image->filename);
3487 status=OpenBlob(color_image_info,color_image,WriteBinaryBlobMode,
3490 if (status == MagickFalse)
3491 return((Image *) NULL);
3493 if ((image_info->ping == MagickFalse) && (jng_color_type >= 12))
3495 alpha_image_info=(ImageInfo *)
3496 AcquireMagickMemory(sizeof(ImageInfo));
3498 if (alpha_image_info == (ImageInfo *) NULL)
3499 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
3501 GetImageInfo(alpha_image_info);
3502 alpha_image=AcquireImage(alpha_image_info);
3504 if (alpha_image == (Image *) NULL)
3506 alpha_image=DestroyImage(alpha_image);
3507 ThrowReaderException(ResourceLimitError,
3508 "MemoryAllocationFailed");
3511 if (logging != MagickFalse)
3512 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3513 " Creating alpha_blob.");
3515 (void) AcquireUniqueFilename(alpha_image->filename);
3516 status=OpenBlob(alpha_image_info,alpha_image,WriteBinaryBlobMode,
3519 if (status == MagickFalse)
3520 return((Image *) NULL);
3522 if (jng_alpha_compression_method == 0)
3527 if (logging != MagickFalse)
3528 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3529 " Writing IHDR chunk to alpha_blob.");
3531 (void) WriteBlob(alpha_image,8,(const unsigned char *)
3532 "\211PNG\r\n\032\n");
3534 (void) WriteBlobMSBULong(alpha_image,13L);
3535 PNGType(data,mng_IHDR);
3536 LogPNGChunk(logging,mng_IHDR,13L);
3537 PNGLong(data+4,jng_width);
3538 PNGLong(data+8,jng_height);
3539 data[12]=jng_alpha_sample_depth;
3540 data[13]=0; /* color_type gray */
3541 data[14]=0; /* compression method 0 */
3542 data[15]=0; /* filter_method 0 */
3543 data[16]=0; /* interlace_method 0 */
3544 (void) WriteBlob(alpha_image,17,data);
3545 (void) WriteBlobMSBULong(alpha_image,crc32(0,data,17));
3548 reading_idat=MagickTrue;
3551 if (memcmp(type,mng_JDAT,4) == 0)
3553 /* Copy chunk to color_image->blob */
3555 if (logging != MagickFalse)
3556 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3557 " Copying JDAT chunk data to color_blob.");
3559 (void) WriteBlob(color_image,length,chunk);
3562 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
3567 if (memcmp(type,mng_IDAT,4) == 0)
3572 /* Copy IDAT header and chunk data to alpha_image->blob */
3574 if (image_info->ping == MagickFalse)
3576 if (logging != MagickFalse)
3577 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3578 " Copying IDAT chunk data to alpha_blob.");
3580 (void) WriteBlobMSBULong(alpha_image,(size_t) length);
3581 PNGType(data,mng_IDAT);
3582 LogPNGChunk(logging,mng_IDAT,length);
3583 (void) WriteBlob(alpha_image,4,data);
3584 (void) WriteBlob(alpha_image,length,chunk);
3585 (void) WriteBlobMSBULong(alpha_image,
3586 crc32(crc32(0,data,4),chunk,(uInt) length));
3590 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
3595 if ((memcmp(type,mng_JDAA,4) == 0) || (memcmp(type,mng_JdAA,4) == 0))
3597 /* Copy chunk data to alpha_image->blob */
3599 if (image_info->ping == MagickFalse)
3601 if (logging != MagickFalse)
3602 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3603 " Copying JDAA chunk data to alpha_blob.");
3605 (void) WriteBlob(alpha_image,length,chunk);
3609 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
3614 if (memcmp(type,mng_JSEP,4) == 0)
3616 read_JSEP=MagickTrue;
3619 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
3624 if (memcmp(type,mng_bKGD,4) == 0)
3628 image->background_color.red=ScaleCharToQuantum(p[1]);
3629 image->background_color.green=image->background_color.red;
3630 image->background_color.blue=image->background_color.red;
3635 image->background_color.red=ScaleCharToQuantum(p[1]);
3636 image->background_color.green=ScaleCharToQuantum(p[3]);
3637 image->background_color.blue=ScaleCharToQuantum(p[5]);
3640 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
3644 if (memcmp(type,mng_gAMA,4) == 0)
3647 image->gamma=((float) mng_get_long(p))*0.00001;
3649 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
3653 if (memcmp(type,mng_cHRM,4) == 0)
3657 image->chromaticity.white_point.x=0.00001*mng_get_long(p);
3658 image->chromaticity.white_point.y=0.00001*mng_get_long(&p[4]);
3659 image->chromaticity.red_primary.x=0.00001*mng_get_long(&p[8]);
3660 image->chromaticity.red_primary.y=0.00001*mng_get_long(&p[12]);
3661 image->chromaticity.green_primary.x=0.00001*mng_get_long(&p[16]);
3662 image->chromaticity.green_primary.y=0.00001*mng_get_long(&p[20]);
3663 image->chromaticity.blue_primary.x=0.00001*mng_get_long(&p[24]);
3664 image->chromaticity.blue_primary.y=0.00001*mng_get_long(&p[28]);
3667 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
3671 if (memcmp(type,mng_sRGB,4) == 0)
3675 image->rendering_intent=
3676 Magick_RenderingIntent_from_PNG_RenderingIntent(p[0]);
3677 image->gamma=0.45455f;
3678 image->chromaticity.red_primary.x=0.6400f;
3679 image->chromaticity.red_primary.y=0.3300f;
3680 image->chromaticity.green_primary.x=0.3000f;
3681 image->chromaticity.green_primary.y=0.6000f;
3682 image->chromaticity.blue_primary.x=0.1500f;
3683 image->chromaticity.blue_primary.y=0.0600f;
3684 image->chromaticity.white_point.x=0.3127f;
3685 image->chromaticity.white_point.y=0.3290f;
3688 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
3692 if (memcmp(type,mng_oFFs,4) == 0)
3696 image->page.x=(ssize_t) mng_get_long(p);
3697 image->page.y=(ssize_t) mng_get_long(&p[4]);
3699 if ((int) p[8] != 0)
3701 image->page.x/=10000;
3702 image->page.y/=10000;
3707 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
3712 if (memcmp(type,mng_pHYs,4) == 0)
3716 image->x_resolution=(double) mng_get_long(p);
3717 image->y_resolution=(double) mng_get_long(&p[4]);
3718 if ((int) p[8] == PNG_RESOLUTION_METER)
3720 image->units=PixelsPerCentimeterResolution;
3721 image->x_resolution=image->x_resolution/100.0f;
3722 image->y_resolution=image->y_resolution/100.0f;
3726 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
3731 if (memcmp(type,mng_iCCP,4) == 0)
3735 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
3742 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
3744 if (memcmp(type,mng_IEND,4))
3754 Finish up reading image data:
3756 o read main image from color_blob.
3760 o if (color_type has alpha)
3761 if alpha_encoding is PNG
3762 read secondary image from alpha_blob via ReadPNG
3763 if alpha_encoding is JPEG
3764 read secondary image from alpha_blob via ReadJPEG
3768 o copy intensity of secondary image into
3769 opacity samples of main image.
3771 o destroy the secondary image.
3774 (void) CloseBlob(color_image);
3776 if (logging != MagickFalse)
3777 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3778 " Reading jng_image from color_blob.");
3780 (void) FormatMagickString(color_image_info->filename,MaxTextExtent,"%s",
3781 color_image->filename);
3783 color_image_info->ping=MagickFalse; /* To do: avoid this */
3784 jng_image=ReadImage(color_image_info,exception);
3786 if (jng_image == (Image *) NULL)
3787 return((Image *) NULL);
3789 (void) RelinquishUniqueFileResource(color_image->filename);
3790 color_image=DestroyImage(color_image);
3791 color_image_info=DestroyImageInfo(color_image_info);
3793 if (jng_image == (Image *) NULL)
3794 return((Image *) NULL);
3796 if (logging != MagickFalse)
3797 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3798 " Copying jng_image pixels to main image.");
3800 image->rows=jng_height;
3801 image->columns=jng_width;
3802 length=image->columns*sizeof(PixelPacket);
3804 for (y=0; y < (ssize_t) image->rows; y++)
3806 s=GetVirtualPixels(jng_image,0,y,image->columns,1,&image->exception);
3807 q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
3808 (void) CopyMagickMemory(q,s,length);
3810 if (SyncAuthenticPixels(image,exception) == MagickFalse)
3814 jng_image=DestroyImage(jng_image);
3816 if (image_info->ping == MagickFalse)
3818 if (jng_color_type >= 12)
3820 if (jng_alpha_compression_method == 0)
3824 (void) WriteBlobMSBULong(alpha_image,0x00000000L);
3825 PNGType(data,mng_IEND);
3826 LogPNGChunk(logging,mng_IEND,0L);
3827 (void) WriteBlob(alpha_image,4,data);
3828 (void) WriteBlobMSBULong(alpha_image,crc32(0,data,4));
3831 (void) CloseBlob(alpha_image);
3833 if (logging != MagickFalse)
3834 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3835 " Reading opacity from alpha_blob.");
3837 (void) FormatMagickString(alpha_image_info->filename,MaxTextExtent,
3838 "%s",alpha_image->filename);
3840 jng_image=ReadImage(alpha_image_info,exception);
3842 if (jng_image != (Image *) NULL)
3843 for (y=0; y < (ssize_t) image->rows; y++)
3845 s=GetVirtualPixels(jng_image,0,y,image->columns,1,
3847 q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
3849 if (image->matte != MagickFalse)
3850 for (x=(ssize_t) image->columns; x != 0; x--,q++,s++)
3851 q->opacity=(Quantum) QuantumRange-s->red;
3854 for (x=(ssize_t) image->columns; x != 0; x--,q++,s++)
3856 q->opacity=(Quantum) QuantumRange-s->red;
3857 if (q->opacity != OpaqueOpacity)
3858 image->matte=MagickTrue;
3861 if (SyncAuthenticPixels(image,exception) == MagickFalse)
3864 (void) RelinquishUniqueFileResource(alpha_image->filename);
3865 alpha_image=DestroyImage(alpha_image);
3866 alpha_image_info=DestroyImageInfo(alpha_image_info);
3867 if (jng_image != (Image *) NULL)
3868 jng_image=DestroyImage(jng_image);
3872 /* Read the JNG image. */
3874 if (mng_info->mng_type == 0)
3876 mng_info->mng_width=jng_width;
3877 mng_info->mng_height=jng_height;
3880 if (image->page.width == 0 && image->page.height == 0)
3882 image->page.width=jng_width;
3883 image->page.height=jng_height;
3886 if (image->page.x == 0 && image->page.y == 0)
3888 image->page.x=mng_info->x_off[mng_info->object_id];
3889 image->page.y=mng_info->y_off[mng_info->object_id];
3894 image->page.y=mng_info->y_off[mng_info->object_id];
3897 mng_info->image_found++;
3898 status=SetImageProgress(image,LoadImagesTag,2*TellBlob(image),
3899 2*GetBlobSize(image));
3901 if (logging != MagickFalse)
3902 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3903 " exit ReadOneJNGImage()");
3909 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3913 % R e a d J N G I m a g e %
3917 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3919 % ReadJNGImage() reads a JPEG Network Graphics (JNG) image file
3920 % (including the 8-byte signature) and returns it. It allocates the memory
3921 % necessary for the new Image structure and returns a pointer to the new
3924 % JNG support written by Glenn Randers-Pehrson, glennrp@image...
3926 % The format of the ReadJNGImage method is:
3928 % Image *ReadJNGImage(const ImageInfo *image_info, ExceptionInfo
3931 % A description of each parameter follows:
3933 % o image_info: the image info.
3935 % o exception: return any errors or warnings in this structure.
3939 static Image *ReadJNGImage(const ImageInfo *image_info,ExceptionInfo *exception)
3954 magic_number[MaxTextExtent];
3962 assert(image_info != (const ImageInfo *) NULL);
3963 assert(image_info->signature == MagickSignature);
3964 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image_info->filename);
3965 assert(exception != (ExceptionInfo *) NULL);
3966 assert(exception->signature == MagickSignature);
3967 logging=LogMagickEvent(CoderEvent,GetMagickModule(),"enter ReadJNGImage()");
3968 image=AcquireImage(image_info);
3969 mng_info=(MngInfo *) NULL;
3970 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
3972 if (status == MagickFalse)
3973 return((Image *) NULL);
3975 if (LocaleCompare(image_info->magick,"JNG") != 0)
3976 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
3978 /* Verify JNG signature. */
3980 count=(size_t) ReadBlob(image,8,(unsigned char *) magic_number);
3982 if (count < 8 || memcmp(magic_number,"\213JNG\r\n\032\n",8) != 0)
3983 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
3985 /* Allocate a MngInfo structure. */
3987 have_mng_structure=MagickFalse;
3988 mng_info=(MngInfo *) AcquireMagickMemory(sizeof(*mng_info));
3990 if (mng_info == (MngInfo *) NULL)
3991 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
3993 /* Initialize members of the MngInfo structure. */
3995 (void) ResetMagickMemory(mng_info,0,sizeof(MngInfo));
3996 have_mng_structure=MagickTrue;
3998 mng_info->image=image;
4000 image=ReadOneJNGImage(mng_info,image_info,exception);
4001 MngInfoFreeStruct(mng_info,&have_mng_structure);
4003 if (image == (Image *) NULL)
4005 if (IsImageObject(previous) != MagickFalse)
4007 (void) CloseBlob(previous);
4008 (void) DestroyImageList(previous);
4011 if (logging != MagickFalse)
4012 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4013 "exit ReadJNGImage() with error");
4015 return((Image *) NULL);
4017 (void) CloseBlob(image);
4019 if (image->columns == 0 || image->rows == 0)
4021 if (logging != MagickFalse)
4022 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4023 "exit ReadJNGImage() with error");
4025 ThrowReaderException(CorruptImageError,"CorruptImage");
4028 if (logging != MagickFalse)
4029 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"exit ReadJNGImage()");
4035 static Image *ReadMNGImage(const ImageInfo *image_info,ExceptionInfo *exception)
4038 page_geometry[MaxTextExtent];
4071 #if defined(MNG_INSERT_LAYERS)
4073 mng_background_color;
4076 register unsigned char
4091 #if defined(MNG_INSERT_LAYERS)
4096 volatile unsigned int
4097 #ifdef MNG_OBJECT_BUFFERS
4098 mng_background_object=0,
4100 mng_type=0; /* 0: PNG or JNG; 1: MNG; 2: MNG-LC; 3: MNG-VLC */
4103 default_frame_timeout,
4105 #if defined(MNG_INSERT_LAYERS)
4111 /* These delays are all measured in image ticks_per_second,
4112 * not in MNG ticks_per_second
4115 default_frame_delay,
4119 #if defined(MNG_INSERT_LAYERS)
4128 previous_fb.bottom=0;
4130 previous_fb.right=0;
4132 default_fb.bottom=0;
4136 /* Open image file. */
4138 assert(image_info != (const ImageInfo *) NULL);
4139 assert(image_info->signature == MagickSignature);
4140 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image_info->filename);
4141 assert(exception != (ExceptionInfo *) NULL);
4142 assert(exception->signature == MagickSignature);
4143 logging=LogMagickEvent(CoderEvent,GetMagickModule(),"enter ReadMNGImage()");
4144 image=AcquireImage(image_info);
4145 mng_info=(MngInfo *) NULL;
4146 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
4148 if (status == MagickFalse)
4149 return((Image *) NULL);
4151 first_mng_object=MagickFalse;
4153 have_mng_structure=MagickFalse;
4155 /* Allocate a MngInfo structure. */
4157 mng_info=(MngInfo *) AcquireMagickMemory(sizeof(MngInfo));
4159 if (mng_info == (MngInfo *) NULL)
4160 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
4162 /* Initialize members of the MngInfo structure. */
4164 (void) ResetMagickMemory(mng_info,0,sizeof(MngInfo));
4165 mng_info->image=image;
4166 have_mng_structure=MagickTrue;
4168 if (LocaleCompare(image_info->magick,"MNG") == 0)
4171 magic_number[MaxTextExtent];
4173 /* Verify MNG signature. */
4174 count=(size_t) ReadBlob(image,8,(unsigned char *) magic_number);
4175 if (memcmp(magic_number,"\212MNG\r\n\032\n",8) != 0)
4176 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
4178 /* Initialize some nonzero members of the MngInfo structure. */
4179 for (i=0; i < MNG_MAX_OBJECTS; i++)
4181 mng_info->object_clip[i].right=(ssize_t) PNG_UINT_31_MAX;
4182 mng_info->object_clip[i].bottom=(ssize_t) PNG_UINT_31_MAX;
4184 mng_info->exists[0]=MagickTrue;
4187 first_mng_object=MagickTrue;
4189 #if defined(MNG_INSERT_LAYERS)
4190 insert_layers=MagickFalse; /* should be False when converting or mogrifying */
4192 default_frame_delay=0;
4193 default_frame_timeout=0;
4196 mng_info->ticks_per_second=1UL*image->ticks_per_second;
4198 skip_to_iend=MagickFalse;
4199 term_chunk_found=MagickFalse;
4200 mng_info->framing_mode=1;
4201 #if defined(MNG_INSERT_LAYERS)
4202 mandatory_back=MagickFalse;
4204 #if defined(MNG_INSERT_LAYERS)
4205 mng_background_color=image->background_color;
4207 default_fb=mng_info->frame;
4208 previous_fb=mng_info->frame;
4212 type[MaxTextExtent];
4214 if (LocaleCompare(image_info->magick,"MNG") == 0)
4223 (void) ConcatenateMagickString(type,"errr",MaxTextExtent);
4224 length=ReadBlobMSBLong(image);
4225 count=(size_t) ReadBlob(image,4,(unsigned char *) type);
4227 if (logging != MagickFalse)
4228 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4229 " Reading MNG chunk type %c%c%c%c, length: %.20g",
4230 type[0],type[1],type[2],type[3],(double) length);
4232 if (length > PNG_UINT_31_MAX)
4236 ThrowReaderException(CorruptImageError,"CorruptImage");
4239 chunk=(unsigned char *) NULL;
4243 chunk=(unsigned char *) AcquireQuantumMemory(length,sizeof(*chunk));
4245 if (chunk == (unsigned char *) NULL)
4246 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
4248 for (i=0; i < (ssize_t) length; i++)
4249 chunk[i]=(unsigned char) ReadBlobByte(image);
4254 (void) ReadBlobMSBLong(image); /* read crc word */
4256 #if !defined(JNG_SUPPORTED)
4257 if (memcmp(type,mng_JHDR,4) == 0)
4259 skip_to_iend=MagickTrue;
4261 if (mng_info->jhdr_warning == 0)
4262 (void) ThrowMagickException(&image->exception,GetMagickModule(),
4263 CoderError,"JNGCompressNotSupported","`%s'",image->filename);
4265 mng_info->jhdr_warning++;
4268 if (memcmp(type,mng_DHDR,4) == 0)
4270 skip_to_iend=MagickTrue;
4272 if (mng_info->dhdr_warning == 0)
4273 (void) ThrowMagickException(&image->exception,GetMagickModule(),
4274 CoderError,"DeltaPNGNotSupported","`%s'",image->filename);
4276 mng_info->dhdr_warning++;
4278 if (memcmp(type,mng_MEND,4) == 0)
4283 if (memcmp(type,mng_IEND,4) == 0)
4284 skip_to_iend=MagickFalse;
4287 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4289 if (logging != MagickFalse)
4290 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4296 if (memcmp(type,mng_MHDR,4) == 0)
4298 mng_info->mng_width=(size_t) ((p[0] << 24) | (p[1] << 16) |
4299 (p[2] << 8) | p[3]);
4301 mng_info->mng_height=(size_t) ((p[4] << 24) | (p[5] << 16) |
4302 (p[6] << 8) | p[7]);
4304 if (logging != MagickFalse)
4306 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4307 " MNG width: %.20g",(double) mng_info->mng_width);
4308 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4309 " MNG height: %.20g",(double) mng_info->mng_height);
4313 mng_info->ticks_per_second=(size_t) mng_get_long(p);
4315 if (mng_info->ticks_per_second == 0)
4316 default_frame_delay=0;
4319 default_frame_delay=1UL*image->ticks_per_second/
4320 mng_info->ticks_per_second;
4322 frame_delay=default_frame_delay;
4328 simplicity=(size_t) mng_get_long(p);
4331 mng_type=1; /* Full MNG */
4333 if ((simplicity != 0) && ((simplicity | 11) == 11))
4334 mng_type=2; /* LC */
4336 if ((simplicity != 0) && ((simplicity | 9) == 9))
4337 mng_type=3; /* VLC */
4339 #if defined(MNG_INSERT_LAYERS)
4341 insert_layers=MagickTrue;
4343 if (GetAuthenticPixelQueue(image) != (PixelPacket *) NULL)
4345 /* Allocate next image structure. */
4346 AcquireNextImage(image_info,image);
4348 if (GetNextImageInList(image) == (Image *) NULL)
4349 return((Image *) NULL);
4351 image=SyncNextImageInList(image);
4352 mng_info->image=image;
4355 if ((mng_info->mng_width > 65535L) ||
4356 (mng_info->mng_height > 65535L))
4357 ThrowReaderException(ImageError,"WidthOrHeightExceedsLimit");
4359 (void) FormatMagickString(page_geometry,MaxTextExtent,
4360 "%.20gx%.20g+0+0",(double) mng_info->mng_width,(double)
4361 mng_info->mng_height);
4363 mng_info->frame.left=0;
4364 mng_info->frame.right=(ssize_t) mng_info->mng_width;
4365 mng_info->frame.top=0;
4366 mng_info->frame.bottom=(ssize_t) mng_info->mng_height;
4367 mng_info->clip=default_fb=previous_fb=mng_info->frame;
4369 for (i=0; i < MNG_MAX_OBJECTS; i++)
4370 mng_info->object_clip[i]=mng_info->frame;
4372 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4376 if (memcmp(type,mng_TERM,4) == 0)
4387 final_delay=(png_uint_32) mng_get_long(&p[2]);
4388 mng_iterations=(png_uint_32) mng_get_long(&p[6]);
4390 if (mng_iterations == PNG_UINT_31_MAX)
4393 image->iterations=mng_iterations;
4394 term_chunk_found=MagickTrue;
4397 if (logging != MagickFalse)
4399 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4400 " repeat=%d",repeat);
4402 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4403 " final_delay=%.20g",(double) final_delay);
4405 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4406 " image->iterations=%.20g",(double) image->iterations);
4409 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4412 if (memcmp(type,mng_DEFI,4) == 0)
4415 (void) ThrowMagickException(&image->exception,GetMagickModule(),
4416 CoderError,"DEFI chunk found in MNG-VLC datastream","`%s'",
4419 object_id=(p[0] << 8) | p[1];
4421 if (mng_type == 2 && object_id != 0)
4422 (void) ThrowMagickException(&image->exception,GetMagickModule(),
4423 CoderError,"Nonzero object_id in MNG-LC datastream","`%s'",
4426 if (object_id > MNG_MAX_OBJECTS)
4429 Instead ofsuing a warning we should allocate a larger
4430 MngInfo structure and continue.
4432 (void) ThrowMagickException(&image->exception,GetMagickModule(),
4433 CoderError,"object id too large","`%s'",image->filename);
4434 object_id=MNG_MAX_OBJECTS;
4437 if (mng_info->exists[object_id])
4438 if (mng_info->frozen[object_id])
4440 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4441 (void) ThrowMagickException(&image->exception,
4442 GetMagickModule(),CoderError,
4443 "DEFI cannot redefine a frozen MNG object","`%s'",
4448 mng_info->exists[object_id]=MagickTrue;
4451 mng_info->invisible[object_id]=p[2];
4454 Extract object offset info.
4458 mng_info->x_off[object_id]=(ssize_t) ((p[4] << 24) |
4459 (p[5] << 16) | (p[6] << 8) | p[7]);
4461 mng_info->y_off[object_id]=(ssize_t) ((p[8] << 24) |
4462 (p[9] << 16) | (p[10] << 8) | p[11]);
4464 if (logging != MagickFalse)
4466 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4467 " x_off[%d]: %.20g",object_id,(double)
4468 mng_info->x_off[object_id]);
4470 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4471 " y_off[%d]: %.20g",object_id,(double)
4472 mng_info->y_off[object_id]);
4477 Extract object clipping info.
4480 mng_info->object_clip[object_id]=mng_read_box(mng_info->frame,0,
4483 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4486 if (memcmp(type,mng_bKGD,4) == 0)
4488 mng_info->have_global_bkgd=MagickFalse;
4492 mng_info->mng_global_bkgd.red=
4493 ScaleShortToQuantum((unsigned short) ((p[0] << 8) | p[1]));
4495 mng_info->mng_global_bkgd.green=
4496 ScaleShortToQuantum((unsigned short) ((p[2] << 8) | p[3]));
4498 mng_info->mng_global_bkgd.blue=
4499 ScaleShortToQuantum((unsigned short) ((p[4] << 8) | p[5]));
4501 mng_info->have_global_bkgd=MagickTrue;
4504 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4507 if (memcmp(type,mng_BACK,4) == 0)
4509 #if defined(MNG_INSERT_LAYERS)
4511 mandatory_back=p[6];
4516 if (mandatory_back && length > 5)
4518 mng_background_color.red=
4519 ScaleShortToQuantum((unsigned short) ((p[0] << 8) | p[1]));
4521 mng_background_color.green=
4522 ScaleShortToQuantum((unsigned short) ((p[2] << 8) | p[3]));
4524 mng_background_color.blue=
4525 ScaleShortToQuantum((unsigned short) ((p[4] << 8) | p[5]));
4527 mng_background_color.opacity=OpaqueOpacity;
4530 #ifdef MNG_OBJECT_BUFFERS
4532 mng_background_object=(p[7] << 8) | p[8];
4535 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4539 if (memcmp(type,mng_PLTE,4) == 0)
4541 /* Read global PLTE. */
4543 if (length && (length < 769))
4545 if (mng_info->global_plte == (png_colorp) NULL)
4546 mng_info->global_plte=(png_colorp) AcquireQuantumMemory(256,
4547 sizeof(*mng_info->global_plte));
4549 for (i=0; i < (ssize_t) (length/3); i++)
4551 mng_info->global_plte[i].red=p[3*i];
4552 mng_info->global_plte[i].green=p[3*i+1];
4553 mng_info->global_plte[i].blue=p[3*i+2];
4556 mng_info->global_plte_length=(unsigned int) (length/3);
4559 for ( ; i < 256; i++)
4561 mng_info->global_plte[i].red=i;
4562 mng_info->global_plte[i].green=i;
4563 mng_info->global_plte[i].blue=i;
4567 mng_info->global_plte_length=256;
4570 mng_info->global_plte_length=0;
4572 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4576 if (memcmp(type,mng_tRNS,4) == 0)
4578 /* read global tRNS */
4581 for (i=0; i < (ssize_t) length; i++)
4582 mng_info->global_trns[i]=p[i];
4585 for ( ; i < 256; i++)
4586 mng_info->global_trns[i]=255;
4588 mng_info->global_trns_length=(unsigned int) length;
4589 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4592 if (memcmp(type,mng_gAMA,4) == 0)
4599 igamma=mng_get_long(p);
4600 mng_info->global_gamma=((float) igamma)*0.00001;
4601 mng_info->have_global_gama=MagickTrue;
4605 mng_info->have_global_gama=MagickFalse;
4607 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4611 if (memcmp(type,mng_cHRM,4) == 0)
4613 /* Read global cHRM */
4617 mng_info->global_chrm.white_point.x=0.00001*mng_get_long(p);
4618 mng_info->global_chrm.white_point.y=0.00001*mng_get_long(&p[4]);
4619 mng_info->global_chrm.red_primary.x=0.00001*mng_get_long(&p[8]);
4620 mng_info->global_chrm.red_primary.y=0.00001*
4621 mng_get_long(&p[12]);
4622 mng_info->global_chrm.green_primary.x=0.00001*
4623 mng_get_long(&p[16]);
4624 mng_info->global_chrm.green_primary.y=0.00001*
4625 mng_get_long(&p[20]);
4626 mng_info->global_chrm.blue_primary.x=0.00001*
4627 mng_get_long(&p[24]);
4628 mng_info->global_chrm.blue_primary.y=0.00001*
4629 mng_get_long(&p[28]);
4630 mng_info->have_global_chrm=MagickTrue;
4633 mng_info->have_global_chrm=MagickFalse;
4635 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4639 if (memcmp(type,mng_sRGB,4) == 0)
4646 mng_info->global_srgb_intent=
4647 Magick_RenderingIntent_from_PNG_RenderingIntent(p[0]);
4648 mng_info->have_global_srgb=MagickTrue;
4651 mng_info->have_global_srgb=MagickFalse;
4653 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4657 if (memcmp(type,mng_iCCP,4) == 0)
4665 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4670 if (memcmp(type,mng_FRAM,4) == 0)
4673 (void) ThrowMagickException(&image->exception,GetMagickModule(),
4674 CoderError,"FRAM chunk found in MNG-VLC datastream","`%s'",
4677 if ((mng_info->framing_mode == 2) || (mng_info->framing_mode == 4))
4678 image->delay=frame_delay;
4680 frame_delay=default_frame_delay;
4681 frame_timeout=default_frame_timeout;
4686 mng_info->framing_mode=p[0];
4688 if (logging != MagickFalse)
4689 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4690 " Framing_mode=%d",mng_info->framing_mode);
4694 /* Note the delay and frame clipping boundaries. */
4696 p++; /* framing mode */
4698 while (*p && ((p-chunk) < (ssize_t) length))
4699 p++; /* frame name */
4701 p++; /* frame name terminator */
4703 if ((p-chunk) < (ssize_t) (length-4))
4710 change_delay=(*p++);
4711 change_timeout=(*p++);
4712 change_clipping=(*p++);
4713 p++; /* change_sync */
4717 frame_delay=1UL*image->ticks_per_second*
4720 if (mng_info->ticks_per_second != 0)
4721 frame_delay/=mng_info->ticks_per_second;
4724 frame_delay=PNG_UINT_31_MAX;
4726 if (change_delay == 2)
4727 default_frame_delay=frame_delay;
4731 if (logging != MagickFalse)
4732 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4733 " Framing_delay=%.20g",(double) frame_delay);
4738 frame_timeout=1UL*image->ticks_per_second*
4741 if (mng_info->ticks_per_second != 0)
4742 frame_timeout/=mng_info->ticks_per_second;
4745 frame_timeout=PNG_UINT_31_MAX;
4747 if (change_delay == 2)
4748 default_frame_timeout=frame_timeout;
4752 if (logging != MagickFalse)
4753 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4754 " Framing_timeout=%.20g",(double) frame_timeout);
4757 if (change_clipping)
4759 fb=mng_read_box(previous_fb,(char) p[0],&p[1]);
4763 if (logging != MagickFalse)
4764 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4765 " Frame_clip: L=%.20g R=%.20g T=%.20g B=%.20g",
4766 (double) fb.left,(double) fb.right,(double) fb.top,
4767 (double) fb.bottom);
4769 if (change_clipping == 2)
4775 mng_info->clip=mng_minimum_box(fb,mng_info->frame);
4777 subframe_width=(size_t) (mng_info->clip.right
4778 -mng_info->clip.left);
4780 subframe_height=(size_t) (mng_info->clip.bottom
4781 -mng_info->clip.top);
4783 Insert a background layer behind the frame if framing_mode is 4.
4785 #if defined(MNG_INSERT_LAYERS)
4786 if (logging != MagickFalse)
4787 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4788 " subframe_width=%.20g, subframe_height=%.20g",(double)
4789 subframe_width,(double) subframe_height);
4791 if (insert_layers && (mng_info->framing_mode == 4) &&
4792 (subframe_width) && (subframe_height))
4794 /* Allocate next image structure. */
4795 if (GetAuthenticPixelQueue(image) != (PixelPacket *) NULL)
4797 AcquireNextImage(image_info,image);
4799 if (GetNextImageInList(image) == (Image *) NULL)
4801 image=DestroyImageList(image);
4802 MngInfoFreeStruct(mng_info,&have_mng_structure);
4803 return((Image *) NULL);
4806 image=SyncNextImageInList(image);
4809 mng_info->image=image;
4811 if (term_chunk_found)
4813 image->start_loop=MagickTrue;
4814 image->iterations=mng_iterations;
4815 term_chunk_found=MagickFalse;
4819 image->start_loop=MagickFalse;
4821 image->columns=subframe_width;
4822 image->rows=subframe_height;
4823 image->page.width=subframe_width;
4824 image->page.height=subframe_height;
4825 image->page.x=mng_info->clip.left;
4826 image->page.y=mng_info->clip.top;
4827 image->background_color=mng_background_color;
4828 image->matte=MagickFalse;
4830 (void) SetImageBackgroundColor(image);
4832 if (logging != MagickFalse)
4833 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4834 " Insert backgd layer, L=%.20g, R=%.20g T=%.20g, B=%.20g",
4835 (double) mng_info->clip.left,(double) mng_info->clip.right,
4836 (double) mng_info->clip.top,(double) mng_info->clip.bottom);
4839 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4842 if (memcmp(type,mng_CLIP,4) == 0)
4851 first_object=(p[0] << 8) | p[1];
4852 last_object=(p[2] << 8) | p[3];
4854 for (i=(int) first_object; i <= (int) last_object; i++)
4856 if (mng_info->exists[i] && !mng_info->frozen[i])
4861 box=mng_info->object_clip[i];
4862 mng_info->object_clip[i]=mng_read_box(box,(char) p[4],&p[5]);
4866 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4869 if (memcmp(type,mng_SAVE,4) == 0)
4871 for (i=1; i < MNG_MAX_OBJECTS; i++)
4872 if (mng_info->exists[i])
4874 mng_info->frozen[i]=MagickTrue;
4875 #ifdef MNG_OBJECT_BUFFERS
4876 if (mng_info->ob[i] != (MngBuffer *) NULL)
4877 mng_info->ob[i]->frozen=MagickTrue;
4882 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4887 if ((memcmp(type,mng_DISC,4) == 0) || (memcmp(type,mng_SEEK,4) == 0))
4889 /* Read DISC or SEEK. */
4891 if ((length == 0) || !memcmp(type,mng_SEEK,4))
4893 for (i=1; i < MNG_MAX_OBJECTS; i++)
4894 MngInfoDiscardObject(mng_info,i);
4902 for (j=0; j < (ssize_t) length; j+=2)
4904 i=p[j] << 8 | p[j+1];
4905 MngInfoDiscardObject(mng_info,i);
4910 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4915 if (memcmp(type,mng_MOVE,4) == 0)
4923 first_object=(p[0] << 8) | p[1];
4924 last_object=(p[2] << 8) | p[3];
4925 for (i=(ssize_t) first_object; i <= (ssize_t) last_object; i++)
4927 if (mng_info->exists[i] && !mng_info->frozen[i])
4935 old_pair.a=mng_info->x_off[i];
4936 old_pair.b=mng_info->y_off[i];
4937 new_pair=mng_read_pair(old_pair,(int) p[4],&p[5]);
4938 mng_info->x_off[i]=new_pair.a;
4939 mng_info->y_off[i]=new_pair.b;
4943 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4947 if (memcmp(type,mng_LOOP,4) == 0)
4949 ssize_t loop_iters=1;
4950 loop_level=chunk[0];
4951 mng_info->loop_active[loop_level]=1; /* mark loop active */
4953 /* Record starting point. */
4954 loop_iters=mng_get_long(&chunk[1]);
4956 if (logging != MagickFalse)
4957 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4958 " LOOP level %.20g has %.20g iterations ",(double) loop_level,
4959 (double) loop_iters);
4961 if (loop_iters == 0)
4962 skipping_loop=loop_level;
4966 mng_info->loop_jump[loop_level]=TellBlob(image);
4967 mng_info->loop_count[loop_level]=loop_iters;
4970 mng_info->loop_iteration[loop_level]=0;
4971 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4975 if (memcmp(type,mng_ENDL,4) == 0)
4977 loop_level=chunk[0];
4979 if (skipping_loop > 0)
4981 if (skipping_loop == loop_level)
4984 Found end of zero-iteration loop.
4987 mng_info->loop_active[loop_level]=0;
4993 if (mng_info->loop_active[loop_level] == 1)
4995 mng_info->loop_count[loop_level]--;
4996 mng_info->loop_iteration[loop_level]++;
4998 if (logging != MagickFalse)
4999 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5000 " ENDL: LOOP level %.20g has %.20g remaining iters ",
5001 (double) loop_level,(double)
5002 mng_info->loop_count[loop_level]);
5004 if (mng_info->loop_count[loop_level] != 0)
5006 offset=SeekBlob(image,mng_info->loop_jump[loop_level],
5010 ThrowReaderException(CorruptImageError,
5011 "ImproperImageHeader");
5022 mng_info->loop_active[loop_level]=0;
5024 for (i=0; i < loop_level; i++)
5025 if (mng_info->loop_active[i] == 1)
5026 last_level=(short) i;
5027 loop_level=last_level;
5032 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5036 if (memcmp(type,mng_CLON,4) == 0)
5038 if (mng_info->clon_warning == 0)
5039 (void) ThrowMagickException(&image->exception,GetMagickModule(),
5040 CoderError,"CLON is not implemented yet","`%s'",
5043 mng_info->clon_warning++;
5046 if (memcmp(type,mng_MAGN,4) == 0)
5061 magn_first=(p[0] << 8) | p[1];
5067 magn_last=(p[2] << 8) | p[3];
5070 magn_last=magn_first;
5071 #ifndef MNG_OBJECT_BUFFERS
5072 if (magn_first || magn_last)
5073 if (mng_info->magn_warning == 0)
5075 (void) ThrowMagickException(&image->exception,
5076 GetMagickModule(),CoderError,
5077 "MAGN is not implemented yet for nonzero objects",
5078 "`%s'",image->filename);
5080 mng_info->magn_warning++;
5090 magn_mx=(p[5] << 8) | p[6];
5099 magn_my=(p[7] << 8) | p[8];
5108 magn_ml=(p[9] << 8) | p[10];
5117 magn_mr=(p[11] << 8) | p[12];
5126 magn_mt=(p[13] << 8) | p[14];
5135 magn_mb=(p[15] << 8) | p[16];
5147 magn_methy=magn_methx;
5150 if (magn_methx > 5 || magn_methy > 5)
5151 if (mng_info->magn_warning == 0)
5153 (void) ThrowMagickException(&image->exception,
5154 GetMagickModule(),CoderError,
5155 "Unknown MAGN method in MNG datastream","`%s'",
5158 mng_info->magn_warning++;
5160 #ifdef MNG_OBJECT_BUFFERS
5161 /* Magnify existing objects in the range magn_first to magn_last */
5163 if (magn_first == 0 || magn_last == 0)
5165 /* Save the magnification factors for object 0 */
5166 mng_info->magn_mb=magn_mb;
5167 mng_info->magn_ml=magn_ml;
5168 mng_info->magn_mr=magn_mr;
5169 mng_info->magn_mt=magn_mt;
5170 mng_info->magn_mx=magn_mx;
5171 mng_info->magn_my=magn_my;
5172 mng_info->magn_methx=magn_methx;
5173 mng_info->magn_methy=magn_methy;
5177 if (memcmp(type,mng_PAST,4) == 0)
5179 if (mng_info->past_warning == 0)
5180 (void) ThrowMagickException(&image->exception,GetMagickModule(),
5181 CoderError,"PAST is not implemented yet","`%s'",
5184 mng_info->past_warning++;
5187 if (memcmp(type,mng_SHOW,4) == 0)
5189 if (mng_info->show_warning == 0)
5190 (void) ThrowMagickException(&image->exception,GetMagickModule(),
5191 CoderError,"SHOW is not implemented yet","`%s'",
5194 mng_info->show_warning++;
5197 if (memcmp(type,mng_sBIT,4) == 0)
5200 mng_info->have_global_sbit=MagickFalse;
5204 mng_info->global_sbit.gray=p[0];
5205 mng_info->global_sbit.red=p[0];
5206 mng_info->global_sbit.green=p[1];
5207 mng_info->global_sbit.blue=p[2];
5208 mng_info->global_sbit.alpha=p[3];
5209 mng_info->have_global_sbit=MagickTrue;
5212 if (memcmp(type,mng_pHYs,4) == 0)
5216 mng_info->global_x_pixels_per_unit=
5217 (size_t) mng_get_long(p);
5218 mng_info->global_y_pixels_per_unit=
5219 (size_t) mng_get_long(&p[4]);
5220 mng_info->global_phys_unit_type=p[8];
5221 mng_info->have_global_phys=MagickTrue;
5225 mng_info->have_global_phys=MagickFalse;
5227 if (memcmp(type,mng_pHYg,4) == 0)
5229 if (mng_info->phyg_warning == 0)
5230 (void) ThrowMagickException(&image->exception,GetMagickModule(),
5231 CoderError,"pHYg is not implemented.","`%s'",image->filename);
5233 mng_info->phyg_warning++;
5235 if (memcmp(type,mng_BASI,4) == 0)
5237 skip_to_iend=MagickTrue;
5239 if (mng_info->basi_warning == 0)
5240 (void) ThrowMagickException(&image->exception,GetMagickModule(),
5241 CoderError,"BASI is not implemented yet","`%s'",
5244 mng_info->basi_warning++;
5245 #ifdef MNG_BASI_SUPPORTED
5246 basi_width=(size_t) ((p[0] << 24) | (p[1] << 16) |
5247 (p[2] << 8) | p[3]);
5248 basi_height=(size_t) ((p[4] << 24) | (p[5] << 16) |
5249 (p[6] << 8) | p[7]);
5250 basi_color_type=p[8];
5251 basi_compression_method=p[9];
5252 basi_filter_type=p[10];
5253 basi_interlace_method=p[11];
5255 basi_red=(p[12] << 8) & p[13];
5261 basi_green=(p[14] << 8) & p[15];
5267 basi_blue=(p[16] << 8) & p[17];
5273 basi_alpha=(p[18] << 8) & p[19];
5277 if (basi_sample_depth == 16)
5284 basi_viewable=p[20];
5290 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5294 if (memcmp(type,mng_IHDR,4)
5295 #if defined(JNG_SUPPORTED)
5296 && memcmp(type,mng_JHDR,4)
5300 /* Not an IHDR or JHDR chunk */
5302 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5307 if (logging != MagickFalse)
5308 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5309 " Processing %c%c%c%c chunk",type[0],type[1],type[2],type[3]);
5311 mng_info->exists[object_id]=MagickTrue;
5312 mng_info->viewable[object_id]=MagickTrue;
5314 if (mng_info->invisible[object_id])
5316 if (logging != MagickFalse)
5317 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5318 " Skipping invisible object");
5320 skip_to_iend=MagickTrue;
5321 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5324 #if defined(MNG_INSERT_LAYERS)
5326 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
5328 image_width=(size_t) mng_get_long(p);
5329 image_height=(size_t) mng_get_long(&p[4]);
5331 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5334 Insert a transparent background layer behind the entire animation
5335 if it is not full screen.
5337 #if defined(MNG_INSERT_LAYERS)
5338 if (insert_layers && mng_type && first_mng_object)
5340 if ((mng_info->clip.left > 0) || (mng_info->clip.top > 0) ||
5341 (image_width < mng_info->mng_width) ||
5342 (mng_info->clip.right < (ssize_t) mng_info->mng_width) ||
5343 (image_height < mng_info->mng_height) ||
5344 (mng_info->clip.bottom < (ssize_t) mng_info->mng_height))
5346 if (GetAuthenticPixelQueue(image) != (PixelPacket *) NULL)
5349 Allocate next image structure.
5351 AcquireNextImage(image_info,image);
5353 if (GetNextImageInList(image) == (Image *) NULL)
5355 image=DestroyImageList(image);
5356 MngInfoFreeStruct(mng_info,&have_mng_structure);
5357 return((Image *) NULL);
5360 image=SyncNextImageInList(image);
5362 mng_info->image=image;
5364 if (term_chunk_found)
5366 image->start_loop=MagickTrue;
5367 image->iterations=mng_iterations;
5368 term_chunk_found=MagickFalse;
5372 image->start_loop=MagickFalse;
5374 /* Make a background rectangle. */
5377 image->columns=mng_info->mng_width;
5378 image->rows=mng_info->mng_height;
5379 image->page.width=mng_info->mng_width;
5380 image->page.height=mng_info->mng_height;
5383 image->background_color=mng_background_color;
5384 (void) SetImageBackgroundColor(image);
5385 if (logging != MagickFalse)
5386 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5387 " Inserted transparent background layer, W=%.20g, H=%.20g",
5388 (double) mng_info->mng_width,(double) mng_info->mng_height);
5392 Insert a background layer behind the upcoming image if
5393 framing_mode is 3, and we haven't already inserted one.
5395 if (insert_layers && (mng_info->framing_mode == 3) &&
5396 (subframe_width) && (subframe_height) && (simplicity == 0 ||
5397 (simplicity & 0x08)))
5399 if (GetAuthenticPixelQueue(image) != (PixelPacket *) NULL)
5402 Allocate next image structure.
5404 AcquireNextImage(image_info,image);
5406 if (GetNextImageInList(image) == (Image *) NULL)
5408 image=DestroyImageList(image);
5409 MngInfoFreeStruct(mng_info,&have_mng_structure);
5410 return((Image *) NULL);
5413 image=SyncNextImageInList(image);
5416 mng_info->image=image;
5418 if (term_chunk_found)
5420 image->start_loop=MagickTrue;
5421 image->iterations=mng_iterations;
5422 term_chunk_found=MagickFalse;
5426 image->start_loop=MagickFalse;
5429 image->columns=subframe_width;
5430 image->rows=subframe_height;
5431 image->page.width=subframe_width;
5432 image->page.height=subframe_height;
5433 image->page.x=mng_info->clip.left;
5434 image->page.y=mng_info->clip.top;
5435 image->background_color=mng_background_color;
5436 image->matte=MagickFalse;
5437 (void) SetImageBackgroundColor(image);
5439 if (logging != MagickFalse)
5440 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5441 " Insert background layer, L=%.20g, R=%.20g T=%.20g, B=%.20g",
5442 (double) mng_info->clip.left,(double) mng_info->clip.right,
5443 (double) mng_info->clip.top,(double) mng_info->clip.bottom);
5445 #endif /* MNG_INSERT_LAYERS */
5446 first_mng_object=MagickFalse;
5448 if (GetAuthenticPixelQueue(image) != (PixelPacket *) NULL)
5451 Allocate next image structure.
5453 AcquireNextImage(image_info,image);
5455 if (GetNextImageInList(image) == (Image *) NULL)
5457 image=DestroyImageList(image);
5458 MngInfoFreeStruct(mng_info,&have_mng_structure);
5459 return((Image *) NULL);
5462 image=SyncNextImageInList(image);
5464 mng_info->image=image;
5465 status=SetImageProgress(image,LoadImagesTag,TellBlob(image),
5466 GetBlobSize(image));
5468 if (status == MagickFalse)
5471 if (term_chunk_found)
5473 image->start_loop=MagickTrue;
5474 term_chunk_found=MagickFalse;
5478 image->start_loop=MagickFalse;
5480 if (mng_info->framing_mode == 1 || mng_info->framing_mode == 3)
5482 image->delay=frame_delay;
5483 frame_delay=default_frame_delay;
5489 image->page.width=mng_info->mng_width;
5490 image->page.height=mng_info->mng_height;
5491 image->page.x=mng_info->x_off[object_id];
5492 image->page.y=mng_info->y_off[object_id];
5493 image->iterations=mng_iterations;
5496 Seek back to the beginning of the IHDR or JHDR chunk's length field.
5499 if (logging != MagickFalse)
5500 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5501 " Seeking back to beginning of %c%c%c%c chunk",type[0],type[1],
5504 offset=SeekBlob(image,-((ssize_t) length+12),SEEK_CUR);
5507 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
5511 mng_info->image=image;
5512 mng_info->mng_type=mng_type;
5513 mng_info->object_id=object_id;
5515 if (memcmp(type,mng_IHDR,4) == 0)
5516 image=ReadOnePNGImage(mng_info,image_info,exception);
5518 #if defined(JNG_SUPPORTED)
5520 image=ReadOneJNGImage(mng_info,image_info,exception);
5523 if (image == (Image *) NULL)
5525 if (IsImageObject(previous) != MagickFalse)
5527 (void) DestroyImageList(previous);
5528 (void) CloseBlob(previous);
5531 MngInfoFreeStruct(mng_info,&have_mng_structure);
5532 return((Image *) NULL);
5535 if (image->columns == 0 || image->rows == 0)
5537 (void) CloseBlob(image);
5538 image=DestroyImageList(image);
5539 MngInfoFreeStruct(mng_info,&have_mng_structure);
5540 return((Image *) NULL);
5543 mng_info->image=image;
5550 if (mng_info->magn_methx || mng_info->magn_methy)
5556 if (logging != MagickFalse)
5557 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5558 " Processing MNG MAGN chunk");
5560 if (mng_info->magn_methx == 1)
5562 magnified_width=mng_info->magn_ml;
5564 if (image->columns > 1)
5565 magnified_width += mng_info->magn_mr;
5567 if (image->columns > 2)
5568 magnified_width += (png_uint_32)
5569 ((image->columns-2)*(mng_info->magn_mx));
5574 magnified_width=(png_uint_32) image->columns;
5576 if (image->columns > 1)
5577 magnified_width += mng_info->magn_ml-1;
5579 if (image->columns > 2)
5580 magnified_width += mng_info->magn_mr-1;
5582 if (image->columns > 3)
5583 magnified_width += (png_uint_32)
5584 ((image->columns-3)*(mng_info->magn_mx-1));
5587 if (mng_info->magn_methy == 1)
5589 magnified_height=mng_info->magn_mt;
5591 if (image->rows > 1)
5592 magnified_height += mng_info->magn_mb;
5594 if (image->rows > 2)
5595 magnified_height += (png_uint_32)
5596 ((image->rows-2)*(mng_info->magn_my));
5601 magnified_height=(png_uint_32) image->rows;
5603 if (image->rows > 1)
5604 magnified_height += mng_info->magn_mt-1;
5606 if (image->rows > 2)
5607 magnified_height += mng_info->magn_mb-1;
5609 if (image->rows > 3)
5610 magnified_height += (png_uint_32)
5611 ((image->rows-3)*(mng_info->magn_my-1));
5614 if (magnified_height > image->rows ||
5615 magnified_width > image->columns)
5630 register PixelPacket
5642 /* Allocate next image structure. */
5644 if (logging != MagickFalse)
5645 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5646 " Allocate magnified image");
5648 AcquireNextImage(image_info,image);
5650 if (GetNextImageInList(image) == (Image *) NULL)
5652 image=DestroyImageList(image);
5653 MngInfoFreeStruct(mng_info,&have_mng_structure);
5654 return((Image *) NULL);
5657 large_image=SyncNextImageInList(image);
5659 large_image->columns=magnified_width;
5660 large_image->rows=magnified_height;
5662 magn_methx=mng_info->magn_methx;
5663 magn_methy=mng_info->magn_methy;
5665 #if (MAGICKCORE_QUANTUM_DEPTH == 32)
5666 #define QM unsigned short
5667 if (magn_methx != 1 || magn_methy != 1)
5670 Scale pixels to unsigned shorts to prevent
5671 overflow of intermediate values of interpolations
5673 for (y=0; y < (ssize_t) image->rows; y++)
5675 q=GetAuthenticPixels(image,0,y,image->columns,1,
5678 for (x=(ssize_t) image->columns-1; x >= 0; x--)
5680 q->red=ScaleQuantumToShort(q->red);
5681 q->green=ScaleQuantumToShort(q->green);
5682 q->blue=ScaleQuantumToShort(q->blue);
5683 q->opacity=ScaleQuantumToShort(q->opacity);
5687 if (SyncAuthenticPixels(image,exception) == MagickFalse)
5695 if (image->matte != MagickFalse)
5696 (void) SetImageBackgroundColor(large_image);
5700 large_image->background_color.opacity=OpaqueOpacity;
5701 (void) SetImageBackgroundColor(large_image);
5703 if (magn_methx == 4)
5706 if (magn_methx == 5)
5709 if (magn_methy == 4)
5712 if (magn_methy == 5)
5716 /* magnify the rows into the right side of the large image */
5718 if (logging != MagickFalse)
5719 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5720 " Magnify the rows to %.20g",(double) large_image->rows);
5721 m=(ssize_t) mng_info->magn_mt;
5723 length=(size_t) image->columns;
5724 next=(PixelPacket *) AcquireQuantumMemory(length,sizeof(*next));
5725 prev=(PixelPacket *) AcquireQuantumMemory(length,sizeof(*prev));
5727 if ((prev == (PixelPacket *) NULL) ||
5728 (next == (PixelPacket *) NULL))
5730 image=DestroyImageList(image);
5731 MngInfoFreeStruct(mng_info,&have_mng_structure);
5732 ThrowReaderException(ResourceLimitError,
5733 "MemoryAllocationFailed");
5736 n=GetAuthenticPixels(image,0,0,image->columns,1,exception);
5737 (void) CopyMagickMemory(next,n,length);
5739 for (y=0; y < (ssize_t) image->rows; y++)
5742 m=(ssize_t) mng_info->magn_mt;
5744 else if (magn_methy > 1 && y == (ssize_t) image->rows-2)
5745 m=(ssize_t) mng_info->magn_mb;
5747 else if (magn_methy <= 1 && y == (ssize_t) image->rows-1)
5748 m=(ssize_t) mng_info->magn_mb;
5750 else if (magn_methy > 1 && y == (ssize_t) image->rows-1)
5754 m=(ssize_t) mng_info->magn_my;
5760 if (y < (ssize_t) image->rows-1)
5762 n=GetAuthenticPixels(image,0,y+1,image->columns,1,
5764 (void) CopyMagickMemory(next,n,length);
5767 for (i=0; i < m; i++, yy++)
5769 register PixelPacket
5772 assert(yy < (ssize_t) large_image->rows);
5775 q=GetAuthenticPixels(large_image,0,yy,large_image->columns,
5777 q+=(large_image->columns-image->columns);
5779 for (x=(ssize_t) image->columns-1; x >= 0; x--)
5781 /* TO DO: get color as function of indexes[x] */
5783 if (image->storage_class == PseudoClass)
5788 if (magn_methy <= 1)
5790 *q=(*pixels); /* replicate previous */
5793 else if (magn_methy == 2 || magn_methy == 4)
5801 (*q).red=(QM) (((ssize_t) (2*i*((*n).red
5802 -(*pixels).red)+m))/((ssize_t) (m*2))
5804 (*q).green=(QM) (((ssize_t) (2*i*((*n).green
5805 -(*pixels).green)+m))/((ssize_t) (m*2))
5807 (*q).blue=(QM) (((ssize_t) (2*i*((*n).blue
5808 -(*pixels).blue)+m))/((ssize_t) (m*2))
5811 if (image->matte != MagickFalse)
5812 (*q).opacity=(QM) (((ssize_t)
5814 -(*pixels).opacity)+m))
5815 /((ssize_t) (m*2))+(*pixels).opacity);
5818 if (magn_methy == 4)
5820 /* Replicate nearest */
5821 if (i <= ((m+1) << 1))
5822 (*q).opacity=(*pixels).opacity+0;
5824 (*q).opacity=(*n).opacity+0;
5828 else /* if (magn_methy == 3 || magn_methy == 5) */
5830 /* Replicate nearest */
5831 if (i <= ((m+1) << 1))
5837 if (magn_methy == 5)
5839 (*q).opacity=(QM) (((ssize_t) (2*i*((*n).opacity
5840 -(*pixels).opacity)+m))/((ssize_t) (m*2))
5841 +(*pixels).opacity);
5849 if (SyncAuthenticPixels(large_image,exception) == 0)
5855 prev=(PixelPacket *) RelinquishMagickMemory(prev);
5856 next=(PixelPacket *) RelinquishMagickMemory(next);
5858 length=image->columns;
5860 if (logging != MagickFalse)
5861 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5862 " Delete original image");
5864 DeleteImageFromList(&image);
5868 mng_info->image=image;
5870 /* magnify the columns */
5871 if (logging != MagickFalse)
5872 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5873 " Magnify the columns to %.20g",(double) image->columns);
5875 for (y=0; y < (ssize_t) image->rows; y++)
5877 register PixelPacket
5880 q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
5881 pixels=q+(image->columns-length);
5884 for (x=(ssize_t) (image->columns-length);
5885 x < (ssize_t) image->columns; x++)
5887 if (x == (ssize_t) (image->columns-length))
5888 m=(ssize_t) mng_info->magn_ml;
5890 else if (magn_methx > 1 && x == (ssize_t) image->columns-2)
5891 m=(ssize_t) mng_info->magn_mr;
5893 else if (magn_methx <= 1 && x == (ssize_t) image->columns-1)
5894 m=(ssize_t) mng_info->magn_mr;
5896 else if (magn_methx > 1 && x == (ssize_t) image->columns-1)
5900 m=(ssize_t) mng_info->magn_mx;
5902 for (i=0; i < m; i++)
5904 if (magn_methx <= 1)
5906 /* replicate previous */
5910 else if (magn_methx == 2 || magn_methx == 4)
5918 (*q).red=(QM) ((2*i*((*n).red
5920 /((ssize_t) (m*2))+(*pixels).red);
5921 (*q).green=(QM) ((2*i*((*n).green
5923 +m)/((ssize_t) (m*2))+(*pixels).green);
5924 (*q).blue=(QM) ((2*i*((*n).blue
5926 /((ssize_t) (m*2))+(*pixels).blue);
5927 if (image->matte != MagickFalse)
5928 (*q).opacity=(QM) ((2*i*((*n).opacity
5929 -(*pixels).opacity)+m)/((ssize_t) (m*2))
5930 +(*pixels).opacity);
5933 if (magn_methx == 4)
5935 /* Replicate nearest */
5936 if (i <= ((m+1) << 1))
5937 (*q).opacity=(*pixels).opacity+0;
5939 (*q).opacity=(*n).opacity+0;
5943 else /* if (magn_methx == 3 || magn_methx == 5) */
5945 /* Replicate nearest */
5946 if (i <= ((m+1) << 1))
5952 if (magn_methx == 5)
5955 (*q).opacity=(QM) ((2*i*((*n).opacity
5956 -(*pixels).opacity)+m) /((ssize_t) (m*2))
5957 +(*pixels).opacity);
5966 if (SyncAuthenticPixels(image,exception) == MagickFalse)
5969 #if (MAGICKCORE_QUANTUM_DEPTH == 32)
5970 if (magn_methx != 1 || magn_methy != 1)
5973 Rescale pixels to Quantum
5975 for (y=0; y < (ssize_t) image->rows; y++)
5977 q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
5979 for (x=(ssize_t) image->columns-1; x >= 0; x--)
5981 q->red=ScaleShortToQuantum(q->red);
5982 q->green=ScaleShortToQuantum(q->green);
5983 q->blue=ScaleShortToQuantum(q->blue);
5984 q->opacity=ScaleShortToQuantum(q->opacity);
5988 if (SyncAuthenticPixels(image,exception) == MagickFalse)
5993 if (logging != MagickFalse)
5994 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5995 " Finished MAGN processing");
6000 Crop_box is with respect to the upper left corner of the MNG.
6002 crop_box.left=mng_info->image_box.left+mng_info->x_off[object_id];
6003 crop_box.right=mng_info->image_box.right+mng_info->x_off[object_id];
6004 crop_box.top=mng_info->image_box.top+mng_info->y_off[object_id];
6005 crop_box.bottom=mng_info->image_box.bottom+mng_info->y_off[object_id];
6006 crop_box=mng_minimum_box(crop_box,mng_info->clip);
6007 crop_box=mng_minimum_box(crop_box,mng_info->frame);
6008 crop_box=mng_minimum_box(crop_box,mng_info->object_clip[object_id]);
6009 if ((crop_box.left != (mng_info->image_box.left
6010 +mng_info->x_off[object_id])) ||
6011 (crop_box.right != (mng_info->image_box.right
6012 +mng_info->x_off[object_id])) ||
6013 (crop_box.top != (mng_info->image_box.top
6014 +mng_info->y_off[object_id])) ||
6015 (crop_box.bottom != (mng_info->image_box.bottom
6016 +mng_info->y_off[object_id])))
6018 if (logging != MagickFalse)
6019 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6020 " Crop the PNG image");
6022 if ((crop_box.left < crop_box.right) &&
6023 (crop_box.top < crop_box.bottom))
6032 Crop_info is with respect to the upper left corner of
6035 crop_info.x=(crop_box.left-mng_info->x_off[object_id]);
6036 crop_info.y=(crop_box.top-mng_info->y_off[object_id]);
6037 crop_info.width=(size_t) (crop_box.right-crop_box.left);
6038 crop_info.height=(size_t) (crop_box.bottom-crop_box.top);
6039 image->page.width=image->columns;
6040 image->page.height=image->rows;
6043 im=CropImage(image,&crop_info,exception);
6045 if (im != (Image *) NULL)
6047 image->columns=im->columns;
6048 image->rows=im->rows;
6049 im=DestroyImage(im);
6050 image->page.width=image->columns;
6051 image->page.height=image->rows;
6052 image->page.x=crop_box.left;
6053 image->page.y=crop_box.top;
6060 No pixels in crop area. The MNG spec still requires
6061 a layer, though, so make a single transparent pixel in
6062 the top left corner.
6067 (void) SetImageBackgroundColor(image);
6068 image->page.width=1;
6069 image->page.height=1;
6074 #ifndef PNG_READ_EMPTY_PLTE_SUPPORTED
6075 image=mng_info->image;
6079 #if (MAGICKCORE_QUANTUM_DEPTH > 16)
6080 /* PNG does not handle depths greater than 16 so reduce it even
6083 if (image->depth > 16)
6087 #if (MAGICKCORE_QUANTUM_DEPTH >= 16)
6088 if (LosslessReduceDepthOK(image) != MagickFalse)
6092 GetImageException(image,exception);
6094 if (image_info->number_scenes != 0)
6096 if (mng_info->scenes_found >
6097 (ssize_t) (image_info->first_scene+image_info->number_scenes))
6101 if (logging != MagickFalse)
6102 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6103 " Finished reading image datastream.");
6105 } while (LocaleCompare(image_info->magick,"MNG") == 0);
6107 (void) CloseBlob(image);
6109 if (logging != MagickFalse)
6110 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6111 " Finished reading all image datastreams.");
6113 #if defined(MNG_INSERT_LAYERS)
6114 if (insert_layers && !mng_info->image_found && (mng_info->mng_width) &&
6115 (mng_info->mng_height))
6118 Insert a background layer if nothing else was found.
6120 if (logging != MagickFalse)
6121 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6122 " No images found. Inserting a background layer.");
6124 if (GetAuthenticPixelQueue(image) != (PixelPacket *) NULL)
6127 Allocate next image structure.
6129 AcquireNextImage(image_info,image);
6130 if (GetNextImageInList(image) == (Image *) NULL)
6132 image=DestroyImageList(image);
6133 MngInfoFreeStruct(mng_info,&have_mng_structure);
6135 if (logging != MagickFalse)
6136 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6137 " Allocation failed, returning NULL.");
6139 return((Image *) NULL);
6141 image=SyncNextImageInList(image);
6143 image->columns=mng_info->mng_width;
6144 image->rows=mng_info->mng_height;
6145 image->page.width=mng_info->mng_width;
6146 image->page.height=mng_info->mng_height;
6149 image->background_color=mng_background_color;
6150 image->matte=MagickFalse;
6152 if (image_info->ping == MagickFalse)
6153 (void) SetImageBackgroundColor(image);
6155 mng_info->image_found++;
6158 image->iterations=mng_iterations;
6160 if (mng_iterations == 1)
6161 image->start_loop=MagickTrue;
6163 while (GetPreviousImageInList(image) != (Image *) NULL)
6166 if (image_count > 10*mng_info->image_found)
6168 if (logging != MagickFalse)
6169 (void) LogMagickEvent(CoderEvent,GetMagickModule()," No beginning");
6171 (void) ThrowMagickException(&image->exception,GetMagickModule(),
6172 CoderError,"Linked list is corrupted, beginning of list not found",
6173 "`%s'",image_info->filename);
6175 return((Image *) NULL);
6178 image=GetPreviousImageInList(image);
6180 if (GetNextImageInList(image) == (Image *) NULL)
6182 if (logging != MagickFalse)
6183 (void) LogMagickEvent(CoderEvent,GetMagickModule()," Corrupt list");
6185 (void) ThrowMagickException(&image->exception,GetMagickModule(),
6186 CoderError,"Linked list is corrupted; next_image is NULL","`%s'",
6187 image_info->filename);
6191 if (mng_info->ticks_per_second && mng_info->image_found > 1 &&
6192 GetNextImageInList(image) ==
6195 if (logging != MagickFalse)
6196 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6197 " First image null");
6199 (void) ThrowMagickException(&image->exception,GetMagickModule(),
6200 CoderError,"image->next for first image is NULL but shouldn't be.",
6201 "`%s'",image_info->filename);
6204 if (mng_info->image_found == 0)
6206 if (logging != MagickFalse)
6207 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6208 " No visible images found.");
6210 (void) ThrowMagickException(&image->exception,GetMagickModule(),
6211 CoderError,"No visible images in file","`%s'",image_info->filename);
6213 if (image != (Image *) NULL)
6214 image=DestroyImageList(image);
6216 MngInfoFreeStruct(mng_info,&have_mng_structure);
6217 return((Image *) NULL);
6220 if (mng_info->ticks_per_second)
6221 final_delay=1UL*MagickMax(image->ticks_per_second,1L)*
6222 final_delay/mng_info->ticks_per_second;
6225 image->start_loop=MagickTrue;
6227 /* Find final nonzero image delay */
6228 final_image_delay=0;
6230 while (GetNextImageInList(image) != (Image *) NULL)
6233 final_image_delay=image->delay;
6235 image=GetNextImageInList(image);
6238 if (final_delay < final_image_delay)
6239 final_delay=final_image_delay;
6241 image->delay=final_delay;
6243 if (logging != MagickFalse)
6244 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6245 " image->delay=%.20g, final_delay=%.20g",(double) image->delay,
6246 (double) final_delay);
6248 if (logging != MagickFalse)
6254 image=GetFirstImageInList(image);
6256 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6257 " Before coalesce:");
6259 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6260 " scene 0 delay=%.20g",(double) image->delay);
6262 while (GetNextImageInList(image) != (Image *) NULL)
6264 image=GetNextImageInList(image);
6265 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6266 " scene %.20g delay=%.20g",(double) scene++,(double) image->delay);
6270 image=GetFirstImageInList(image);
6271 #ifdef MNG_COALESCE_LAYERS
6281 if (logging != MagickFalse)
6282 (void) LogMagickEvent(CoderEvent,GetMagickModule()," Coalesce Images");
6285 next_image=CoalesceImages(image,&image->exception);
6287 if (next_image == (Image *) NULL)
6288 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
6290 image=DestroyImageList(image);
6293 for (next=image; next != (Image *) NULL; next=next_image)
6295 next->page.width=mng_info->mng_width;
6296 next->page.height=mng_info->mng_height;
6299 next->scene=scene++;
6300 next_image=GetNextImageInList(next);
6302 if (next_image == (Image *) NULL)
6305 if (next->delay == 0)
6308 next_image->previous=GetPreviousImageInList(next);
6309 if (GetPreviousImageInList(next) == (Image *) NULL)
6312 next->previous->next=next_image;
6313 next=DestroyImage(next);
6319 while (GetNextImageInList(image) != (Image *) NULL)
6320 image=GetNextImageInList(image);
6322 image->dispose=BackgroundDispose;
6324 if (logging != MagickFalse)
6330 image=GetFirstImageInList(image);
6332 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6333 " After coalesce:");
6335 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6336 " scene 0 delay=%.20g dispose=%.20g",(double) image->delay,
6337 (double) image->dispose);
6339 while (GetNextImageInList(image) != (Image *) NULL)
6341 image=GetNextImageInList(image);
6343 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6344 " scene %.20g delay=%.20g dispose=%.20g",(double) scene++,
6345 (double) image->delay,(double) image->dispose);
6349 image=GetFirstImageInList(image);
6350 MngInfoFreeStruct(mng_info,&have_mng_structure);
6351 have_mng_structure=MagickFalse;
6353 if (logging != MagickFalse)
6354 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"exit ReadMNGImage()");
6356 return(GetFirstImageInList(image));
6358 #else /* PNG_LIBPNG_VER > 10011 */
6359 static Image *ReadPNGImage(const ImageInfo *image_info,ExceptionInfo *exception)
6361 printf("Your PNG library is too old: You have libpng-%s\n",
6362 PNG_LIBPNG_VER_STRING);
6364 (void) ThrowMagickException(exception,GetMagickModule(),CoderError,
6365 "PNG library is too old","`%s'",image_info->filename);
6367 return(Image *) NULL;
6370 static Image *ReadMNGImage(const ImageInfo *image_info,ExceptionInfo *exception)
6372 return(ReadPNGImage(image_info,exception));
6374 #endif /* PNG_LIBPNG_VER > 10011 */
6378 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6382 % R e g i s t e r P N G I m a g e %
6386 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6388 % RegisterPNGImage() adds properties for the PNG image format to
6389 % the list of supported formats. The properties include the image format
6390 % tag, a method to read and/or write the format, whether the format
6391 % supports the saving of more than one frame to the same file or blob,
6392 % whether the format supports native in-memory I/O, and a brief
6393 % description of the format.
6395 % The format of the RegisterPNGImage method is:
6397 % size_t RegisterPNGImage(void)
6400 ModuleExport size_t RegisterPNGImage(void)
6403 version[MaxTextExtent];
6411 "See http://www.libpng.org/ for details about the PNG format."
6416 "See http://www.libpng.org/pub/mng/ for details about the JNG\n"
6422 "See http://www.libpng.org/pub/mng/ for details about the MNG\n"
6428 #if defined(PNG_LIBPNG_VER_STRING)
6429 (void) ConcatenateMagickString(version,"libpng ",MaxTextExtent);
6430 (void) ConcatenateMagickString(version,PNG_LIBPNG_VER_STRING,MaxTextExtent);
6432 if (LocaleCompare(PNG_LIBPNG_VER_STRING,png_get_header_ver(NULL)) != 0)
6434 (void) ConcatenateMagickString(version,",",MaxTextExtent);
6435 (void) ConcatenateMagickString(version,png_get_libpng_ver(NULL),
6440 entry=SetMagickInfo("MNG");
6441 entry->seekable_stream=MagickTrue; /* To do: eliminate this. */
6443 #if defined(MAGICKCORE_PNG_DELEGATE)
6444 entry->decoder=(DecodeImageHandler *) ReadMNGImage;
6445 entry->encoder=(EncodeImageHandler *) WriteMNGImage;
6448 entry->magick=(IsImageFormatHandler *) IsMNG;
6449 entry->description=ConstantString("Multiple-image Network Graphics");
6451 if (*version != '\0')
6452 entry->version=ConstantString(version);
6454 entry->module=ConstantString("PNG");
6455 entry->note=ConstantString(MNGNote);
6456 (void) RegisterMagickInfo(entry);
6458 entry=SetMagickInfo("PNG");
6460 #if defined(MAGICKCORE_PNG_DELEGATE)
6461 entry->decoder=(DecodeImageHandler *) ReadPNGImage;
6462 entry->encoder=(EncodeImageHandler *) WritePNGImage;
6465 entry->magick=(IsImageFormatHandler *) IsPNG;
6466 entry->adjoin=MagickFalse;
6467 entry->description=ConstantString("Portable Network Graphics");
6468 entry->module=ConstantString("PNG");
6470 if (*version != '\0')
6471 entry->version=ConstantString(version);
6473 entry->note=ConstantString(PNGNote);
6474 (void) RegisterMagickInfo(entry);
6476 entry=SetMagickInfo("PNG8");
6478 #if defined(MAGICKCORE_PNG_DELEGATE)
6479 entry->decoder=(DecodeImageHandler *) ReadPNGImage;
6480 entry->encoder=(EncodeImageHandler *) WritePNGImage;
6483 entry->magick=(IsImageFormatHandler *) IsPNG;
6484 entry->adjoin=MagickFalse;
6485 entry->description=ConstantString(
6486 "8-bit indexed with optional binary transparency");
6487 entry->module=ConstantString("PNG");
6488 (void) RegisterMagickInfo(entry);
6490 entry=SetMagickInfo("PNG24");
6493 #if defined(ZLIB_VERSION)
6494 (void) ConcatenateMagickString(version,"zlib ",MaxTextExtent);
6495 (void) ConcatenateMagickString(version,ZLIB_VERSION,MaxTextExtent);
6497 if (LocaleCompare(ZLIB_VERSION,zlib_version) != 0)
6499 (void) ConcatenateMagickString(version,",",MaxTextExtent);
6500 (void) ConcatenateMagickString(version,zlib_version,MaxTextExtent);
6504 if (*version != '\0')
6505 entry->version=ConstantString(version);
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 24-bit RGB");
6515 entry->module=ConstantString("PNG");
6516 (void) RegisterMagickInfo(entry);
6518 entry=SetMagickInfo("PNG32");
6520 #if defined(MAGICKCORE_PNG_DELEGATE)
6521 entry->decoder=(DecodeImageHandler *) ReadPNGImage;
6522 entry->encoder=(EncodeImageHandler *) WritePNGImage;
6525 entry->magick=(IsImageFormatHandler *) IsPNG;
6526 entry->adjoin=MagickFalse;
6527 entry->description=ConstantString("opaque or transparent 32-bit RGBA");
6528 entry->module=ConstantString("PNG");
6529 (void) RegisterMagickInfo(entry);
6531 entry=SetMagickInfo("JNG");
6533 #if defined(JNG_SUPPORTED)
6534 #if defined(MAGICKCORE_PNG_DELEGATE)
6535 entry->decoder=(DecodeImageHandler *) ReadJNGImage;
6536 entry->encoder=(EncodeImageHandler *) WriteJNGImage;
6540 entry->magick=(IsImageFormatHandler *) IsJNG;
6541 entry->adjoin=MagickFalse;
6542 entry->description=ConstantString("JPEG Network Graphics");
6543 entry->module=ConstantString("PNG");
6544 entry->note=ConstantString(JNGNote);
6545 (void) RegisterMagickInfo(entry);
6547 #if defined(PNG_SETJMP_NOT_THREAD_SAFE)
6548 ping_semaphore=AllocateSemaphoreInfo();
6551 return(MagickImageCoderSignature);
6555 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6559 % U n r e g i s t e r P N G I m a g e %
6563 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6565 % UnregisterPNGImage() removes format registrations made by the
6566 % PNG module from the list of supported formats.
6568 % The format of the UnregisterPNGImage method is:
6570 % UnregisterPNGImage(void)
6573 ModuleExport void UnregisterPNGImage(void)
6575 (void) UnregisterMagickInfo("MNG");
6576 (void) UnregisterMagickInfo("PNG");
6577 (void) UnregisterMagickInfo("PNG8");
6578 (void) UnregisterMagickInfo("PNG24");
6579 (void) UnregisterMagickInfo("PNG32");
6580 (void) UnregisterMagickInfo("JNG");
6582 #if defined(PNG_SETJMP_NOT_THREAD_SAFE)
6583 if (ping_semaphore != (SemaphoreInfo *) NULL)
6584 DestroySemaphoreInfo(&ping_semaphore);
6588 #if defined(MAGICKCORE_PNG_DELEGATE)
6589 #if PNG_LIBPNG_VER > 10011
6591 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6595 % W r i t e M N G I m a g e %
6599 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6601 % WriteMNGImage() writes an image in the Portable Network Graphics
6602 % Group's "Multiple-image Network Graphics" encoded image format.
6604 % MNG support written by Glenn Randers-Pehrson, glennrp@image...
6606 % The format of the WriteMNGImage method is:
6608 % MagickBooleanType WriteMNGImage(const ImageInfo *image_info,Image *image)
6610 % A description of each parameter follows.
6612 % o image_info: the image info.
6614 % o image: The image.
6617 % To do (as of version 5.5.2, November 26, 2002 -- glennrp -- see also
6618 % "To do" under ReadPNGImage):
6620 % Preserve all unknown and not-yet-handled known chunks found in input
6621 % PNG file and copy them into output PNG files according to the PNG
6624 % Write the iCCP chunk at MNG level when (icc profile length > 0)
6626 % Improve selection of color type (use indexed-colour or indexed-colour
6627 % with tRNS when 256 or fewer unique RGBA values are present).
6629 % Figure out what to do with "dispose=<restore-to-previous>" (dispose == 3)
6630 % This will be complicated if we limit ourselves to generating MNG-LC
6631 % files. For now we ignore disposal method 3 and simply overlay the next
6634 % Check for identical PLTE's or PLTE/tRNS combinations and use a
6635 % global MNG PLTE or PLTE/tRNS combination when appropriate.
6636 % [mostly done 15 June 1999 but still need to take care of tRNS]
6638 % Check for identical sRGB and replace with a global sRGB (and remove
6639 % gAMA/cHRM if sRGB is found; check for identical gAMA/cHRM and
6640 % replace with global gAMA/cHRM (or with sRGB if appropriate; replace
6641 % local gAMA/cHRM with local sRGB if appropriate).
6643 % Check for identical sBIT chunks and write global ones.
6645 % Provide option to skip writing the signature tEXt chunks.
6647 % Use signatures to detect identical objects and reuse the first
6648 % instance of such objects instead of writing duplicate objects.
6650 % Use a smaller-than-32k value of compression window size when
6653 % Encode JNG datastreams. Mostly done as of 5.5.2; need to write
6654 % ancillary text chunks and save profiles.
6656 % Provide an option to force LC files (to ensure exact framing rate)
6659 % Provide an option to force VLC files instead of LC, even when offsets
6660 % are present. This will involve expanding the embedded images with a
6661 % transparent region at the top and/or left.
6665 Magick_png_write_raw_profile(const ImageInfo *image_info,png_struct *ping,
6666 png_info *ping_info, unsigned char *profile_type, unsigned char
6667 *profile_description, unsigned char *profile_data, png_uint_32 length)
6686 hex[16]={'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
6688 if (LocaleNCompare((char *) profile_type+1, "ng-chunk-",9) == 0)
6691 if (image_info->verbose)
6693 (void) printf("writing raw profile: type=%s, length=%.20g\n",
6694 (char *) profile_type, (double) length);
6697 text=(png_textp) png_malloc(ping,(png_uint_32) sizeof(png_text));
6698 description_length=(png_uint_32) strlen((const char *) profile_description);
6699 allocated_length=(png_uint_32) (length*2 + (length >> 5) + 20
6700 + description_length);
6701 text[0].text=(png_charp) png_malloc(ping,allocated_length);
6702 text[0].key=(png_charp) png_malloc(ping, (png_uint_32) 80);
6703 text[0].key[0]='\0';
6704 (void) ConcatenateMagickString(text[0].key,
6705 "Raw profile type ",MaxTextExtent);
6706 (void) ConcatenateMagickString(text[0].key,(const char *) profile_type,62);
6710 (void) CopyMagickString(dp,(const char *) profile_description,
6712 dp+=description_length;
6714 (void) FormatMagickString(dp,allocated_length-
6715 (png_size_t) (dp-text[0].text),"%8lu ",(unsigned long) length);
6718 for (i=0; i < (ssize_t) length; i++)
6722 *(dp++)=(char) hex[((*sp >> 4) & 0x0f)];
6723 *(dp++)=(char) hex[((*sp++ ) & 0x0f)];
6728 text[0].text_length=(png_size_t) (dp-text[0].text);
6729 text[0].compression=image_info->compression == NoCompression ||
6730 (image_info->compression == UndefinedCompression &&
6731 text[0].text_length < 128) ? -1 : 0;
6733 if (text[0].text_length <= allocated_length)
6734 png_set_text(ping,ping_info,text,1);
6736 png_free(ping,text[0].text);
6737 png_free(ping,text[0].key);
6738 png_free(ping,text);
6741 static MagickBooleanType Magick_png_write_chunk_from_profile(Image *image,
6742 const char *string, MagickBooleanType logging)
6755 ResetImageProfileIterator(image);
6757 for (name=GetNextImageProfile(image); name != (const char *) NULL; )
6759 profile=GetImageProfile(image,name);
6761 if (profile != (const StringInfo *) NULL)
6766 if (LocaleNCompare(name,string,11) == 0)
6768 if (logging != MagickFalse)
6769 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6770 " Found %s profile",name);
6772 ping_profile=CloneStringInfo(profile);
6773 data=GetStringInfoDatum(ping_profile),
6774 length=(png_uint_32) GetStringInfoLength(ping_profile);
6779 (void) WriteBlobMSBULong(image,length-5); /* data length */
6780 (void) WriteBlob(image,length-1,data+1);
6781 (void) WriteBlobMSBULong(image,crc32(0,data+1,(uInt) length-1));
6782 ping_profile=DestroyStringInfo(ping_profile);
6786 name=GetNextImageProfile(image);
6793 /* Write one PNG image */
6794 static MagickBooleanType WriteOnePNGImage(MngInfo *mng_info,
6795 const ImageInfo *IMimage_info,Image *IMimage)
6819 ping_trans_alpha[256];
6854 /* ping_exclude_EXIF, */
6857 /* ping_exclude_iTXt, */
6862 /* ping_exclude_tRNS, */
6864 ping_exclude_zCCP, /* hex-encoded iCCP */
6867 ping_need_colortype_warning,
6885 ping_interlace_method,
6886 ping_compression_method,
6902 number_semitransparent,
6904 ping_pHYs_unit_type;
6907 ping_pHYs_x_resolution,
6908 ping_pHYs_y_resolution;
6910 logging=LogMagickEvent(CoderEvent,GetMagickModule(),
6911 " enter WriteOnePNGImage()");
6913 image = CloneImage(IMimage,0,0,MagickFalse,&IMimage->exception);
6914 image_info=(ImageInfo *) CloneImageInfo(IMimage_info);
6916 if (mng_info->need_blob != MagickFalse)
6918 if (OpenBlob(image_info,image,WriteBinaryBlobMode,&image->exception) ==
6921 image_info=DestroyImageInfo(image_info);
6922 image=DestroyImage(image);
6923 return(MagickFalse);
6927 #if defined(PNG_SETJMP_NOT_THREAD_SAFE)
6928 LockSemaphoreInfo(ping_semaphore);
6931 /* Initialize some stuff */
6934 ping_interlace_method=0,
6935 ping_compression_method=0,
6936 ping_filter_method=0,
6939 ping_background.red = 0;
6940 ping_background.green = 0;
6941 ping_background.blue = 0;
6942 ping_background.gray = 0;
6943 ping_background.index = 0;
6945 ping_trans_color.red=0;
6946 ping_trans_color.green=0;
6947 ping_trans_color.blue=0;
6948 ping_trans_color.gray=0;
6950 ping_pHYs_unit_type = 0;
6951 ping_pHYs_x_resolution = 0;
6952 ping_pHYs_y_resolution = 0;
6954 ping_have_color=MagickTrue;
6955 ping_have_PLTE=MagickFalse;
6956 ping_have_bKGD=MagickFalse;
6957 ping_have_pHYs=MagickFalse;
6958 ping_have_tRNS=MagickFalse;
6960 ping_exclude_bKGD=mng_info->ping_exclude_bKGD;
6961 ping_exclude_cHRM=mng_info->ping_exclude_cHRM;
6962 /* ping_exclude_EXIF=mng_info->ping_exclude_EXIF; */
6963 ping_exclude_gAMA=mng_info->ping_exclude_gAMA;
6964 ping_exclude_cHRM=mng_info->ping_exclude_cHRM;
6965 ping_exclude_iCCP=mng_info->ping_exclude_iCCP;
6966 /* ping_exclude_iTXt=mng_info->ping_exclude_iTXt; */
6967 ping_exclude_oFFs=mng_info->ping_exclude_oFFs;
6968 ping_exclude_pHYs=mng_info->ping_exclude_pHYs;
6969 ping_exclude_sRGB=mng_info->ping_exclude_sRGB;
6970 ping_exclude_tEXt=mng_info->ping_exclude_tEXt;
6971 /* ping_exclude_tRNS=mng_info->ping_exclude_tRNS; */
6972 ping_exclude_vpAg=mng_info->ping_exclude_vpAg;
6973 ping_exclude_zCCP=mng_info->ping_exclude_zCCP; /* hex-encoded iCCP in zTXt */
6974 ping_exclude_zTXt=mng_info->ping_exclude_zTXt;
6976 ping_need_colortype_warning = MagickFalse;
6979 number_semitransparent = 0;
6980 number_transparent = 0;
6982 if (image->colorspace != RGBColorspace)
6983 (void) TransformImageColorspace(image,RGBColorspace);
6986 Sometimes we get PseudoClass images whose RGB values don't match
6987 the colors in the colormap. This code syncs the RGB values.
6989 if (image->depth <= 8 && image->taint && image->storage_class == PseudoClass)
6990 (void) SyncImage(image);
6992 #if (MAGICKCORE_QUANTUM_DEPTH == 8)
6993 if (image->depth > 8)
6995 if (logging != MagickFalse)
6996 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6997 " Reducing PNG bit depth to 8 since this is a Q8 build.");
7004 #if (MAGICKCORE_QUANTUM_DEPTH > 16)
7005 /* PNG does not handle depths greater than 16 so reduce it even
7008 if (image->depth > 16)
7012 #if (MAGICKCORE_QUANTUM_DEPTH >= 16)
7013 if (image->depth == 16 && mng_info->write_png_colortype != 16)
7014 if (mng_info->write_png8 || LosslessReduceDepthOK(image) != MagickFalse)
7018 #ifdef BUILD_PNG_PALETTE
7019 if (mng_info->write_png_colortype < 8 /* all */)
7022 * Sometimes we get DirectClass images that have 256 colors or fewer.
7023 * This code will build a colormap.
7025 * Also, sometimes we get PseudoClass images with an out-of-date
7026 * colormap. This code will replace the colormap with a new one.
7027 * Sometimes we get PseudoClass images that have more than 256 colors.
7028 * This code will delete the colormap and change the image to
7031 * If image->matte is MagickFalse, we ignore the opacity channel
7032 * even though it sometimes contains left-over non-opaque values.
7034 * Also we gather some information (number of opaque, transparent,
7035 * and semitransparent pixels, and whether the image has any non-gray
7036 * pixels) that we might need later. If the user wants to force
7037 * GrayAlpha or RGBA (colortype 4 or 6) we probably don't need any
7049 semitransparent[260],
7052 register IndexPacket
7055 register const PixelPacket
7058 if (logging != MagickFalse)
7059 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7060 " Enter BUILD_PALETTE:");
7062 if (logging != MagickFalse)
7064 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7065 " image->columns=%.20g",(double) image->columns);
7066 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7067 " image->rows=%.20g",(double) image->rows);
7068 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7069 " image->matte=%.20g",(double) image->matte);
7070 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7071 " image->depth=%.20g",(double) image->depth);
7073 if (image->colormap != NULL)
7075 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7076 " Original colormap:");
7077 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7078 " i (red,green,blue,opacity)");
7080 for (i=0; i < 256; 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);
7091 for (i=image->colors - 10; i < (ssize_t) image->colors; i++)
7095 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7096 " %d (%d,%d,%d,%d)",
7098 (int) image->colormap[i].red,
7099 (int) image->colormap[i].green,
7100 (int) image->colormap[i].blue,
7101 (int) image->colormap[i].opacity);
7106 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7107 " image->colors=%d",(int) image->colors);
7109 if (image->colors == 0)
7110 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7111 " (zero means unknown)");
7113 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7114 " Regenerate the colormap");
7117 exception=(&image->exception);
7119 ping_have_color=MagickFalse;
7122 for (y=0; y < (ssize_t) image->rows; y++)
7124 q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
7126 if (q == (PixelPacket *) NULL)
7129 for (x=0; x < (ssize_t) image->columns; x++)
7131 if (q->red != q->green || q->red != q->blue)
7132 ping_have_color=MagickTrue;
7134 if (image->matte == MagickFalse || q->opacity == OpaqueOpacity)
7136 if (number_opaque < 259)
7138 if (number_opaque == 0)
7141 opaque[0].opacity=OpaqueOpacity;
7145 for (i=0; i< (ssize_t) number_opaque; i++)
7147 if (IsColorEqual(opaque+i, (PixelPacket *) q))
7151 if (i == (ssize_t) number_opaque &&
7152 number_opaque < 259)
7156 opaque[i].opacity = OpaqueOpacity;
7160 else if (q->opacity == TransparentOpacity)
7162 if (number_transparent < 259)
7164 if (number_transparent == 0)
7167 ping_trans_color.red=(unsigned short)(q->red);
7168 ping_trans_color.green=(unsigned short) (q->green);
7169 ping_trans_color.blue=(unsigned short) (q->blue);
7170 ping_trans_color.gray=(unsigned short) (q->blue);
7171 number_transparent = 1;
7174 for (i=0; i< (ssize_t) number_transparent; i++)
7176 if (IsColorEqual(transparent+i, (PixelPacket *) q))
7180 if (i == (ssize_t) number_transparent &&
7181 number_transparent < 259)
7183 number_transparent++;
7184 transparent[i] = *q;
7190 if (number_semitransparent < 259)
7192 if (number_semitransparent == 0)
7194 semitransparent[0]=*q;
7195 number_semitransparent = 1;
7198 for (i=0; i< (ssize_t) number_semitransparent; i++)
7200 if (IsColorEqual(semitransparent+i,
7201 (PixelPacket *) q) &&
7202 q->opacity == semitransparent[i].opacity)
7206 if (i == (ssize_t) number_semitransparent &&
7207 number_semitransparent < 259)
7209 number_semitransparent++;
7210 semitransparent[i] = *q;
7218 image_colors=number_opaque+number_transparent+number_semitransparent;
7220 if (logging != MagickFalse)
7222 if (image_colors > 256)
7223 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7224 " image has more than 256 colors");
7227 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7228 " image has %d colors",image_colors);
7231 if (image_colors < 257)
7237 Initialize image colormap.
7240 if (logging != MagickFalse)
7241 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7242 " Sort the new colormap");
7244 /* Sort palette, transparent first */;
7248 for (i=0; i<number_transparent; i++)
7249 colormap[n++] = transparent[i];
7251 for (i=0; i<number_semitransparent; i++)
7252 colormap[n++] = semitransparent[i];
7254 for (i=0; i<number_opaque; i++)
7255 colormap[n++] = opaque[i];
7257 if (ping_exclude_bKGD == MagickFalse)
7259 /* Add the background color to the palette, if it
7260 * isn't already there.
7262 for (i=0; i<number_opaque; i++)
7264 if (IsColorEqual(opaque+i,
7265 &image->background_color))
7269 if (number_opaque < 257 && i == number_opaque)
7271 opaque[i]=image->background_color;
7272 opaque[i].opacity = OpaqueOpacity;
7277 if ((mng_info->ping_exclude_tRNS == MagickFalse ||
7278 (number_transparent == 0 && number_semitransparent == 0)) &&
7279 (((mng_info->write_png_colortype-1) ==
7280 PNG_COLOR_TYPE_PALETTE) ||
7281 (mng_info->write_png_colortype == 0)))
7283 if (logging != MagickFalse)
7285 if (n != (ssize_t) image_colors)
7286 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7287 " image_colors (%d) and n (%d) don't match",
7290 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7291 " AcquireImageColormap");
7294 image->colors = image_colors;
7296 if (AcquireImageColormap(image,image_colors) ==
7298 ThrowWriterException(ResourceLimitError,
7299 "MemoryAllocationFailed");
7301 for (i=0; i< (ssize_t) image_colors; i++)
7302 image->colormap[i] = colormap[i];
7304 if (logging != MagickFalse)
7306 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7307 " image->colors=%d (%d)",
7308 (int) image->colors, image_colors);
7310 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7311 " Update the pixel indexes");
7314 for (y=0; y < (ssize_t) image->rows; y++)
7316 q=GetAuthenticPixels(image,0,y,image->columns,1,
7319 if (q == (PixelPacket *) NULL)
7322 indexes=GetAuthenticIndexQueue(image);
7324 for (x=0; x < (ssize_t) image->columns; x++)
7326 for (i=0; i< (ssize_t) image_colors; i++)
7328 if ((image->matte == MagickFalse ||
7329 image->colormap[i].opacity == q->opacity) &&
7330 (IsColorEqual(&image->colormap[i],(PixelPacket *) q)))
7332 indexes[x]=(IndexPacket) i;
7339 if (SyncAuthenticPixels(image,exception) == MagickFalse)
7345 if (logging != MagickFalse)
7347 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7348 " image->colors=%d", (int) image->colors);
7350 if (image->colormap != NULL)
7352 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7353 " i (red,green,blue,opacity)");
7355 for (i=0; i < (ssize_t) image->colors; i++)
7357 if (i < 300 || i >= image->colors - 10)
7359 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7360 " %d (%d,%d,%d,%d)",
7362 (int) image->colormap[i].red,
7363 (int) image->colormap[i].green,
7364 (int) image->colormap[i].blue,
7365 (int) image->colormap[i].opacity);
7370 if (logging != MagickFalse)
7372 if (number_transparent < 257)
7373 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7374 " number_transparent = %d",
7375 number_transparent);
7378 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7379 " number_transparent > 256");
7381 if (number_opaque < 257)
7382 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7383 " number_opaque = %d",
7386 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7387 " number_opaque > 256");
7389 if (number_semitransparent < 257)
7390 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7391 " number_semitransparent = %d",
7392 number_semitransparent);
7395 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7396 " number_semitransparent > 256");
7399 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7400 " Exit BUILD_PALETTE:");
7403 #endif /* BUILD_PNG_PALETTE */
7405 if (mng_info->ping_exclude_tRNS != MagickFalse &&
7406 (number_transparent != 0 || number_semitransparent != 0))
7408 int colortype=mng_info->write_png_colortype;
7410 if (ping_have_color == MagickFalse)
7411 mng_info->write_png_colortype = 5;
7414 mng_info->write_png_colortype = 7;
7416 if (colortype != 0 && mng_info->write_png_colortype != (ssize_t) colortype)
7417 ping_need_colortype_warning=MagickTrue;
7421 image_depth=image->depth;
7423 quantum_info = (QuantumInfo *) NULL;
7425 image_colors=(int) image->colors;
7426 image_matte=image->matte;
7428 mng_info->IsPalette=image->storage_class == PseudoClass &&
7429 image_colors <= 256;
7432 Allocate the PNG structures
7434 #ifdef PNG_USER_MEM_SUPPORTED
7435 ping=png_create_write_struct_2(PNG_LIBPNG_VER_STRING,image,
7436 MagickPNGErrorHandler,MagickPNGWarningHandler,(void *) NULL,
7437 (png_malloc_ptr) Magick_png_malloc,(png_free_ptr) Magick_png_free);
7440 ping=png_create_write_struct(PNG_LIBPNG_VER_STRING,image,
7441 MagickPNGErrorHandler,MagickPNGWarningHandler);
7444 if (ping == (png_struct *) NULL)
7445 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
7447 ping_info=png_create_info_struct(ping);
7449 if (ping_info == (png_info *) NULL)
7451 png_destroy_write_struct(&ping,(png_info **) NULL);
7452 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
7455 png_set_write_fn(ping,image,png_put_data,png_flush_data);
7456 ping_pixels=(unsigned char *) NULL;
7458 if (setjmp(png_jmpbuf(ping)))
7464 if (image_info->verbose)
7465 (void) printf("PNG write has failed.\n");
7467 png_destroy_write_struct(&ping,&ping_info);
7468 #if defined(PNG_SETJMP_NOT_THREAD_SAFE)
7469 UnlockSemaphoreInfo(ping_semaphore);
7471 if (mng_info->need_blob != MagickFalse)
7472 (void) CloseBlob(image);
7473 image_info=DestroyImageInfo(image_info);
7474 image=DestroyImage(image);
7475 return(MagickFalse);
7478 Prepare PNG for writing.
7480 #if defined(PNG_MNG_FEATURES_SUPPORTED)
7481 if (mng_info->write_mng)
7482 (void) png_permit_mng_features(ping,PNG_ALL_MNG_FEATURES);
7485 # ifdef PNG_WRITE_EMPTY_PLTE_SUPPORTED
7486 if (mng_info->write_mng)
7487 png_permit_empty_plte(ping,MagickTrue);
7494 ping_width=(png_uint_32) image->columns;
7495 ping_height=(png_uint_32) image->rows;
7497 if (mng_info->write_png8 || mng_info->write_png24 || mng_info->write_png32)
7500 if (mng_info->write_png_depth != 0)
7501 image_depth=mng_info->write_png_depth;
7503 /* Adjust requested depth to next higher valid depth if necessary */
7504 if (image_depth > 8)
7507 if ((image_depth > 4) && (image_depth < 8))
7510 if (image_depth == 3)
7513 if (logging != MagickFalse)
7515 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7516 " width=%.20g",(double) ping_width);
7517 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7518 " height=%.20g",(double) ping_height);
7519 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7520 " image_matte=%.20g",(double) image->matte);
7521 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7522 " image->depth=%.20g",(double) image->depth);
7523 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7524 " Tentative ping_bit_depth=%.20g",(double) image_depth);
7527 save_image_depth=image_depth;
7528 ping_bit_depth=(png_byte) save_image_depth;
7531 #if defined(PNG_pHYs_SUPPORTED)
7532 if (ping_exclude_pHYs == MagickFalse)
7534 if ((image->x_resolution != 0) && (image->y_resolution != 0) &&
7535 (!mng_info->write_mng || !mng_info->equal_physs))
7537 if (logging != MagickFalse)
7538 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7539 " Setting up pHYs chunk");
7541 if (image->units == PixelsPerInchResolution)
7543 ping_pHYs_unit_type=PNG_RESOLUTION_METER;
7544 ping_pHYs_x_resolution=(png_uint_32) (100.0*image->x_resolution/2.54);
7545 ping_pHYs_y_resolution=(png_uint_32) (100.0*image->y_resolution/2.54);
7548 else if (image->units == PixelsPerCentimeterResolution)
7550 ping_pHYs_unit_type=PNG_RESOLUTION_METER;
7551 ping_pHYs_x_resolution=(png_uint_32) (100.0*image->x_resolution);
7552 ping_pHYs_y_resolution=(png_uint_32) (100.0*image->y_resolution);
7557 ping_pHYs_unit_type=PNG_RESOLUTION_UNKNOWN;
7558 ping_pHYs_x_resolution=(png_uint_32) image->x_resolution;
7559 ping_pHYs_y_resolution=(png_uint_32) image->y_resolution;
7562 ping_have_pHYs = MagickTrue;
7567 if (ping_exclude_bKGD == MagickFalse)
7569 if ((!mng_info->adjoin || !mng_info->equal_backgrounds))
7575 if (ping_bit_depth == 8)
7578 if (ping_bit_depth == 4)
7581 if (ping_bit_depth == 2)
7584 if (ping_bit_depth == 1)
7587 ping_background.red=(png_uint_16)
7588 (ScaleQuantumToShort(image->background_color.red) & mask);
7590 ping_background.green=(png_uint_16)
7591 (ScaleQuantumToShort(image->background_color.green) & mask);
7593 ping_background.blue=(png_uint_16)
7594 (ScaleQuantumToShort(image->background_color.blue) & mask);
7597 if (logging != MagickFalse)
7599 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7600 " Setting up bKGD chunk (1)");
7602 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7603 " ping_bit_depth=%d",ping_bit_depth);
7606 ping_have_bKGD = MagickTrue;
7610 Select the color type.
7615 if (mng_info->write_png8)
7618 /* TO DO: make this a function cause it's used twice, except
7619 for reducing the sample depth from 8. */
7621 number_colors=image_colors;
7623 ping_have_tRNS=MagickFalse;
7628 ping_color_type=(png_byte) PNG_COLOR_TYPE_PALETTE;
7630 if (logging != MagickFalse)
7631 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7632 " Setting up PLTE chunk with %d colors (%d)",
7633 number_colors, image_colors);
7635 for (i=0; i < (ssize_t) number_colors; i++)
7637 palette[i].red=ScaleQuantumToChar(image->colormap[i].red);
7638 palette[i].green=ScaleQuantumToChar(image->colormap[i].green);
7639 palette[i].blue=ScaleQuantumToChar(image->colormap[i].blue);
7640 if (logging != MagickFalse)
7641 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7642 #if MAGICKCORE_QUANTUM_DEPTH == 8
7643 " %3ld (%3d,%3d,%3d)",
7645 " %5ld (%5d,%5d,%5d)",
7647 (long) i,palette[i].red,palette[i].green,palette[i].blue);
7651 ping_have_PLTE=MagickTrue;
7652 image_depth=ping_bit_depth;
7655 if (matte != MagickFalse)
7658 Identify which colormap entry is transparent.
7660 assert(number_colors <= 256);
7661 assert(image->colormap != NULL);
7663 for (i=0; i < (ssize_t) number_transparent; i++)
7664 ping_trans_alpha[i]=0;
7666 /* PNG8 can't have semitransparent colors so we threshold them
7669 for (; i < (ssize_t) number_semitransparent; i++)
7670 ping_trans_alpha[i]=image->colormap[i].opacity >
7671 OpaqueOpacity/2 ? 0 : 255;
7673 ping_num_trans=(unsigned short) (number_transparent +
7674 number_semitransparent);
7676 if (ping_num_trans == 0)
7677 ping_have_tRNS=MagickFalse;
7680 ping_have_tRNS=MagickTrue;
7683 if (ping_exclude_bKGD == MagickFalse)
7686 * Identify which colormap entry is the background color.
7688 for (i=0; i < (ssize_t) MagickMax(1L*number_colors-1L,1L); i++)
7689 if (IsPNGColorEqual(ping_background,image->colormap[i]))
7692 ping_background.index=(png_byte) i;
7694 } /* end of write_png8 */
7696 else if (mng_info->write_png24)
7698 image_matte=MagickFalse;
7699 ping_color_type=(png_byte) PNG_COLOR_TYPE_RGB;
7702 else if (mng_info->write_png32)
7704 image_matte=MagickTrue;
7705 ping_color_type=(png_byte) PNG_COLOR_TYPE_RGB_ALPHA;
7708 else /* mng_info->write_pngNN not specified */
7710 image_depth=ping_bit_depth;
7712 if (mng_info->write_png_colortype != 0)
7714 ping_color_type=(png_byte) mng_info->write_png_colortype-1;
7716 if (ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA ||
7717 ping_color_type == PNG_COLOR_TYPE_RGB_ALPHA)
7718 image_matte=MagickTrue;
7721 image_matte=MagickFalse;
7724 else /* write_ping_colortype not specified */
7726 if (logging != MagickFalse)
7727 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7728 " Selecting PNG colortype:");
7730 ping_color_type=(png_byte) ((matte != MagickFalse)?
7731 PNG_COLOR_TYPE_RGB_ALPHA:PNG_COLOR_TYPE_RGB);
7733 if (image_info->type == TrueColorType)
7735 ping_color_type=(png_byte) PNG_COLOR_TYPE_RGB;
7736 image_matte=MagickFalse;
7739 if (image_info->type == TrueColorMatteType)
7741 ping_color_type=(png_byte) PNG_COLOR_TYPE_RGB_ALPHA;
7742 image_matte=MagickTrue;
7745 if (image_info->type == PaletteType ||
7746 image_info->type == PaletteMatteType)
7747 ping_color_type=(png_byte) PNG_COLOR_TYPE_PALETTE;
7749 if (image_info->type == UndefinedType ||
7750 image_info->type == OptimizeType)
7752 if (ping_have_color == MagickFalse)
7754 if (image_matte == MagickFalse)
7756 ping_color_type=(png_byte) PNG_COLOR_TYPE_GRAY;
7757 image_matte=MagickFalse;
7762 ping_color_type=(png_byte) PNG_COLOR_TYPE_GRAY_ALPHA;
7763 image_matte=MagickTrue;
7768 if (image_matte == MagickFalse)
7770 ping_color_type=(png_byte) PNG_COLOR_TYPE_RGB;
7771 image_matte=MagickFalse;
7776 ping_color_type=(png_byte) PNG_COLOR_TYPE_RGBA;
7777 image_matte=MagickTrue;
7784 if (logging != MagickFalse)
7785 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7786 " Selected PNG colortype=%d",ping_color_type);
7788 if (ping_bit_depth < 8)
7790 if (ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA ||
7791 ping_color_type == PNG_COLOR_TYPE_RGB ||
7792 ping_color_type == PNG_COLOR_TYPE_RGB_ALPHA)
7796 old_bit_depth=ping_bit_depth;
7798 if (ping_color_type == PNG_COLOR_TYPE_GRAY)
7800 if (image->matte == MagickFalse && image->colors < 256)
7802 if (ImageIsMonochrome(image))
7809 if (ping_color_type == PNG_COLOR_TYPE_PALETTE)
7814 if (image->colors == 0)
7817 (void) ThrowMagickException(&image->exception,
7818 GetMagickModule(),CoderError,
7819 "image has 0 colors", "`%s'","");
7822 while ((int) (one << ping_bit_depth) < (ssize_t) image_colors)
7823 ping_bit_depth <<= 1;
7826 if (logging != MagickFalse)
7828 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7829 " Number of colors: %.20g",(double) image_colors);
7831 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7832 " Tentative PNG bit depth: %d",ping_bit_depth);
7835 if (ping_bit_depth < (int) mng_info->write_png_depth)
7836 ping_bit_depth = mng_info->write_png_depth;
7839 image_depth=ping_bit_depth;
7841 if (logging != MagickFalse)
7843 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7844 " Tentative PNG color type: %.20g",(double) ping_color_type);
7846 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7847 " image_info->type: %.20g",(double) image_info->type);
7849 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7850 " image_depth: %.20g",(double) image_depth);
7852 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7854 " image->depth: %.20g",(double) image->depth);
7856 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7857 " ping_bit_depth: %.20g",(double) ping_bit_depth);
7860 if (matte != MagickFalse)
7862 if (mng_info->IsPalette)
7865 ping_color_type=PNG_COLOR_TYPE_GRAY_ALPHA;
7867 if (ping_have_color != MagickFalse)
7868 ping_color_type=PNG_COLOR_TYPE_RGBA;
7871 * Determine if there is any transparent color.
7873 if (number_transparent + number_semitransparent == 0)
7876 No transparent pixels are present. Change 4 or 6 to 0 or 2.
7879 image_matte=MagickFalse;
7880 ping_color_type&=0x03;
7890 if (ping_bit_depth == 8)
7893 if (ping_bit_depth == 4)
7896 if (ping_bit_depth == 2)
7899 if (ping_bit_depth == 1)
7902 ping_trans_color.red=(png_uint_16)
7903 (ScaleQuantumToShort(image->colormap[0].red) & mask);
7905 ping_trans_color.green=(png_uint_16)
7906 (ScaleQuantumToShort(image->colormap[0].green) & mask);
7908 ping_trans_color.blue=(png_uint_16)
7909 (ScaleQuantumToShort(image->colormap[0].blue) & mask);
7911 ping_trans_color.gray=(png_uint_16)
7912 (ScaleQuantumToShort(PixelIntensityToQuantum(
7913 image->colormap)) & mask);
7915 ping_trans_color.index=(png_byte) 0;
7917 ping_have_tRNS=MagickTrue;
7920 if (ping_have_tRNS != MagickFalse)
7923 Determine if there is one and only one transparent color
7924 and if so if it is fully transparent.
7926 if (logging != MagickFalse)
7927 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7928 " Is there a single fully transparent color?");
7930 if (number_transparent > 1 || number_semitransparent > 0)
7932 ping_have_tRNS = MagickFalse;
7933 if (logging != MagickFalse)
7934 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7939 if (logging != MagickFalse)
7940 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7941 " ... Yes: (%d,%d,%d), (gray: %d)",
7942 (int) ping_trans_color.red,
7943 (int) ping_trans_color.green,
7944 (int) ping_trans_color.blue,
7945 (int) ping_trans_color.gray);
7949 if (ping_have_tRNS != MagickFalse)
7951 ping_color_type &= 0x03; /* changes 4 or 6 to 0 or 2 */
7953 if (image_depth == 8)
7955 ping_trans_color.red&=0xff;
7956 ping_trans_color.green&=0xff;
7957 ping_trans_color.blue&=0xff;
7958 ping_trans_color.gray&=0xff;
7964 if (image_depth == 8)
7966 ping_trans_color.red&=0xff;
7967 ping_trans_color.green&=0xff;
7968 ping_trans_color.blue&=0xff;
7969 ping_trans_color.gray&=0xff;
7976 if (ping_have_tRNS != MagickFalse)
7977 image_matte=MagickFalse;
7979 if ((mng_info->IsPalette) &&
7980 mng_info->write_png_colortype-1 != PNG_COLOR_TYPE_PALETTE &&
7981 ImageIsGray(image) && (image_matte == MagickFalse || image_depth >= 8))
7985 if (image_matte != MagickFalse)
7986 ping_color_type=PNG_COLOR_TYPE_GRAY_ALPHA;
7990 ping_color_type=PNG_COLOR_TYPE_GRAY;
7992 if (save_image_depth == 16 && image_depth == 8)
7994 if (logging != MagickFalse)
7996 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7997 " Scaling ping_trans_color (0)");
7999 ping_trans_color.gray*=0x0101;
8003 if (image_depth > MAGICKCORE_QUANTUM_DEPTH)
8004 image_depth=MAGICKCORE_QUANTUM_DEPTH;
8006 if (image_colors == 0 || image_colors-1 > MaxColormapSize)
8007 image_colors=(int) (one << image_depth);
8009 if (image_depth > 8)
8015 if ((int) ping_color_type == PNG_COLOR_TYPE_PALETTE)
8017 if(!mng_info->write_png_depth)
8021 while ((int) (one << ping_bit_depth)
8022 < (ssize_t) image_colors)
8023 ping_bit_depth <<= 1;
8027 #if 0 /* TO DO: Enable this when low bit-depth grayscale is working */
8028 else if (ping_color_type ==
8029 PNG_COLOR_TYPE_GRAY && image_colors < 17 &&
8030 mng_info->IsPalette)
8033 /* Check if grayscale is reducible */
8035 depth_4_ok=MagickTrue,
8036 depth_2_ok=MagickTrue,
8037 depth_1_ok=MagickTrue;
8039 for (i=0; i < (ssize_t) image_colors; i++)
8044 intensity=ScaleQuantumToChar(image->colormap[i].red);
8046 if ((intensity & 0x0f) != ((intensity & 0xf0) >> 4))
8047 depth_4_ok=depth_2_ok=depth_1_ok=MagickFalse;
8049 else if ((intensity & 0x03) != ((intensity & 0x0c) >> 2))
8050 depth_2_ok=depth_1_ok=MagickFalse;
8052 else if ((intensity & 0x01) != ((intensity & 0x02) >> 1))
8053 depth_1_ok=MagickFalse;
8056 if (depth_1_ok && mng_info->write_png_depth <= 1)
8059 else if (depth_2_ok && mng_info->write_png_depth <= 2)
8062 else if (depth_4_ok && mng_info->write_png_depth <= 4)
8068 image_depth=ping_bit_depth;
8073 if (mng_info->IsPalette)
8075 number_colors=image_colors;
8077 if (image_depth <= 8)
8082 ping_color_type=(png_byte) PNG_COLOR_TYPE_PALETTE;
8084 if (mng_info->have_write_global_plte && matte == MagickFalse)
8086 png_set_PLTE(ping,ping_info,NULL,0);
8088 if (logging != MagickFalse)
8089 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8090 " Setting up empty PLTE chunk");
8095 for (i=0; i < (ssize_t) number_colors; i++)
8097 palette[i].red=ScaleQuantumToChar(image->colormap[i].red);
8098 palette[i].green=ScaleQuantumToChar(image->colormap[i].green);
8099 palette[i].blue=ScaleQuantumToChar(image->colormap[i].blue);
8102 if (logging != MagickFalse)
8103 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8104 " Setting up PLTE chunk with %d colors",
8107 ping_have_PLTE=MagickTrue;
8110 /* color_type is PNG_COLOR_TYPE_PALETTE */
8111 if (mng_info->write_png_depth == 0)
8119 while ((one << ping_bit_depth) < number_colors)
8120 ping_bit_depth <<= 1;
8125 if (matte != MagickFalse)
8128 * Set up trans_colors array.
8130 assert(number_colors <= 256);
8132 ping_num_trans=(unsigned short) (number_transparent +
8133 number_semitransparent);
8135 if (ping_num_trans == 0)
8136 ping_have_tRNS=MagickFalse;
8140 if (logging != MagickFalse)
8142 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8143 " Scaling ping_trans_color (1)");
8145 ping_have_tRNS=MagickTrue;
8147 for (i=0; i < ping_num_trans; i++)
8149 ping_trans_alpha[i]= (png_byte) (255-
8150 ScaleQuantumToChar(image->colormap[i].opacity));
8160 if (image_depth < 8)
8163 if ((save_image_depth == 16) && (image_depth == 8))
8165 if (logging != MagickFalse)
8167 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8168 " Scaling ping_trans_color from (%d,%d,%d)",
8169 (int) ping_trans_color.red,
8170 (int) ping_trans_color.green,
8171 (int) ping_trans_color.blue);
8174 ping_trans_color.red*=0x0101;
8175 ping_trans_color.green*=0x0101;
8176 ping_trans_color.blue*=0x0101;
8177 ping_trans_color.gray*=0x0101;
8179 if (logging != MagickFalse)
8181 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8183 (int) ping_trans_color.red,
8184 (int) ping_trans_color.green,
8185 (int) ping_trans_color.blue);
8190 if (ping_bit_depth < (ssize_t) mng_info->write_png_depth)
8191 ping_bit_depth = (ssize_t) mng_info->write_png_depth;
8194 Adjust background and transparency samples in sub-8-bit grayscale files.
8196 if (ping_bit_depth < 8 && ping_color_type ==
8197 PNG_COLOR_TYPE_GRAY)
8205 maxval=(png_uint_16) ((one << ping_bit_depth)-1);
8207 if (ping_exclude_bKGD == MagickFalse)
8210 ping_background.gray=(png_uint_16)
8211 (QuantumScale*(maxval*(PixelIntensity(&image->background_color))));
8213 if (logging != MagickFalse)
8214 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8215 " Setting up bKGD chunk (2)");
8217 ping_have_bKGD = MagickTrue;
8220 ping_trans_color.gray=(png_uint_16) (QuantumScale*(maxval*
8221 ping_trans_color.gray));
8224 if (ping_exclude_bKGD == MagickFalse)
8226 if ((int) ping_color_type == PNG_COLOR_TYPE_PALETTE)
8229 Identify which colormap entry is the background color.
8232 number_colors=image_colors;
8234 for (i=0; i < (ssize_t) MagickMax(1L*number_colors,1L); i++)
8235 if (IsPNGColorEqual(image->background_color,image->colormap[i]))
8238 ping_background.index=(png_byte) i;
8240 if (logging != MagickFalse)
8242 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8243 " Setting up bKGD chunk with index=%d",(int) i);
8246 if (i < (ssize_t) number_colors)
8248 ping_have_bKGD = MagickTrue;
8250 if (logging != MagickFalse)
8252 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8253 " background =(%d,%d,%d)",
8254 (int) ping_background.red,
8255 (int) ping_background.green,
8256 (int) ping_background.blue);
8260 else /* Can't happen */
8262 if (logging != MagickFalse)
8263 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8264 " No room in PLTE to add bKGD color");
8265 ping_have_bKGD = MagickFalse;
8270 if (logging != MagickFalse)
8271 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8272 " PNG color type: %d",ping_color_type);
8274 Initialize compression level and filtering.
8276 if (logging != MagickFalse)
8278 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8279 " Setting up deflate compression");
8281 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8282 " Compression buffer size: 32768");
8285 png_set_compression_buffer_size(ping,32768L);
8287 if (logging != MagickFalse)
8288 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8289 " Compression mem level: 9");
8291 png_set_compression_mem_level(ping, 9);
8293 quality=image->quality == UndefinedCompressionQuality ? 75UL :
8301 level=(int) MagickMin((ssize_t) quality/10,9);
8303 if (logging != MagickFalse)
8304 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8305 " Compression level: %d",level);
8307 png_set_compression_level(ping,level);
8312 if (logging != MagickFalse)
8313 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8314 " Compression strategy: Z_HUFFMAN_ONLY");
8316 png_set_compression_strategy(ping, Z_HUFFMAN_ONLY);
8319 if (logging != MagickFalse)
8320 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8321 " Setting up filtering");
8323 #if defined(PNG_MNG_FEATURES_SUPPORTED) && defined(PNG_INTRAPIXEL_DIFFERENCING)
8324 /* This became available in libpng-1.0.9. Output must be a MNG. */
8325 if (mng_info->write_mng && ((quality % 10) == 7))
8327 if (logging != MagickFalse)
8328 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8329 " Filter_type: PNG_INTRAPIXEL_DIFFERENCING");
8331 ping_filter_method=PNG_INTRAPIXEL_DIFFERENCING;
8335 if (logging != MagickFalse)
8336 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8344 if ((quality % 10) > 5)
8345 base_filter=PNG_ALL_FILTERS;
8348 if ((quality % 10) != 5)
8349 base_filter=(int) quality % 10;
8352 if (((int) ping_color_type == PNG_COLOR_TYPE_GRAY) ||
8353 ((int) ping_color_type == PNG_COLOR_TYPE_PALETTE) ||
8355 base_filter=PNG_NO_FILTERS;
8358 base_filter=PNG_ALL_FILTERS;
8360 if (logging != MagickFalse)
8362 if (base_filter == PNG_ALL_FILTERS)
8363 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8364 " Base filter method: ADAPTIVE");
8366 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8367 " Base filter method: NONE");
8370 png_set_filter(ping,PNG_FILTER_TYPE_BASE,base_filter);
8373 if (ping_exclude_iCCP == MagickFalse || ping_exclude_zCCP == MagickFalse)
8375 ResetImageProfileIterator(image);
8376 for (name=GetNextImageProfile(image); name != (const char *) NULL; )
8378 profile=GetImageProfile(image,name);
8380 if (profile != (StringInfo *) NULL)
8382 #ifdef PNG_WRITE_iCCP_SUPPORTED
8383 if ((LocaleCompare(name,"ICC") == 0) ||
8384 (LocaleCompare(name,"ICM") == 0))
8387 if (ping_exclude_iCCP == MagickFalse)
8389 png_set_iCCP(ping,ping_info,(const png_charp) name,0,
8390 #if (PNG_LIBPNG_VER < 10500)
8391 (png_charp) GetStringInfoDatum(profile),
8393 (png_const_bytep) GetStringInfoDatum(profile),
8395 (png_uint_32) GetStringInfoLength(profile));
8401 if (ping_exclude_zCCP == MagickFalse)
8403 Magick_png_write_raw_profile(image_info,ping,ping_info,
8404 (unsigned char *) name,(unsigned char *) name,
8405 GetStringInfoDatum(profile),
8406 (png_uint_32) GetStringInfoLength(profile));
8410 if (logging != MagickFalse)
8411 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8412 " Setting up text chunk with %s profile",name);
8414 name=GetNextImageProfile(image);
8418 #if defined(PNG_WRITE_sRGB_SUPPORTED)
8419 if ((mng_info->have_write_global_srgb == 0) &&
8420 ((image->rendering_intent != UndefinedIntent) ||
8421 (image->colorspace == sRGBColorspace)))
8423 if (ping_exclude_sRGB == MagickFalse)
8426 Note image rendering intent.
8428 if (logging != MagickFalse)
8429 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8430 " Setting up sRGB chunk");
8432 (void) png_set_sRGB(ping,ping_info,(
8433 Magick_RenderingIntent_to_PNG_RenderingIntent(
8434 image->rendering_intent)));
8436 if (ping_exclude_gAMA == MagickFalse)
8437 png_set_gAMA(ping,ping_info,0.45455);
8441 if ((!mng_info->write_mng) || (!png_get_valid(ping,ping_info,PNG_INFO_sRGB)))
8444 if (ping_exclude_gAMA == MagickFalse &&
8445 (ping_exclude_sRGB == MagickFalse ||
8446 (image->gamma < .45 || image->gamma > .46)))
8448 if ((mng_info->have_write_global_gama == 0) && (image->gamma != 0.0))
8452 To do: check for cHRM+gAMA == sRGB, and write sRGB instead.
8454 if (logging != MagickFalse)
8455 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8456 " Setting up gAMA chunk");
8458 png_set_gAMA(ping,ping_info,image->gamma);
8462 if (ping_exclude_cHRM == MagickFalse)
8464 if ((mng_info->have_write_global_chrm == 0) &&
8465 (image->chromaticity.red_primary.x != 0.0))
8468 Note image chromaticity.
8469 To do: check for cHRM+gAMA == sRGB, and write sRGB instead.
8477 wp=image->chromaticity.white_point;
8478 rp=image->chromaticity.red_primary;
8479 gp=image->chromaticity.green_primary;
8480 bp=image->chromaticity.blue_primary;
8482 if (logging != MagickFalse)
8483 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8484 " Setting up cHRM chunk");
8486 png_set_cHRM(ping,ping_info,wp.x,wp.y,rp.x,rp.y,gp.x,gp.y,
8492 ping_interlace_method=image_info->interlace != NoInterlace;
8494 if (mng_info->write_mng)
8495 png_set_sig_bytes(ping,8);
8497 /* Bail out if cannot meet defined PNG:bit-depth or PNG:color-type */
8499 if (mng_info->write_png_colortype != 0)
8501 if (mng_info->write_png_colortype-1 == PNG_COLOR_TYPE_GRAY)
8502 if (ImageIsGray(image) == MagickFalse)
8504 ping_color_type = PNG_COLOR_TYPE_RGB;
8506 if (ping_bit_depth < 8)
8510 if (mng_info->write_png_colortype-1 == PNG_COLOR_TYPE_GRAY_ALPHA)
8511 if (ImageIsGray(image) == MagickFalse)
8512 ping_color_type = PNG_COLOR_TYPE_RGB_ALPHA;
8515 if (ping_need_colortype_warning != MagickFalse ||
8516 ((mng_info->write_png_depth &&
8517 (int) mng_info->write_png_depth != ping_bit_depth) ||
8518 (mng_info->write_png_colortype &&
8519 ((int) mng_info->write_png_colortype-1 != ping_color_type &&
8520 mng_info->write_png_colortype != 7 &&
8521 !(mng_info->write_png_colortype == 5 && ping_color_type == 0)))))
8523 if (logging != MagickFalse)
8525 if (ping_need_colortype_warning != MagickFalse)
8527 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8528 " Image has transparency but tRNS chunk was excluded");
8531 if (mng_info->write_png_depth)
8533 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8534 " Defined PNG:bit-depth=%u, Computed depth=%u",
8535 mng_info->write_png_depth,
8539 if (mng_info->write_png_colortype)
8541 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8542 " Defined PNG:color-type=%u, Computed color type=%u",
8543 mng_info->write_png_colortype-1,
8549 "Cannot write image with defined PNG:bit-depth or PNG:color-type.");
8552 if (image_matte != MagickFalse && image->matte == MagickFalse)
8554 /* Add an opaque matte channel */
8555 image->matte = MagickTrue;
8556 (void) SetImageOpacity(image,0);
8558 if (logging != MagickFalse)
8559 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8560 " Added an opaque matte channel");
8563 if (number_transparent != 0 || number_semitransparent != 0)
8565 if (ping_color_type < 4)
8567 ping_have_tRNS=MagickTrue;
8568 if (logging != MagickFalse)
8569 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8570 " Setting ping_have_tRNS=MagickTrue.");
8574 if (logging != MagickFalse)
8575 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8576 " Writing PNG header chunks");
8578 png_set_IHDR(ping,ping_info,ping_width,ping_height,
8579 ping_bit_depth,ping_color_type,
8580 ping_interlace_method,ping_compression_method,
8581 ping_filter_method);
8583 if (ping_color_type == 3 && ping_have_PLTE != MagickFalse)
8585 png_set_PLTE(ping,ping_info,palette,number_colors);
8587 if (logging != MagickFalse)
8589 for (i=0; i< (ssize_t) number_colors; i++)
8591 if (i < ping_num_trans)
8592 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8593 " PLTE[%d] = (%d,%d,%d), tRNS[%d] = (%d)",
8595 (int) palette[i].red,
8596 (int) palette[i].green,
8597 (int) palette[i].blue,
8599 (int) ping_trans_alpha[i]);
8601 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8602 " PLTE[%d] = (%d,%d,%d)",
8604 (int) palette[i].red,
8605 (int) palette[i].green,
8606 (int) palette[i].blue);
8611 if (ping_exclude_bKGD == MagickFalse)
8613 if (ping_have_bKGD != MagickFalse)
8614 png_set_bKGD(ping,ping_info,&ping_background);
8617 if (ping_exclude_pHYs == MagickFalse)
8619 if (ping_have_pHYs != MagickFalse)
8621 png_set_pHYs(ping,ping_info,
8622 ping_pHYs_x_resolution,
8623 ping_pHYs_y_resolution,
8624 ping_pHYs_unit_type);
8628 #if defined(PNG_oFFs_SUPPORTED)
8629 if (ping_exclude_oFFs == MagickFalse)
8631 if (image->page.x || image->page.y)
8633 png_set_oFFs(ping,ping_info,(png_int_32) image->page.x,
8634 (png_int_32) image->page.y, 0);
8636 if (logging != MagickFalse)
8637 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8638 " Setting up oFFs chunk with x=%d, y=%d, units=0",
8639 (int) image->page.x, (int) image->page.y);
8644 png_write_info_before_PLTE(ping, ping_info);
8646 if (ping_have_tRNS != MagickFalse && ping_color_type < 4)
8648 if (logging != MagickFalse)
8650 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8651 " Calling png_set_tRNS with num_trans=%d",ping_num_trans);
8654 if (ping_color_type == 3)
8655 (void) png_set_tRNS(ping, ping_info,
8662 (void) png_set_tRNS(ping, ping_info,
8667 if (logging != MagickFalse)
8669 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8670 " tRNS color =(%d,%d,%d)",
8671 (int) ping_trans_color.red,
8672 (int) ping_trans_color.green,
8673 (int) ping_trans_color.blue);
8678 /* write any png-chunk-b profiles */
8679 (void) Magick_png_write_chunk_from_profile(image,"PNG-chunk-b",logging);
8680 png_write_info(ping,ping_info);
8682 /* write any PNG-chunk-m profiles */
8683 (void) Magick_png_write_chunk_from_profile(image,"PNG-chunk-m",logging);
8685 if (ping_exclude_vpAg == MagickFalse)
8687 if ((image->page.width != 0 && image->page.width != image->columns) ||
8688 (image->page.height != 0 && image->page.height != image->rows))
8693 (void) WriteBlobMSBULong(image,9L); /* data length=8 */
8694 PNGType(chunk,mng_vpAg);
8695 LogPNGChunk(logging,mng_vpAg,9L);
8696 PNGLong(chunk+4,(png_uint_32) image->page.width);
8697 PNGLong(chunk+8,(png_uint_32) image->page.height);
8698 chunk[12]=0; /* unit = pixels */
8699 (void) WriteBlob(image,13,chunk);
8700 (void) WriteBlobMSBULong(image,crc32(0,chunk,13));
8704 #if (PNG_LIBPNG_VER == 10206)
8705 /* avoid libpng-1.2.6 bug by setting PNG_HAVE_IDAT flag */
8706 #define PNG_HAVE_IDAT 0x04
8707 ping->mode |= PNG_HAVE_IDAT;
8708 #undef PNG_HAVE_IDAT
8711 png_set_packing(ping);
8715 rowbytes=image->columns;
8716 if (image_depth > 8)
8718 switch (ping_color_type)
8720 case PNG_COLOR_TYPE_RGB:
8724 case PNG_COLOR_TYPE_GRAY_ALPHA:
8728 case PNG_COLOR_TYPE_RGBA:
8736 if (logging != MagickFalse)
8738 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8739 " Writing PNG image data");
8741 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8742 " Allocating %.20g bytes of memory for pixels",(double) rowbytes);
8744 ping_pixels=(unsigned char *) AcquireQuantumMemory(rowbytes,
8745 sizeof(*ping_pixels));
8747 if (ping_pixels == (unsigned char *) NULL)
8748 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
8751 Initialize image scanlines.
8753 if (setjmp(png_jmpbuf(ping)))
8759 if (image_info->verbose)
8760 (void) printf("PNG write has failed.\n");
8762 png_destroy_write_struct(&ping,&ping_info);
8763 if (quantum_info != (QuantumInfo *) NULL)
8764 quantum_info=DestroyQuantumInfo(quantum_info);
8765 if (ping_pixels != (unsigned char *) NULL)
8766 ping_pixels=(unsigned char *) RelinquishMagickMemory(ping_pixels);
8767 #if defined(PNG_SETJMP_NOT_THREAD_SAFE)
8768 UnlockSemaphoreInfo(ping_semaphore);
8770 if (mng_info->need_blob != MagickFalse)
8771 (void) CloseBlob(image);
8772 image_info=DestroyImageInfo(image_info);
8773 image=DestroyImage(image);
8774 return(MagickFalse);
8776 quantum_info=AcquireQuantumInfo(image_info,image);
8777 if (quantum_info == (QuantumInfo *) NULL)
8778 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
8779 quantum_info->format=UndefinedQuantumFormat;
8780 quantum_info->depth=image_depth;
8781 num_passes=png_set_interlace_handling(ping);
8783 if ((!mng_info->write_png8 && !mng_info->write_png24 &&
8784 !mng_info->write_png32) &&
8785 (mng_info->IsPalette ||
8786 (image_info->type == BilevelType)) &&
8787 image_matte == MagickFalse && ImageIsMonochrome(image))
8789 /* Palette, Bilevel, or Opaque Monochrome */
8790 register const PixelPacket
8793 quantum_info->depth=8;
8794 for (pass=0; pass < num_passes; pass++)
8797 Convert PseudoClass image to a PNG monochrome image.
8799 for (y=0; y < (ssize_t) image->rows; y++)
8802 if (logging != MagickFalse)
8803 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8804 " Writing row of pixels (0)");
8806 p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception);
8808 if (p == (const PixelPacket *) NULL)
8811 if (mng_info->IsPalette)
8813 (void) ExportQuantumPixels(image,(const CacheView *) NULL,
8814 quantum_info,GrayQuantum,ping_pixels,&image->exception);
8815 if (mng_info->write_png_colortype-1 == PNG_COLOR_TYPE_PALETTE &&
8816 mng_info->write_png_depth &&
8817 mng_info->write_png_depth != old_bit_depth)
8819 /* Undo pixel scaling */
8820 for (i=0; i < (ssize_t) image->columns; i++)
8821 *(ping_pixels+i)=(unsigned char) (*(ping_pixels+i)
8822 >> (8-old_bit_depth));
8828 (void) ExportQuantumPixels(image,(const CacheView *) NULL,
8829 quantum_info,RedQuantum,ping_pixels,&image->exception);
8832 if (mng_info->write_png_colortype-1 != PNG_COLOR_TYPE_PALETTE)
8833 for (i=0; i < (ssize_t) image->columns; i++)
8834 *(ping_pixels+i)=(unsigned char) ((*(ping_pixels+i) > 127) ?
8837 if (logging != MagickFalse && y == 0)
8838 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8839 " Writing row of pixels (1)");
8841 png_write_row(ping,ping_pixels);
8843 if (image->previous == (Image *) NULL)
8845 status=SetImageProgress(image,LoadImageTag,pass,num_passes);
8846 if (status == MagickFalse)
8852 else /* Not Palette, Bilevel, or Opaque Monochrome */
8854 if ((!mng_info->write_png8 && !mng_info->write_png24 &&
8855 !mng_info->write_png32) &&
8856 (image_matte != MagickFalse ||
8857 (ping_bit_depth >= MAGICKCORE_QUANTUM_DEPTH)) &&
8858 (mng_info->IsPalette) && ImageIsGray(image))
8860 register const PixelPacket
8863 for (pass=0; pass < num_passes; pass++)
8866 for (y=0; y < (ssize_t) image->rows; y++)
8868 p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception);
8870 if (p == (const PixelPacket *) NULL)
8873 if (ping_color_type == PNG_COLOR_TYPE_GRAY)
8875 if (mng_info->IsPalette)
8876 (void) ExportQuantumPixels(image,(const CacheView *) NULL,
8877 quantum_info,GrayQuantum,ping_pixels,&image->exception);
8880 (void) ExportQuantumPixels(image,(const CacheView *) NULL,
8881 quantum_info,RedQuantum,ping_pixels,&image->exception);
8883 if (logging != MagickFalse && y == 0)
8884 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8885 " Writing GRAY PNG pixels (2)");
8888 else /* PNG_COLOR_TYPE_GRAY_ALPHA */
8890 if (logging != MagickFalse && y == 0)
8891 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8892 " Writing GRAY_ALPHA PNG pixels (2)");
8894 (void) ExportQuantumPixels(image,(const CacheView *) NULL,
8895 quantum_info,GrayAlphaQuantum,ping_pixels,&image->exception);
8898 if (logging != MagickFalse && y == 0)
8899 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8900 " Writing row of pixels (2)");
8902 png_write_row(ping,ping_pixels);
8905 if (image->previous == (Image *) NULL)
8907 status=SetImageProgress(image,LoadImageTag,pass,num_passes);
8908 if (status == MagickFalse)
8916 register const PixelPacket
8919 for (pass=0; pass < num_passes; pass++)
8921 if ((image_depth > 8) || (mng_info->write_png24 ||
8922 mng_info->write_png32 ||
8923 (!mng_info->write_png8 && !mng_info->IsPalette)))
8925 for (y=0; y < (ssize_t) image->rows; y++)
8927 p=GetVirtualPixels(image,0,y,image->columns,1,
8930 if (p == (const PixelPacket *) NULL)
8933 if (ping_color_type == PNG_COLOR_TYPE_GRAY)
8935 if (image->storage_class == DirectClass)
8936 (void) ExportQuantumPixels(image,(const CacheView *) NULL,
8937 quantum_info,RedQuantum,ping_pixels,&image->exception);
8940 (void) ExportQuantumPixels(image,(const CacheView *) NULL,
8941 quantum_info,GrayQuantum,ping_pixels,&image->exception);
8944 else if (ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
8946 (void) ExportQuantumPixels(image,(const CacheView *) NULL,
8947 quantum_info,GrayAlphaQuantum,ping_pixels,
8950 if (logging != MagickFalse && y == 0)
8951 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8952 " Writing GRAY_ALPHA PNG pixels (3)");
8955 else if (image_matte != MagickFalse)
8956 (void) ExportQuantumPixels(image,(const CacheView *) NULL,
8957 quantum_info,RGBAQuantum,ping_pixels,&image->exception);
8960 (void) ExportQuantumPixels(image,(const CacheView *) NULL,
8961 quantum_info,RGBQuantum,ping_pixels,&image->exception);
8963 if (logging != MagickFalse && y == 0)
8964 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8965 " Writing row of pixels (3)");
8967 png_write_row(ping,ping_pixels);
8972 /* not ((image_depth > 8) || (mng_info->write_png24 ||
8973 mng_info->write_png32 ||
8974 (!mng_info->write_png8 && !mng_info->IsPalette))) */
8976 if ((ping_color_type != PNG_COLOR_TYPE_GRAY) &&
8977 (ping_color_type != PNG_COLOR_TYPE_GRAY_ALPHA))
8979 if (logging != MagickFalse)
8980 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8981 " pass %d, Image Is not GRAY or GRAY_ALPHA",pass);
8983 quantum_info->depth=8;
8987 for (y=0; y < (ssize_t) image->rows; y++)
8989 if (logging != MagickFalse && y == 0)
8990 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8991 " pass %d, Image Is RGB, 16-bit GRAY, or GRAY_ALPHA",pass);
8993 p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception);
8995 if (p == (const PixelPacket *) NULL)
8998 if (ping_color_type == PNG_COLOR_TYPE_GRAY)
8999 (void) ExportQuantumPixels(image,(const CacheView *) NULL,
9000 quantum_info,GrayQuantum,ping_pixels,&image->exception);
9002 else if (ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
9004 if (logging != MagickFalse && y == 0)
9005 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9006 " Writing GRAY_ALPHA PNG pixels (4)");
9008 (void) ExportQuantumPixels(image,(const CacheView *) NULL,
9009 quantum_info,GrayAlphaQuantum,ping_pixels,
9017 * This is failing to account for 1, 2, 4-bit depths
9018 * The call to png_set_packing() above is supposed to
9019 * take care of those.
9022 /* GrayQuantum does not work here */
9023 (void) ExportQuantumPixels(image,(const CacheView *) NULL,
9024 quantum_info,IndexQuantum,ping_pixels,&image->exception);
9026 if (logging != MagickFalse && y <= 2)
9028 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9029 " Writing row of pixels (4)");
9031 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9032 " ping_pixels[0]=%d,ping_pixels[1]=%d",
9033 (int)ping_pixels[0],(int)ping_pixels[1]);
9036 png_write_row(ping,ping_pixels);
9040 if (image->previous == (Image *) NULL)
9042 status=SetImageProgress(image,LoadImageTag,pass,num_passes);
9043 if (status == MagickFalse)
9050 if (quantum_info != (QuantumInfo *) NULL)
9051 quantum_info=DestroyQuantumInfo(quantum_info);
9053 if (logging != MagickFalse)
9055 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9056 " Wrote PNG image data");
9058 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9059 " Width: %.20g",(double) ping_width);
9061 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9062 " Height: %.20g",(double) ping_height);
9064 if (mng_info->write_png_depth)
9066 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9067 " Defined PNG:bit-depth: %d",mng_info->write_png_depth);
9070 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9071 " PNG bit-depth written: %d",ping_bit_depth);
9073 if (mng_info->write_png_colortype)
9075 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9076 " Defined PNG:color-type: %d",mng_info->write_png_colortype-1);
9079 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9080 " PNG color-type written: %d",ping_color_type);
9082 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9083 " PNG Interlace method: %d",ping_interlace_method);
9086 Generate text chunks.
9088 if (ping_exclude_tEXt == MagickFalse && ping_exclude_zTXt == MagickFalse)
9090 ResetImagePropertyIterator(image);
9091 property=GetNextImageProperty(image);
9092 while (property != (const char *) NULL)
9097 value=GetImageProperty(image,property);
9098 if (value != (const char *) NULL)
9100 text=(png_textp) png_malloc(ping,(png_uint_32) sizeof(png_text));
9101 text[0].key=(char *) property;
9102 text[0].text=(char *) value;
9103 text[0].text_length=strlen(value);
9105 if (ping_exclude_tEXt != MagickFalse)
9106 text[0].compression=PNG_TEXT_COMPRESSION_zTXt;
9108 else if (ping_exclude_zTXt != MagickFalse)
9109 text[0].compression=PNG_TEXT_COMPRESSION_NONE;
9113 text[0].compression=image_info->compression == NoCompression ||
9114 (image_info->compression == UndefinedCompression &&
9115 text[0].text_length < 128) ? PNG_TEXT_COMPRESSION_NONE :
9116 PNG_TEXT_COMPRESSION_zTXt ;
9119 if (logging != MagickFalse)
9121 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9122 " Setting up text chunk");
9124 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9125 " keyword: %s",text[0].key);
9128 png_set_text(ping,ping_info,text,1);
9129 png_free(ping,text);
9131 property=GetNextImageProperty(image);
9135 /* write any PNG-chunk-e profiles */
9136 (void) Magick_png_write_chunk_from_profile(image,"PNG-chunk-e",logging);
9138 if (logging != MagickFalse)
9139 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9140 " Writing PNG end info");
9142 png_write_end(ping,ping_info);
9144 if (mng_info->need_fram && (int) image->dispose == BackgroundDispose)
9146 if (mng_info->page.x || mng_info->page.y ||
9147 (ping_width != mng_info->page.width) ||
9148 (ping_height != mng_info->page.height))
9154 Write FRAM 4 with clipping boundaries followed by FRAM 1.
9156 (void) WriteBlobMSBULong(image,27L); /* data length=27 */
9157 PNGType(chunk,mng_FRAM);
9158 LogPNGChunk(logging,mng_FRAM,27L);
9160 chunk[5]=0; /* frame name separator (no name) */
9161 chunk[6]=1; /* flag for changing delay, for next frame only */
9162 chunk[7]=0; /* flag for changing frame timeout */
9163 chunk[8]=1; /* flag for changing frame clipping for next frame */
9164 chunk[9]=0; /* flag for changing frame sync_id */
9165 PNGLong(chunk+10,(png_uint_32) (0L)); /* temporary 0 delay */
9166 chunk[14]=0; /* clipping boundaries delta type */
9167 PNGLong(chunk+15,(png_uint_32) (mng_info->page.x)); /* left cb */
9169 (png_uint_32) (mng_info->page.x + ping_width));
9170 PNGLong(chunk+23,(png_uint_32) (mng_info->page.y)); /* top cb */
9172 (png_uint_32) (mng_info->page.y + ping_height));
9173 (void) WriteBlob(image,31,chunk);
9174 (void) WriteBlobMSBULong(image,crc32(0,chunk,31));
9175 mng_info->old_framing_mode=4;
9176 mng_info->framing_mode=1;
9180 mng_info->framing_mode=3;
9182 if (mng_info->write_mng && !mng_info->need_fram &&
9183 ((int) image->dispose == 3))
9184 (void) ThrowMagickException(&image->exception,GetMagickModule(),
9185 CoderError,"Cannot convert GIF with disposal method 3 to MNG-LC",
9186 "`%s'",image->filename);
9192 png_destroy_write_struct(&ping,&ping_info);
9194 ping_pixels=(unsigned char *) RelinquishMagickMemory(ping_pixels);
9196 #if defined(PNG_SETJMP_NOT_THREAD_SAFE)
9197 UnlockSemaphoreInfo(ping_semaphore);
9200 if (mng_info->need_blob != MagickFalse)
9201 (void) CloseBlob(image);
9203 image_info=DestroyImageInfo(image_info);
9204 image=DestroyImage(image);
9206 /* Store bit depth actually written */
9207 s[0]=(char) ping_bit_depth;
9210 (void) SetImageProperty(IMimage,"png:bit-depth-written",s);
9212 if (logging != MagickFalse)
9213 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9214 " exit WriteOnePNGImage()");
9217 /* End write one PNG image */
9221 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
9225 % W r i t e P N G I m a g e %
9229 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
9231 % WritePNGImage() writes a Portable Network Graphics (PNG) or
9232 % Multiple-image Network Graphics (MNG) image file.
9234 % MNG support written by Glenn Randers-Pehrson, glennrp@image...
9236 % The format of the WritePNGImage method is:
9238 % MagickBooleanType WritePNGImage(const ImageInfo *image_info,Image *image)
9240 % A description of each parameter follows:
9242 % o image_info: the image info.
9244 % o image: The image.
9246 % Returns MagickTrue on success, MagickFalse on failure.
9248 % Communicating with the PNG encoder:
9250 % While the datastream written is always in PNG format and normally would
9251 % be given the "png" file extension, this method also writes the following
9252 % pseudo-formats which are subsets of PNG:
9254 % o PNG8: An 8-bit indexed PNG datastream is written. If transparency
9255 % is present, the tRNS chunk must only have values 0 and 255
9256 % (i.e., transparency is binary: fully opaque or fully
9257 % transparent). The pixels contain 8-bit indices even if
9258 % they could be represented with 1, 2, or 4 bits. Note: grayscale
9259 % images will be written as indexed PNG files even though the
9260 % PNG grayscale type might be slightly more efficient.
9262 % o PNG24: An 8-bit per sample RGB PNG datastream is written. The tRNS
9263 % chunk can be present to convey binary transparency by naming
9264 % one of the colors as transparent.
9266 % o PNG32: An 8-bit per sample RGBA PNG is written. Partial
9267 % transparency is permitted, i.e., the alpha sample for
9268 % each pixel can have any value from 0 to 255. The alpha
9269 % channel is present even if the image is fully opaque.
9271 % o -define: For more precise control of the PNG output, you can use the
9272 % Image options "png:bit-depth" and "png:color-type". These
9273 % can be set from the commandline with "-define" and also
9274 % from the application programming interfaces. The options
9275 % are case-independent and are converted to lowercase before
9276 % being passed to this encoder.
9278 % png:color-type can be 0, 2, 3, 4, or 6.
9280 % When png:color-type is 0 (Grayscale), png:bit-depth can
9281 % be 1, 2, 4, 8, or 16.
9283 % When png:color-type is 2 (RGB), png:bit-depth can
9286 % When png:color-type is 3 (Indexed), png:bit-depth can
9287 % be 1, 2, 4, or 8. This refers to the number of bits
9288 % used to store the index. The color samples always have
9289 % bit-depth 8 in indexed PNG files.
9291 % When png:color-type is 4 (Gray-Matte) or 6 (RGB-Matte),
9292 % png:bit-depth can be 8 or 16.
9294 % If the image cannot be written without loss in the requested PNG8, PNG24,
9295 % or PNG32 format or with the requested bit-depth and color-type without loss,
9296 % a PNG file will not be written, and the encoder will return MagickFalse.
9297 % Since image encoders should not be responsible for the "heavy lifting",
9298 % the user should make sure that ImageMagick has already reduced the
9299 % image depth and number of colors and limit transparency to binary
9300 % transparency prior to attempting to write the image in a format that
9301 % is subject to depth, color, or transparency limitations.
9303 % TODO: Enforce the previous paragraph.
9305 % Note that another definition, "png:bit-depth-written" exists, but it
9306 % is not intended for external use. It is only used internally by the
9307 % PNG encoder to inform the JNG encoder of the depth of the alpha channel.
9309 % It is possible to request that the PNG encoder write previously-formatted
9310 % ancillary chunks in the output PNG file, using the "-profile" commandline
9311 % option as shown below or by setting the profile via a programming
9314 % -profile PNG-chunk-x:<file>
9316 % where x is a location flag and <file> is a file containing the chunk
9317 % name in the first 4 bytes, then a colon (":"), followed by the chunk data.
9318 % This encoder will compute the chunk length and CRC, so those must not
9319 % be included in the file.
9321 % "x" can be "b" (before PLTE), "m" (middle, i.e., between PLTE and IDAT),
9322 % or "e" (end, i.e., after IDAT). If you want to write multiple chunks
9323 % of the same type, then add a short unique string after the "x" to prevent
9324 % subsequent profiles from overwriting the preceding ones, e.g.,
9326 % -profile PNG-chunk-b01:file01 -profile PNG-chunk-b02:file02
9328 % As of version 6.6.6 the following optimizations are always done:
9330 % o 32-bit depth is reduced to 16.
9331 % o 16-bit depth is reduced to 8 if all pixels contain samples whose
9332 % high byte and low byte are identical.
9333 % o Palette is sorted to remove unused entries and to put a
9334 % transparent color first, if BUILD_PNG_PALETTE is defined.
9335 % o Opaque matte channel is removed when writing an indexed PNG.
9336 % o Grayscale images are reduced to 1, 2, or 4 bit depth if
9337 % this can be done without loss and a larger bit depth N was not
9338 % requested via the "-define PNG:bit-depth=N" option.
9339 % o If matte channel is present but only one transparent color is
9340 % present, RGB+tRNS is written instead of RGBA
9341 % o Opaque matte channel is removed (or added, if color-type 4 or 6
9342 % was requested when converting an opaque image).
9344 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
9346 static MagickBooleanType WritePNGImage(const ImageInfo *image_info,
9368 assert(image_info != (const ImageInfo *) NULL);
9369 assert(image_info->signature == MagickSignature);
9370 assert(image != (Image *) NULL);
9371 assert(image->signature == MagickSignature);
9372 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
9373 logging=LogMagickEvent(CoderEvent,GetMagickModule(),"enter WritePNGImage()");
9375 Allocate a MngInfo structure.
9377 have_mng_structure=MagickFalse;
9378 mng_info=(MngInfo *) AcquireMagickMemory(sizeof(MngInfo));
9380 if (mng_info == (MngInfo *) NULL)
9381 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
9384 Initialize members of the MngInfo structure.
9386 (void) ResetMagickMemory(mng_info,0,sizeof(MngInfo));
9387 mng_info->image=image;
9388 mng_info->equal_backgrounds=MagickTrue;
9389 have_mng_structure=MagickTrue;
9391 /* See if user has requested a specific PNG subformat */
9393 mng_info->write_png8=LocaleCompare(image_info->magick,"PNG8") == 0;
9394 mng_info->write_png24=LocaleCompare(image_info->magick,"PNG24") == 0;
9395 mng_info->write_png32=LocaleCompare(image_info->magick,"PNG32") == 0;
9397 if (mng_info->write_png8)
9399 mng_info->write_png_colortype = /* 3 */ 4;
9400 mng_info->write_png_depth = 8;
9404 if (mng_info->write_png24)
9406 mng_info->write_png_colortype = /* 2 */ 3;
9407 mng_info->write_png_depth = 8;
9410 if (image->matte == MagickTrue)
9411 (void) SetImageType(image,TrueColorMatteType);
9414 (void) SetImageType(image,TrueColorType);
9416 (void) SyncImage(image);
9419 if (mng_info->write_png32)
9421 mng_info->write_png_colortype = /* 6 */ 7;
9422 mng_info->write_png_depth = 8;
9425 if (image->matte == MagickTrue)
9426 (void) SetImageType(image,TrueColorMatteType);
9429 (void) SetImageType(image,TrueColorType);
9431 (void) SyncImage(image);
9434 value=GetImageOption(image_info,"png:bit-depth");
9436 if (value != (char *) NULL)
9438 if (LocaleCompare(value,"1") == 0)
9439 mng_info->write_png_depth = 1;
9441 else if (LocaleCompare(value,"2") == 0)
9442 mng_info->write_png_depth = 2;
9444 else if (LocaleCompare(value,"4") == 0)
9445 mng_info->write_png_depth = 4;
9447 else if (LocaleCompare(value,"8") == 0)
9448 mng_info->write_png_depth = 8;
9450 else if (LocaleCompare(value,"16") == 0)
9451 mng_info->write_png_depth = 16;
9454 (void) ThrowMagickException(&image->exception,
9455 GetMagickModule(),CoderWarning,
9456 "ignoring invalid defined png:bit-depth",
9459 if (logging != MagickFalse)
9460 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9461 " png:bit-depth=%d was defined.\n",mng_info->write_png_depth);
9464 value=GetImageOption(image_info,"png:color-type");
9466 if (value != (char *) NULL)
9468 /* We must store colortype+1 because 0 is a valid colortype */
9469 if (LocaleCompare(value,"0") == 0)
9470 mng_info->write_png_colortype = 1;
9472 else if (LocaleCompare(value,"2") == 0)
9473 mng_info->write_png_colortype = 3;
9475 else if (LocaleCompare(value,"3") == 0)
9476 mng_info->write_png_colortype = 4;
9478 else if (LocaleCompare(value,"4") == 0)
9479 mng_info->write_png_colortype = 5;
9481 else if (LocaleCompare(value,"6") == 0)
9482 mng_info->write_png_colortype = 7;
9485 (void) ThrowMagickException(&image->exception,
9486 GetMagickModule(),CoderWarning,
9487 "ignoring invalid defined png:color-type",
9490 if (logging != MagickFalse)
9491 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9492 " png:color-type=%d was defined.\n",mng_info->write_png_colortype-1);
9495 /* Check for chunks to be excluded:
9497 * The default is to not exclude any known chunks except for any
9498 * listed in the "unused_chunks" array, above.
9500 * Chunks can be listed for exclusion via a "PNG:exclude-chunk"
9501 * define (in the image properties or in the image artifacts)
9502 * or via a mng_info member. For convenience, in addition
9503 * to or instead of a comma-separated list of chunks, the
9504 * "exclude-chunk" string can be simply "all" or "none".
9506 * The exclude-chunk define takes priority over the mng_info.
9508 * A "PNG:include-chunk" define takes priority over both the
9509 * mng_info and the "PNG:exclude-chunk" define. Like the
9510 * "exclude-chunk" string, it can define "all" or "none" as
9511 * well as a comma-separated list. Chunks that are unknown to
9512 * ImageMagick are always excluded, regardless of their "copy-safe"
9513 * status according to the PNG specification, and even if they
9514 * appear in the "include-chunk" list.
9516 * Finally, all chunks listed in the "unused_chunks" array are
9517 * automatically excluded, regardless of the other instructions
9520 * if you exclude sRGB but not gAMA (recommended), then sRGB chunk
9521 * will not be written and the gAMA chunk will only be written if it
9522 * is not between .45 and .46, or approximately (1.0/2.2).
9524 * If you exclude tRNS and the image has transparency, the colortype
9525 * is forced to be 4 or 6 (GRAY_ALPHA or RGB_ALPHA).
9527 * The -strip option causes StripImage() to set the png:include-chunk
9528 * artifact to "none,gama".
9531 mng_info->ping_exclude_bKGD=MagickFalse;
9532 mng_info->ping_exclude_cHRM=MagickFalse;
9533 mng_info->ping_exclude_EXIF=MagickFalse; /* hex-encoded EXIF in zTXt */
9534 mng_info->ping_exclude_gAMA=MagickFalse;
9535 mng_info->ping_exclude_cHRM=MagickFalse;
9536 mng_info->ping_exclude_iCCP=MagickFalse;
9537 /* mng_info->ping_exclude_iTXt=MagickFalse; */
9538 mng_info->ping_exclude_oFFs=MagickFalse;
9539 mng_info->ping_exclude_pHYs=MagickFalse;
9540 mng_info->ping_exclude_sRGB=MagickFalse;
9541 mng_info->ping_exclude_tEXt=MagickFalse;
9542 mng_info->ping_exclude_tRNS=MagickFalse;
9543 mng_info->ping_exclude_vpAg=MagickFalse;
9544 mng_info->ping_exclude_zCCP=MagickFalse; /* hex-encoded iCCP in zTXt */
9545 mng_info->ping_exclude_zTXt=MagickFalse;
9547 excluding=MagickFalse;
9549 for (source=0; source<1; source++)
9553 value=GetImageArtifact(image,"png:exclude-chunk");
9556 value=GetImageArtifact(image,"png:exclude-chunks");
9560 value=GetImageOption(image_info,"png:exclude-chunk");
9563 value=GetImageOption(image_info,"png:exclude-chunks");
9572 excluding=MagickTrue;
9574 if (logging != MagickFalse)
9577 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9578 " png:exclude-chunk=%s found in image artifacts.\n", value);
9580 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9581 " png:exclude-chunk=%s found in image properties.\n", value);
9586 for (i=0; i<(int) last; i+=5)
9589 if (LocaleNCompare(value+i,"all",3) == 0)
9591 mng_info->ping_exclude_bKGD=MagickTrue;
9592 mng_info->ping_exclude_cHRM=MagickTrue;
9593 mng_info->ping_exclude_EXIF=MagickTrue;
9594 mng_info->ping_exclude_gAMA=MagickTrue;
9595 mng_info->ping_exclude_iCCP=MagickTrue;
9596 /* mng_info->ping_exclude_iTXt=MagickTrue; */
9597 mng_info->ping_exclude_oFFs=MagickTrue;
9598 mng_info->ping_exclude_pHYs=MagickTrue;
9599 mng_info->ping_exclude_sRGB=MagickTrue;
9600 mng_info->ping_exclude_tEXt=MagickTrue;
9601 mng_info->ping_exclude_tRNS=MagickTrue;
9602 mng_info->ping_exclude_vpAg=MagickTrue;
9603 mng_info->ping_exclude_zCCP=MagickTrue;
9604 mng_info->ping_exclude_zTXt=MagickTrue;
9608 if (LocaleNCompare(value+i,"none",4) == 0)
9610 mng_info->ping_exclude_bKGD=MagickFalse;
9611 mng_info->ping_exclude_cHRM=MagickFalse;
9612 mng_info->ping_exclude_EXIF=MagickFalse;
9613 mng_info->ping_exclude_gAMA=MagickFalse;
9614 mng_info->ping_exclude_iCCP=MagickFalse;
9615 /* mng_info->ping_exclude_iTXt=MagickFalse; */
9616 mng_info->ping_exclude_oFFs=MagickFalse;
9617 mng_info->ping_exclude_pHYs=MagickFalse;
9618 mng_info->ping_exclude_sRGB=MagickFalse;
9619 mng_info->ping_exclude_tEXt=MagickFalse;
9620 mng_info->ping_exclude_tRNS=MagickFalse;
9621 mng_info->ping_exclude_vpAg=MagickFalse;
9622 mng_info->ping_exclude_zCCP=MagickFalse;
9623 mng_info->ping_exclude_zTXt=MagickFalse;
9626 if (LocaleNCompare(value+i,"bkgd",4) == 0)
9627 mng_info->ping_exclude_bKGD=MagickTrue;
9629 if (LocaleNCompare(value+i,"chrm",4) == 0)
9630 mng_info->ping_exclude_cHRM=MagickTrue;
9632 if (LocaleNCompare(value+i,"exif",4) == 0)
9633 mng_info->ping_exclude_EXIF=MagickTrue;
9635 if (LocaleNCompare(value+i,"gama",4) == 0)
9636 mng_info->ping_exclude_gAMA=MagickTrue;
9638 if (LocaleNCompare(value+i,"iccp",4) == 0)
9639 mng_info->ping_exclude_iCCP=MagickTrue;
9642 if (LocaleNCompare(value+i,"itxt",4) == 0)
9643 mng_info->ping_exclude_iTXt=MagickTrue;
9646 if (LocaleNCompare(value+i,"gama",4) == 0)
9647 mng_info->ping_exclude_gAMA=MagickTrue;
9649 if (LocaleNCompare(value+i,"offs",4) == 0)
9650 mng_info->ping_exclude_oFFs=MagickTrue;
9652 if (LocaleNCompare(value+i,"phys",4) == 0)
9653 mng_info->ping_exclude_pHYs=MagickTrue;
9655 if (LocaleNCompare(value+i,"srgb",4) == 0)
9656 mng_info->ping_exclude_sRGB=MagickTrue;
9658 if (LocaleNCompare(value+i,"text",4) == 0)
9659 mng_info->ping_exclude_tEXt=MagickTrue;
9661 if (LocaleNCompare(value+i,"trns",4) == 0)
9662 mng_info->ping_exclude_tRNS=MagickTrue;
9664 if (LocaleNCompare(value+i,"vpag",4) == 0)
9665 mng_info->ping_exclude_vpAg=MagickTrue;
9667 if (LocaleNCompare(value+i,"zccp",4) == 0)
9668 mng_info->ping_exclude_zCCP=MagickTrue;
9670 if (LocaleNCompare(value+i,"ztxt",4) == 0)
9671 mng_info->ping_exclude_zTXt=MagickTrue;
9677 for (source=0; source<1; source++)
9681 value=GetImageArtifact(image,"png:include-chunk");
9684 value=GetImageArtifact(image,"png:include-chunks");
9688 value=GetImageOption(image_info,"png:include-chunk");
9691 value=GetImageOption(image_info,"png:include-chunks");
9699 excluding=MagickTrue;
9701 if (logging != MagickFalse)
9704 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9705 " png:include-chunk=%s found in image artifacts.\n", value);
9707 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9708 " png:include-chunk=%s found in image properties.\n", value);
9713 for (i=0; i<(int) last; i+=5)
9715 if (LocaleNCompare(value+i,"all",3) == 0)
9717 mng_info->ping_exclude_bKGD=MagickFalse;
9718 mng_info->ping_exclude_cHRM=MagickFalse;
9719 mng_info->ping_exclude_EXIF=MagickFalse;
9720 mng_info->ping_exclude_gAMA=MagickFalse;
9721 mng_info->ping_exclude_iCCP=MagickFalse;
9722 /* mng_info->ping_exclude_iTXt=MagickFalse; */
9723 mng_info->ping_exclude_oFFs=MagickFalse;
9724 mng_info->ping_exclude_pHYs=MagickFalse;
9725 mng_info->ping_exclude_sRGB=MagickFalse;
9726 mng_info->ping_exclude_tEXt=MagickFalse;
9727 mng_info->ping_exclude_tRNS=MagickFalse;
9728 mng_info->ping_exclude_vpAg=MagickFalse;
9729 mng_info->ping_exclude_zCCP=MagickFalse;
9730 mng_info->ping_exclude_zTXt=MagickFalse;
9734 if (LocaleNCompare(value+i,"none",4) == 0)
9736 mng_info->ping_exclude_bKGD=MagickTrue;
9737 mng_info->ping_exclude_cHRM=MagickTrue;
9738 mng_info->ping_exclude_EXIF=MagickTrue;
9739 mng_info->ping_exclude_gAMA=MagickTrue;
9740 mng_info->ping_exclude_iCCP=MagickTrue;
9741 /* mng_info->ping_exclude_iTXt=MagickTrue; */
9742 mng_info->ping_exclude_oFFs=MagickTrue;
9743 mng_info->ping_exclude_pHYs=MagickTrue;
9744 mng_info->ping_exclude_sRGB=MagickTrue;
9745 mng_info->ping_exclude_tEXt=MagickTrue;
9746 mng_info->ping_exclude_tRNS=MagickTrue;
9747 mng_info->ping_exclude_vpAg=MagickTrue;
9748 mng_info->ping_exclude_zCCP=MagickTrue;
9749 mng_info->ping_exclude_zTXt=MagickTrue;
9752 if (LocaleNCompare(value+i,"bkgd",4) == 0)
9753 mng_info->ping_exclude_bKGD=MagickFalse;
9755 if (LocaleNCompare(value+i,"chrm",4) == 0)
9756 mng_info->ping_exclude_cHRM=MagickFalse;
9758 if (LocaleNCompare(value+i,"exif",4) == 0)
9759 mng_info->ping_exclude_EXIF=MagickFalse;
9761 if (LocaleNCompare(value+i,"gama",4) == 0)
9762 mng_info->ping_exclude_gAMA=MagickFalse;
9764 if (LocaleNCompare(value+i,"iccp",4) == 0)
9765 mng_info->ping_exclude_iCCP=MagickFalse;
9768 if (LocaleNCompare(value+i,"itxt",4) == 0)
9769 mng_info->ping_exclude_iTXt=MagickFalse;
9772 if (LocaleNCompare(value+i,"gama",4) == 0)
9773 mng_info->ping_exclude_gAMA=MagickFalse;
9775 if (LocaleNCompare(value+i,"offs",4) == 0)
9776 mng_info->ping_exclude_oFFs=MagickFalse;
9778 if (LocaleNCompare(value+i,"phys",4) == 0)
9779 mng_info->ping_exclude_pHYs=MagickFalse;
9781 if (LocaleNCompare(value+i,"srgb",4) == 0)
9782 mng_info->ping_exclude_sRGB=MagickFalse;
9784 if (LocaleNCompare(value+i,"text",4) == 0)
9785 mng_info->ping_exclude_tEXt=MagickFalse;
9787 if (LocaleNCompare(value+i,"trns",4) == 0)
9788 mng_info->ping_exclude_tRNS=MagickFalse;
9790 if (LocaleNCompare(value+i,"vpag",4) == 0)
9791 mng_info->ping_exclude_vpAg=MagickFalse;
9793 if (LocaleNCompare(value+i,"zccp",4) == 0)
9794 mng_info->ping_exclude_zCCP=MagickFalse;
9796 if (LocaleNCompare(value+i,"ztxt",4) == 0)
9797 mng_info->ping_exclude_zTXt=MagickFalse;
9803 if (excluding != MagickFalse && logging != MagickFalse)
9805 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9806 " Chunks to be excluded from the output PNG:");
9807 if (mng_info->ping_exclude_bKGD != MagickFalse)
9808 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9810 if (mng_info->ping_exclude_cHRM != MagickFalse)
9811 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9813 if (mng_info->ping_exclude_EXIF != MagickFalse)
9814 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9816 if (mng_info->ping_exclude_gAMA != MagickFalse)
9817 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9819 if (mng_info->ping_exclude_iCCP != MagickFalse)
9820 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9823 if (mng_info->ping_exclude_iTXt != MagickFalse)
9824 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9827 if (mng_info->ping_exclude_oFFs != MagickFalse)
9828 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9830 if (mng_info->ping_exclude_pHYs != MagickFalse)
9831 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9833 if (mng_info->ping_exclude_sRGB != MagickFalse)
9834 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9836 if (mng_info->ping_exclude_tEXt != MagickFalse)
9837 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9839 if (mng_info->ping_exclude_tRNS != MagickFalse)
9840 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9842 if (mng_info->ping_exclude_vpAg != MagickFalse)
9843 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9845 if (mng_info->ping_exclude_zCCP != MagickFalse)
9846 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9848 if (mng_info->ping_exclude_zTXt != MagickFalse)
9849 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9853 mng_info->need_blob = MagickTrue;
9855 status=WriteOnePNGImage(mng_info,image_info,image);
9857 MngInfoFreeStruct(mng_info,&have_mng_structure);
9859 if (logging != MagickFalse)
9860 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"exit WritePNGImage()");
9865 #if defined(JNG_SUPPORTED)
9867 /* Write one JNG image */
9868 static MagickBooleanType WriteOneJNGImage(MngInfo *mng_info,
9869 const ImageInfo *image_info,Image *image)
9890 jng_alpha_compression_method,
9891 jng_alpha_sample_depth,
9898 logging=LogMagickEvent(CoderEvent,GetMagickModule(),
9899 " enter WriteOneJNGImage()");
9901 blob=(unsigned char *) NULL;
9902 jpeg_image=(Image *) NULL;
9903 jpeg_image_info=(ImageInfo *) NULL;
9906 transparent=image_info->type==GrayscaleMatteType ||
9907 image_info->type==TrueColorMatteType;
9909 jng_alpha_sample_depth=0;
9910 jng_quality=image_info->quality == 0UL ? 75UL : image_info->quality;
9911 jng_alpha_compression_method=0;
9913 if (image->matte != MagickFalse)
9915 /* if any pixels are transparent */
9916 transparent=MagickTrue;
9917 if (image_info->compression==JPEGCompression)
9918 jng_alpha_compression_method=8;
9925 /* Create JPEG blob, image, and image_info */
9926 if (logging != MagickFalse)
9927 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9928 " Creating jpeg_image_info for opacity.");
9930 jpeg_image_info=(ImageInfo *) CloneImageInfo(image_info);
9932 if (jpeg_image_info == (ImageInfo *) NULL)
9933 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
9935 if (logging != MagickFalse)
9936 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9937 " Creating jpeg_image.");
9939 jpeg_image=CloneImage(image,0,0,MagickTrue,&image->exception);
9941 if (jpeg_image == (Image *) NULL)
9942 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
9944 (void) CopyMagickString(jpeg_image->magick,"JPEG",MaxTextExtent);
9945 status=SeparateImageChannel(jpeg_image,OpacityChannel);
9946 status=NegateImage(jpeg_image,MagickFalse);
9947 jpeg_image->matte=MagickFalse;
9949 if (jng_quality >= 1000)
9950 jpeg_image_info->quality=jng_quality/1000;
9953 jpeg_image_info->quality=jng_quality;
9955 jpeg_image_info->type=GrayscaleType;
9956 (void) SetImageType(jpeg_image,GrayscaleType);
9957 (void) AcquireUniqueFilename(jpeg_image->filename);
9958 (void) FormatMagickString(jpeg_image_info->filename,MaxTextExtent,
9959 "%s",jpeg_image->filename);
9962 /* To do: check bit depth of PNG alpha channel */
9964 /* Check if image is grayscale. */
9965 if (image_info->type != TrueColorMatteType && image_info->type !=
9966 TrueColorType && ImageIsGray(image))
9971 if (jng_alpha_compression_method==0)
9976 /* Encode opacity as a grayscale PNG blob */
9977 status=OpenBlob(jpeg_image_info,jpeg_image,WriteBinaryBlobMode,
9979 if (logging != MagickFalse)
9980 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9981 " Creating PNG blob.");
9984 (void) CopyMagickString(jpeg_image_info->magick,"PNG",MaxTextExtent);
9985 (void) CopyMagickString(jpeg_image->magick,"PNG",MaxTextExtent);
9986 jpeg_image_info->interlace=NoInterlace;
9988 blob=ImageToBlob(jpeg_image_info,jpeg_image,&length,
9991 /* Retrieve sample depth used */
9992 value=GetImageProperty(jpeg_image,"png:bit-depth-written");
9993 if (value != (char *) NULL)
9994 jng_alpha_sample_depth= (unsigned int) value[0];
9998 /* Encode opacity as a grayscale JPEG blob */
10000 status=OpenBlob(jpeg_image_info,jpeg_image,WriteBinaryBlobMode,
10001 &image->exception);
10003 (void) CopyMagickString(jpeg_image_info->magick,"JPEG",MaxTextExtent);
10004 (void) CopyMagickString(jpeg_image->magick,"JPEG",MaxTextExtent);
10005 jpeg_image_info->interlace=NoInterlace;
10006 if (logging != MagickFalse)
10007 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10008 " Creating blob.");
10009 blob=ImageToBlob(jpeg_image_info,jpeg_image,&length,
10010 &image->exception);
10011 jng_alpha_sample_depth=8;
10013 if (logging != MagickFalse)
10014 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10015 " Successfully read jpeg_image into a blob, length=%.20g.",
10019 /* Destroy JPEG image and image_info */
10020 jpeg_image=DestroyImage(jpeg_image);
10021 (void) RelinquishUniqueFileResource(jpeg_image_info->filename);
10022 jpeg_image_info=DestroyImageInfo(jpeg_image_info);
10025 /* Write JHDR chunk */
10026 (void) WriteBlobMSBULong(image,16L); /* chunk data length=16 */
10027 PNGType(chunk,mng_JHDR);
10028 LogPNGChunk(logging,mng_JHDR,16L);
10029 PNGLong(chunk+4,(png_uint_32) image->columns);
10030 PNGLong(chunk+8,(png_uint_32) image->rows);
10031 chunk[12]=jng_color_type;
10032 chunk[13]=8; /* sample depth */
10033 chunk[14]=8; /*jng_image_compression_method */
10034 chunk[15]=(unsigned char) (image_info->interlace == NoInterlace ? 0 : 8);
10035 chunk[16]=jng_alpha_sample_depth;
10036 chunk[17]=jng_alpha_compression_method;
10037 chunk[18]=0; /*jng_alpha_filter_method */
10038 chunk[19]=0; /*jng_alpha_interlace_method */
10039 (void) WriteBlob(image,20,chunk);
10040 (void) WriteBlobMSBULong(image,crc32(0,chunk,20));
10041 if (logging != MagickFalse)
10043 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10044 " JNG width:%15lu",(unsigned long) image->columns);
10046 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10047 " JNG height:%14lu",(unsigned long) image->rows);
10049 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10050 " JNG color type:%10d",jng_color_type);
10052 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10053 " JNG sample depth:%8d",8);
10055 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10056 " JNG compression:%9d",8);
10058 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10059 " JNG interlace:%11d",0);
10061 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10062 " JNG alpha depth:%9d",jng_alpha_sample_depth);
10064 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10065 " JNG alpha compression:%3d",jng_alpha_compression_method);
10067 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10068 " JNG alpha filter:%8d",0);
10070 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10071 " JNG alpha interlace:%5d",0);
10074 /* Write any JNG-chunk-b profiles */
10075 (void) Magick_png_write_chunk_from_profile(image,"JNG-chunk-b",logging);
10078 Write leading ancillary chunks
10084 Write JNG bKGD chunk
10095 if (jng_color_type == 8 || jng_color_type == 12)
10099 (void) WriteBlobMSBULong(image,(size_t) (num_bytes-4L));
10100 PNGType(chunk,mng_bKGD);
10101 LogPNGChunk(logging,mng_bKGD,(size_t) (num_bytes-4L));
10102 red=ScaleQuantumToChar(image->background_color.red);
10103 green=ScaleQuantumToChar(image->background_color.green);
10104 blue=ScaleQuantumToChar(image->background_color.blue);
10111 (void) WriteBlob(image,(size_t) num_bytes,chunk);
10112 (void) WriteBlobMSBULong(image,crc32(0,chunk,(uInt) num_bytes));
10115 if ((image->colorspace == sRGBColorspace || image->rendering_intent))
10118 Write JNG sRGB chunk
10120 (void) WriteBlobMSBULong(image,1L);
10121 PNGType(chunk,mng_sRGB);
10122 LogPNGChunk(logging,mng_sRGB,1L);
10124 if (image->rendering_intent != UndefinedIntent)
10125 chunk[4]=(unsigned char)
10126 Magick_RenderingIntent_to_PNG_RenderingIntent(
10127 (image->rendering_intent));
10130 chunk[4]=(unsigned char)
10131 Magick_RenderingIntent_to_PNG_RenderingIntent(
10132 (PerceptualIntent));
10134 (void) WriteBlob(image,5,chunk);
10135 (void) WriteBlobMSBULong(image,crc32(0,chunk,5));
10139 if (image->gamma != 0.0)
10142 Write JNG gAMA chunk
10144 (void) WriteBlobMSBULong(image,4L);
10145 PNGType(chunk,mng_gAMA);
10146 LogPNGChunk(logging,mng_gAMA,4L);
10147 PNGLong(chunk+4,(png_uint_32) (100000*image->gamma+0.5));
10148 (void) WriteBlob(image,8,chunk);
10149 (void) WriteBlobMSBULong(image,crc32(0,chunk,8));
10152 if ((mng_info->equal_chrms == MagickFalse) &&
10153 (image->chromaticity.red_primary.x != 0.0))
10159 Write JNG cHRM chunk
10161 (void) WriteBlobMSBULong(image,32L);
10162 PNGType(chunk,mng_cHRM);
10163 LogPNGChunk(logging,mng_cHRM,32L);
10164 primary=image->chromaticity.white_point;
10165 PNGLong(chunk+4,(png_uint_32) (100000*primary.x+0.5));
10166 PNGLong(chunk+8,(png_uint_32) (100000*primary.y+0.5));
10167 primary=image->chromaticity.red_primary;
10168 PNGLong(chunk+12,(png_uint_32) (100000*primary.x+0.5));
10169 PNGLong(chunk+16,(png_uint_32) (100000*primary.y+0.5));
10170 primary=image->chromaticity.green_primary;
10171 PNGLong(chunk+20,(png_uint_32) (100000*primary.x+0.5));
10172 PNGLong(chunk+24,(png_uint_32) (100000*primary.y+0.5));
10173 primary=image->chromaticity.blue_primary;
10174 PNGLong(chunk+28,(png_uint_32) (100000*primary.x+0.5));
10175 PNGLong(chunk+32,(png_uint_32) (100000*primary.y+0.5));
10176 (void) WriteBlob(image,36,chunk);
10177 (void) WriteBlobMSBULong(image,crc32(0,chunk,36));
10181 if (image->x_resolution && image->y_resolution && !mng_info->equal_physs)
10184 Write JNG pHYs chunk
10186 (void) WriteBlobMSBULong(image,9L);
10187 PNGType(chunk,mng_pHYs);
10188 LogPNGChunk(logging,mng_pHYs,9L);
10189 if (image->units == PixelsPerInchResolution)
10191 PNGLong(chunk+4,(png_uint_32)
10192 (image->x_resolution*100.0/2.54+0.5));
10194 PNGLong(chunk+8,(png_uint_32)
10195 (image->y_resolution*100.0/2.54+0.5));
10202 if (image->units == PixelsPerCentimeterResolution)
10204 PNGLong(chunk+4,(png_uint_32)
10205 (image->x_resolution*100.0+0.5));
10207 PNGLong(chunk+8,(png_uint_32)
10208 (image->y_resolution*100.0+0.5));
10215 PNGLong(chunk+4,(png_uint_32) (image->x_resolution+0.5));
10216 PNGLong(chunk+8,(png_uint_32) (image->y_resolution+0.5));
10220 (void) WriteBlob(image,13,chunk);
10221 (void) WriteBlobMSBULong(image,crc32(0,chunk,13));
10224 if (mng_info->write_mng == 0 && (image->page.x || image->page.y))
10227 Write JNG oFFs chunk
10229 (void) WriteBlobMSBULong(image,9L);
10230 PNGType(chunk,mng_oFFs);
10231 LogPNGChunk(logging,mng_oFFs,9L);
10232 PNGsLong(chunk+4,(ssize_t) (image->page.x));
10233 PNGsLong(chunk+8,(ssize_t) (image->page.y));
10235 (void) WriteBlob(image,13,chunk);
10236 (void) WriteBlobMSBULong(image,crc32(0,chunk,13));
10238 if (mng_info->write_mng == 0 && (image->page.width || image->page.height))
10240 (void) WriteBlobMSBULong(image,9L); /* data length=8 */
10241 PNGType(chunk,mng_vpAg);
10242 LogPNGChunk(logging,mng_vpAg,9L);
10243 PNGLong(chunk+4,(png_uint_32) image->page.width);
10244 PNGLong(chunk+8,(png_uint_32) image->page.height);
10245 chunk[12]=0; /* unit = pixels */
10246 (void) WriteBlob(image,13,chunk);
10247 (void) WriteBlobMSBULong(image,crc32(0,chunk,13));
10253 if (jng_alpha_compression_method==0)
10261 /* Write IDAT chunk header */
10262 if (logging != MagickFalse)
10263 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10264 " Write IDAT chunks from blob, length=%.20g.",(double)
10267 /* Copy IDAT chunks */
10270 for (i=8; i<(ssize_t) length; i+=len+12)
10272 len=(*p<<24)|((*(p+1))<<16)|((*(p+2))<<8)|(*(p+3));
10275 if (*(p)==73 && *(p+1)==68 && *(p+2)==65 && *(p+3)==84) /* IDAT */
10277 /* Found an IDAT chunk. */
10278 (void) WriteBlobMSBULong(image,(size_t) len);
10279 LogPNGChunk(logging,mng_IDAT,(size_t) len);
10280 (void) WriteBlob(image,(size_t) len+4,p);
10281 (void) WriteBlobMSBULong(image,
10282 crc32(0,p,(uInt) len+4));
10287 if (logging != MagickFalse)
10288 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10289 " Skipping %c%c%c%c chunk, length=%.20g.",
10290 *(p),*(p+1),*(p+2),*(p+3),(double) len);
10297 /* Write JDAA chunk header */
10298 if (logging != MagickFalse)
10299 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10300 " Write JDAA chunk, length=%.20g.",(double) length);
10301 (void) WriteBlobMSBULong(image,(size_t) length);
10302 PNGType(chunk,mng_JDAA);
10303 LogPNGChunk(logging,mng_JDAA,length);
10304 /* Write JDAT chunk(s) data */
10305 (void) WriteBlob(image,4,chunk);
10306 (void) WriteBlob(image,length,blob);
10307 (void) WriteBlobMSBULong(image,crc32(crc32(0,chunk,4),blob,
10310 blob=(unsigned char *) RelinquishMagickMemory(blob);
10313 /* Encode image as a JPEG blob */
10314 if (logging != MagickFalse)
10315 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10316 " Creating jpeg_image_info.");
10317 jpeg_image_info=(ImageInfo *) CloneImageInfo(image_info);
10318 if (jpeg_image_info == (ImageInfo *) NULL)
10319 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
10321 if (logging != MagickFalse)
10322 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10323 " Creating jpeg_image.");
10325 jpeg_image=CloneImage(image,0,0,MagickTrue,&image->exception);
10326 if (jpeg_image == (Image *) NULL)
10327 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
10328 (void) CopyMagickString(jpeg_image->magick,"JPEG",MaxTextExtent);
10330 (void) AcquireUniqueFilename(jpeg_image->filename);
10331 (void) FormatMagickString(jpeg_image_info->filename,MaxTextExtent,"%s",
10332 jpeg_image->filename);
10334 status=OpenBlob(jpeg_image_info,jpeg_image,WriteBinaryBlobMode,
10335 &image->exception);
10337 if (logging != MagickFalse)
10338 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10339 " Created jpeg_image, %.20g x %.20g.",(double) jpeg_image->columns,
10340 (double) jpeg_image->rows);
10342 if (jng_color_type == 8 || jng_color_type == 12)
10343 jpeg_image_info->type=GrayscaleType;
10345 jpeg_image_info->quality=jng_quality % 1000;
10346 (void) CopyMagickString(jpeg_image_info->magick,"JPEG",MaxTextExtent);
10347 (void) CopyMagickString(jpeg_image->magick,"JPEG",MaxTextExtent);
10349 if (logging != MagickFalse)
10350 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10351 " Creating blob.");
10353 blob=ImageToBlob(jpeg_image_info,jpeg_image,&length,&image->exception);
10355 if (logging != MagickFalse)
10357 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10358 " Successfully read jpeg_image into a blob, length=%.20g.",
10361 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10362 " Write JDAT chunk, length=%.20g.",(double) length);
10365 /* Write JDAT chunk(s) */
10366 (void) WriteBlobMSBULong(image,(size_t) length);
10367 PNGType(chunk,mng_JDAT);
10368 LogPNGChunk(logging,mng_JDAT,length);
10369 (void) WriteBlob(image,4,chunk);
10370 (void) WriteBlob(image,length,blob);
10371 (void) WriteBlobMSBULong(image,crc32(crc32(0,chunk,4),blob,(uInt) length));
10373 jpeg_image=DestroyImage(jpeg_image);
10374 (void) RelinquishUniqueFileResource(jpeg_image_info->filename);
10375 jpeg_image_info=DestroyImageInfo(jpeg_image_info);
10376 blob=(unsigned char *) RelinquishMagickMemory(blob);
10378 /* Write any JNG-chunk-e profiles */
10379 (void) Magick_png_write_chunk_from_profile(image,"JNG-chunk-e",logging);
10381 /* Write IEND chunk */
10382 (void) WriteBlobMSBULong(image,0L);
10383 PNGType(chunk,mng_IEND);
10384 LogPNGChunk(logging,mng_IEND,0);
10385 (void) WriteBlob(image,4,chunk);
10386 (void) WriteBlobMSBULong(image,crc32(0,chunk,4));
10388 if (logging != MagickFalse)
10389 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10390 " exit WriteOneJNGImage()");
10397 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
10401 % W r i t e J N G I m a g e %
10405 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
10407 % WriteJNGImage() writes a JPEG Network Graphics (JNG) image file.
10409 % JNG support written by Glenn Randers-Pehrson, glennrp@image...
10411 % The format of the WriteJNGImage method is:
10413 % MagickBooleanType WriteJNGImage(const ImageInfo *image_info,Image *image)
10415 % A description of each parameter follows:
10417 % o image_info: the image info.
10419 % o image: The image.
10421 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
10423 static MagickBooleanType WriteJNGImage(const ImageInfo *image_info,Image *image)
10426 have_mng_structure,
10436 assert(image_info != (const ImageInfo *) NULL);
10437 assert(image_info->signature == MagickSignature);
10438 assert(image != (Image *) NULL);
10439 assert(image->signature == MagickSignature);
10440 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
10441 logging=LogMagickEvent(CoderEvent,GetMagickModule(),"enter WriteJNGImage()");
10442 status=OpenBlob(image_info,image,WriteBinaryBlobMode,&image->exception);
10443 if (status == MagickFalse)
10447 Allocate a MngInfo structure.
10449 have_mng_structure=MagickFalse;
10450 mng_info=(MngInfo *) AcquireMagickMemory(sizeof(MngInfo));
10451 if (mng_info == (MngInfo *) NULL)
10452 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
10454 Initialize members of the MngInfo structure.
10456 (void) ResetMagickMemory(mng_info,0,sizeof(MngInfo));
10457 mng_info->image=image;
10458 have_mng_structure=MagickTrue;
10460 (void) WriteBlob(image,8,(const unsigned char *) "\213JNG\r\n\032\n");
10462 status=WriteOneJNGImage(mng_info,image_info,image);
10463 (void) CloseBlob(image);
10465 (void) CatchImageException(image);
10466 MngInfoFreeStruct(mng_info,&have_mng_structure);
10467 if (logging != MagickFalse)
10468 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"exit WriteJNGImage()");
10475 static MagickBooleanType WriteMNGImage(const ImageInfo *image_info,Image *image)
10484 have_mng_structure,
10487 volatile MagickBooleanType
10499 #if defined(PNG_WRITE_EMPTY_PLTE_SUPPORTED) || \
10500 defined(PNG_MNG_FEATURES_SUPPORTED)
10503 all_images_are_gray,
10513 volatile unsigned int
10524 #if (PNG_LIBPNG_VER < 10200)
10525 if (image_info->verbose)
10526 printf("Your PNG library (libpng-%s) is rather old.\n",
10527 PNG_LIBPNG_VER_STRING);
10533 assert(image_info != (const ImageInfo *) NULL);
10534 assert(image_info->signature == MagickSignature);
10535 assert(image != (Image *) NULL);
10536 assert(image->signature == MagickSignature);
10537 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
10538 logging=LogMagickEvent(CoderEvent,GetMagickModule(),"enter WriteMNGImage()");
10539 status=OpenBlob(image_info,image,WriteBinaryBlobMode,&image->exception);
10540 if (status == MagickFalse)
10544 Allocate a MngInfo structure.
10546 have_mng_structure=MagickFalse;
10547 mng_info=(MngInfo *) AcquireMagickMemory(sizeof(MngInfo));
10548 if (mng_info == (MngInfo *) NULL)
10549 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
10551 Initialize members of the MngInfo structure.
10553 (void) ResetMagickMemory(mng_info,0,sizeof(MngInfo));
10554 mng_info->image=image;
10555 have_mng_structure=MagickTrue;
10556 write_mng=LocaleCompare(image_info->magick,"MNG") == 0;
10559 * See if user has requested a specific PNG subformat to be used
10560 * for all of the PNGs in the MNG being written, e.g.,
10562 * convert *.png png8:animation.mng
10564 * To do: check -define png:bit_depth and png:color_type as well,
10565 * or perhaps use mng:bit_depth and mng:color_type instead for
10569 mng_info->write_png8=LocaleCompare(image_info->magick,"PNG8") == 0;
10570 mng_info->write_png24=LocaleCompare(image_info->magick,"PNG24") == 0;
10571 mng_info->write_png32=LocaleCompare(image_info->magick,"PNG32") == 0;
10573 write_jng=MagickFalse;
10574 if (image_info->compression == JPEGCompression)
10575 write_jng=MagickTrue;
10577 mng_info->adjoin=image_info->adjoin &&
10578 (GetNextImageInList(image) != (Image *) NULL) && write_mng;
10580 if (logging != MagickFalse)
10582 /* Log some info about the input */
10586 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10587 " Checking input image(s)");
10589 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10590 " Image_info depth: %.20g",(double) image_info->depth);
10592 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10593 " Type: %d",image_info->type);
10596 for (p=image; p != (Image *) NULL; p=GetNextImageInList(p))
10598 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10599 " Scene: %.20g",(double) scene++);
10601 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10602 " Image depth: %.20g",(double) p->depth);
10605 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10609 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10612 if (p->storage_class == PseudoClass)
10613 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10614 " Storage class: PseudoClass");
10617 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10618 " Storage class: DirectClass");
10621 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10622 " Number of colors: %.20g",(double) p->colors);
10625 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10626 " Number of colors: unspecified");
10628 if (mng_info->adjoin == MagickFalse)
10633 use_global_plte=MagickFalse;
10634 all_images_are_gray=MagickFalse;
10635 #ifdef PNG_WRITE_EMPTY_PLTE_SUPPORTED
10636 need_local_plte=MagickTrue;
10638 need_defi=MagickFalse;
10639 need_matte=MagickFalse;
10640 mng_info->framing_mode=1;
10641 mng_info->old_framing_mode=1;
10644 if (image_info->page != (char *) NULL)
10647 Determine image bounding box.
10649 SetGeometry(image,&mng_info->page);
10650 (void) ParseMetaGeometry(image_info->page,&mng_info->page.x,
10651 &mng_info->page.y,&mng_info->page.width,&mng_info->page.height);
10663 mng_info->page=image->page;
10664 need_geom=MagickTrue;
10665 if (mng_info->page.width || mng_info->page.height)
10666 need_geom=MagickFalse;
10668 Check all the scenes.
10670 initial_delay=image->delay;
10671 need_iterations=MagickFalse;
10672 mng_info->equal_chrms=image->chromaticity.red_primary.x != 0.0;
10673 mng_info->equal_physs=MagickTrue,
10674 mng_info->equal_gammas=MagickTrue;
10675 mng_info->equal_srgbs=MagickTrue;
10676 mng_info->equal_backgrounds=MagickTrue;
10678 #if defined(PNG_WRITE_EMPTY_PLTE_SUPPORTED) || \
10679 defined(PNG_MNG_FEATURES_SUPPORTED)
10680 all_images_are_gray=MagickTrue;
10681 mng_info->equal_palettes=MagickFalse;
10682 need_local_plte=MagickFalse;
10684 for (next_image=image; next_image != (Image *) NULL; )
10688 if ((next_image->columns+next_image->page.x) > mng_info->page.width)
10689 mng_info->page.width=next_image->columns+next_image->page.x;
10691 if ((next_image->rows+next_image->page.y) > mng_info->page.height)
10692 mng_info->page.height=next_image->rows+next_image->page.y;
10695 if (next_image->page.x || next_image->page.y)
10696 need_defi=MagickTrue;
10698 if (next_image->matte)
10699 need_matte=MagickTrue;
10701 if ((int) next_image->dispose >= BackgroundDispose)
10702 if (next_image->matte || next_image->page.x || next_image->page.y ||
10703 ((next_image->columns < mng_info->page.width) &&
10704 (next_image->rows < mng_info->page.height)))
10705 mng_info->need_fram=MagickTrue;
10707 if (next_image->iterations)
10708 need_iterations=MagickTrue;
10710 final_delay=next_image->delay;
10712 if (final_delay != initial_delay || final_delay > 1UL*
10713 next_image->ticks_per_second)
10714 mng_info->need_fram=1;
10716 #if defined(PNG_WRITE_EMPTY_PLTE_SUPPORTED) || \
10717 defined(PNG_MNG_FEATURES_SUPPORTED)
10719 check for global palette possibility.
10721 if (image->matte != MagickFalse)
10722 need_local_plte=MagickTrue;
10724 if (need_local_plte == 0)
10726 if (ImageIsGray(image) == MagickFalse)
10727 all_images_are_gray=MagickFalse;
10728 mng_info->equal_palettes=PalettesAreEqual(image,next_image);
10729 if (use_global_plte == 0)
10730 use_global_plte=mng_info->equal_palettes;
10731 need_local_plte=!mng_info->equal_palettes;
10734 if (GetNextImageInList(next_image) != (Image *) NULL)
10736 if (next_image->background_color.red !=
10737 next_image->next->background_color.red ||
10738 next_image->background_color.green !=
10739 next_image->next->background_color.green ||
10740 next_image->background_color.blue !=
10741 next_image->next->background_color.blue)
10742 mng_info->equal_backgrounds=MagickFalse;
10744 if (next_image->gamma != next_image->next->gamma)
10745 mng_info->equal_gammas=MagickFalse;
10747 if (next_image->rendering_intent !=
10748 next_image->next->rendering_intent)
10749 mng_info->equal_srgbs=MagickFalse;
10751 if ((next_image->units != next_image->next->units) ||
10752 (next_image->x_resolution != next_image->next->x_resolution) ||
10753 (next_image->y_resolution != next_image->next->y_resolution))
10754 mng_info->equal_physs=MagickFalse;
10756 if (mng_info->equal_chrms)
10758 if (next_image->chromaticity.red_primary.x !=
10759 next_image->next->chromaticity.red_primary.x ||
10760 next_image->chromaticity.red_primary.y !=
10761 next_image->next->chromaticity.red_primary.y ||
10762 next_image->chromaticity.green_primary.x !=
10763 next_image->next->chromaticity.green_primary.x ||
10764 next_image->chromaticity.green_primary.y !=
10765 next_image->next->chromaticity.green_primary.y ||
10766 next_image->chromaticity.blue_primary.x !=
10767 next_image->next->chromaticity.blue_primary.x ||
10768 next_image->chromaticity.blue_primary.y !=
10769 next_image->next->chromaticity.blue_primary.y ||
10770 next_image->chromaticity.white_point.x !=
10771 next_image->next->chromaticity.white_point.x ||
10772 next_image->chromaticity.white_point.y !=
10773 next_image->next->chromaticity.white_point.y)
10774 mng_info->equal_chrms=MagickFalse;
10778 next_image=GetNextImageInList(next_image);
10780 if (image_count < 2)
10782 mng_info->equal_backgrounds=MagickFalse;
10783 mng_info->equal_chrms=MagickFalse;
10784 mng_info->equal_gammas=MagickFalse;
10785 mng_info->equal_srgbs=MagickFalse;
10786 mng_info->equal_physs=MagickFalse;
10787 use_global_plte=MagickFalse;
10788 #ifdef PNG_WRITE_EMPTY_PLTE_SUPPORTED
10789 need_local_plte=MagickTrue;
10791 need_iterations=MagickFalse;
10794 if (mng_info->need_fram == MagickFalse)
10797 Only certain framing rates 100/n are exactly representable without
10798 the FRAM chunk but we'll allow some slop in VLC files
10800 if (final_delay == 0)
10802 if (need_iterations != MagickFalse)
10805 It's probably a GIF with loop; don't run it *too* fast.
10807 if (mng_info->adjoin)
10810 (void) ThrowMagickException(&image->exception,
10811 GetMagickModule(),CoderWarning,
10812 "input has zero delay between all frames; assuming",
10817 mng_info->ticks_per_second=0;
10819 if (final_delay != 0)
10820 mng_info->ticks_per_second=(png_uint_32)
10821 (image->ticks_per_second/final_delay);
10822 if (final_delay > 50)
10823 mng_info->ticks_per_second=2;
10825 if (final_delay > 75)
10826 mng_info->ticks_per_second=1;
10828 if (final_delay > 125)
10829 mng_info->need_fram=MagickTrue;
10831 if (need_defi && final_delay > 2 && (final_delay != 4) &&
10832 (final_delay != 5) && (final_delay != 10) && (final_delay != 20) &&
10833 (final_delay != 25) && (final_delay != 50) && (final_delay !=
10834 1UL*image->ticks_per_second))
10835 mng_info->need_fram=MagickTrue; /* make it exact; cannot be VLC */
10838 if (mng_info->need_fram != MagickFalse)
10839 mng_info->ticks_per_second=1UL*image->ticks_per_second;
10841 If pseudocolor, we should also check to see if all the
10842 palettes are identical and write a global PLTE if they are.
10846 Write the MNG version 1.0 signature and MHDR chunk.
10848 (void) WriteBlob(image,8,(const unsigned char *) "\212MNG\r\n\032\n");
10849 (void) WriteBlobMSBULong(image,28L); /* chunk data length=28 */
10850 PNGType(chunk,mng_MHDR);
10851 LogPNGChunk(logging,mng_MHDR,28L);
10852 PNGLong(chunk+4,(png_uint_32) mng_info->page.width);
10853 PNGLong(chunk+8,(png_uint_32) mng_info->page.height);
10854 PNGLong(chunk+12,mng_info->ticks_per_second);
10855 PNGLong(chunk+16,0L); /* layer count=unknown */
10856 PNGLong(chunk+20,0L); /* frame count=unknown */
10857 PNGLong(chunk+24,0L); /* play time=unknown */
10862 if (need_defi || mng_info->need_fram || use_global_plte)
10863 PNGLong(chunk+28,27L); /* simplicity=LC+JNG */
10866 PNGLong(chunk+28,25L); /* simplicity=VLC+JNG */
10871 if (need_defi || mng_info->need_fram || use_global_plte)
10872 PNGLong(chunk+28,19L); /* simplicity=LC+JNG, no transparency */
10875 PNGLong(chunk+28,17L); /* simplicity=VLC+JNG, no transparency */
10883 if (need_defi || mng_info->need_fram || use_global_plte)
10884 PNGLong(chunk+28,11L); /* simplicity=LC */
10887 PNGLong(chunk+28,9L); /* simplicity=VLC */
10892 if (need_defi || mng_info->need_fram || use_global_plte)
10893 PNGLong(chunk+28,3L); /* simplicity=LC, no transparency */
10896 PNGLong(chunk+28,1L); /* simplicity=VLC, no transparency */
10899 (void) WriteBlob(image,32,chunk);
10900 (void) WriteBlobMSBULong(image,crc32(0,chunk,32));
10901 option=GetImageOption(image_info,"mng:need-cacheoff");
10902 if (option != (const char *) NULL)
10908 Write "nEED CACHEOFF" to turn playback caching off for streaming MNG.
10910 PNGType(chunk,mng_nEED);
10911 length=CopyMagickString((char *) chunk+4,"CACHEOFF",20);
10912 (void) WriteBlobMSBULong(image,(size_t) length);
10913 LogPNGChunk(logging,mng_nEED,(size_t) length);
10915 (void) WriteBlob(image,length,chunk);
10916 (void) WriteBlobMSBULong(image,crc32(0,chunk,(uInt) length));
10918 if ((GetPreviousImageInList(image) == (Image *) NULL) &&
10919 (GetNextImageInList(image) != (Image *) NULL) &&
10920 (image->iterations != 1))
10923 Write MNG TERM chunk
10925 (void) WriteBlobMSBULong(image,10L); /* data length=10 */
10926 PNGType(chunk,mng_TERM);
10927 LogPNGChunk(logging,mng_TERM,10L);
10928 chunk[4]=3; /* repeat animation */
10929 chunk[5]=0; /* show last frame when done */
10930 PNGLong(chunk+6,(png_uint_32) (mng_info->ticks_per_second*
10931 final_delay/MagickMax(image->ticks_per_second,1)));
10933 if (image->iterations == 0)
10934 PNGLong(chunk+10,PNG_UINT_31_MAX);
10937 PNGLong(chunk+10,(png_uint_32) image->iterations);
10939 if (logging != MagickFalse)
10941 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10942 " TERM delay: %.20g",(double) (mng_info->ticks_per_second*
10943 final_delay/MagickMax(image->ticks_per_second,1)));
10945 if (image->iterations == 0)
10946 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10947 " TERM iterations: %.20g",(double) PNG_UINT_31_MAX);
10950 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10951 " Image iterations: %.20g",(double) image->iterations);
10953 (void) WriteBlob(image,14,chunk);
10954 (void) WriteBlobMSBULong(image,crc32(0,chunk,14));
10957 To do: check for cHRM+gAMA == sRGB, and write sRGB instead.
10959 if ((image->colorspace == sRGBColorspace || image->rendering_intent) &&
10960 mng_info->equal_srgbs)
10963 Write MNG sRGB chunk
10965 (void) WriteBlobMSBULong(image,1L);
10966 PNGType(chunk,mng_sRGB);
10967 LogPNGChunk(logging,mng_sRGB,1L);
10969 if (image->rendering_intent != UndefinedIntent)
10970 chunk[4]=(unsigned char)
10971 Magick_RenderingIntent_to_PNG_RenderingIntent(
10972 (image->rendering_intent));
10975 chunk[4]=(unsigned char)
10976 Magick_RenderingIntent_to_PNG_RenderingIntent(
10977 (PerceptualIntent));
10979 (void) WriteBlob(image,5,chunk);
10980 (void) WriteBlobMSBULong(image,crc32(0,chunk,5));
10981 mng_info->have_write_global_srgb=MagickTrue;
10986 if (image->gamma && mng_info->equal_gammas)
10989 Write MNG gAMA chunk
10991 (void) WriteBlobMSBULong(image,4L);
10992 PNGType(chunk,mng_gAMA);
10993 LogPNGChunk(logging,mng_gAMA,4L);
10994 PNGLong(chunk+4,(png_uint_32) (100000*image->gamma+0.5));
10995 (void) WriteBlob(image,8,chunk);
10996 (void) WriteBlobMSBULong(image,crc32(0,chunk,8));
10997 mng_info->have_write_global_gama=MagickTrue;
10999 if (mng_info->equal_chrms)
11005 Write MNG cHRM chunk
11007 (void) WriteBlobMSBULong(image,32L);
11008 PNGType(chunk,mng_cHRM);
11009 LogPNGChunk(logging,mng_cHRM,32L);
11010 primary=image->chromaticity.white_point;
11011 PNGLong(chunk+4,(png_uint_32) (100000*primary.x+0.5));
11012 PNGLong(chunk+8,(png_uint_32) (100000*primary.y+0.5));
11013 primary=image->chromaticity.red_primary;
11014 PNGLong(chunk+12,(png_uint_32) (100000*primary.x+0.5));
11015 PNGLong(chunk+16,(png_uint_32) (100000*primary.y+0.5));
11016 primary=image->chromaticity.green_primary;
11017 PNGLong(chunk+20,(png_uint_32) (100000*primary.x+0.5));
11018 PNGLong(chunk+24,(png_uint_32) (100000*primary.y+0.5));
11019 primary=image->chromaticity.blue_primary;
11020 PNGLong(chunk+28,(png_uint_32) (100000*primary.x+0.5));
11021 PNGLong(chunk+32,(png_uint_32) (100000*primary.y+0.5));
11022 (void) WriteBlob(image,36,chunk);
11023 (void) WriteBlobMSBULong(image,crc32(0,chunk,36));
11024 mng_info->have_write_global_chrm=MagickTrue;
11027 if (image->x_resolution && image->y_resolution && mng_info->equal_physs)
11030 Write MNG pHYs chunk
11032 (void) WriteBlobMSBULong(image,9L);
11033 PNGType(chunk,mng_pHYs);
11034 LogPNGChunk(logging,mng_pHYs,9L);
11036 if (image->units == PixelsPerInchResolution)
11038 PNGLong(chunk+4,(png_uint_32)
11039 (image->x_resolution*100.0/2.54+0.5));
11041 PNGLong(chunk+8,(png_uint_32)
11042 (image->y_resolution*100.0/2.54+0.5));
11049 if (image->units == PixelsPerCentimeterResolution)
11051 PNGLong(chunk+4,(png_uint_32)
11052 (image->x_resolution*100.0+0.5));
11054 PNGLong(chunk+8,(png_uint_32)
11055 (image->y_resolution*100.0+0.5));
11062 PNGLong(chunk+4,(png_uint_32) (image->x_resolution+0.5));
11063 PNGLong(chunk+8,(png_uint_32) (image->y_resolution+0.5));
11067 (void) WriteBlob(image,13,chunk);
11068 (void) WriteBlobMSBULong(image,crc32(0,chunk,13));
11071 Write MNG BACK chunk and global bKGD chunk, if the image is transparent
11072 or does not cover the entire frame.
11074 if (write_mng && (image->matte || image->page.x > 0 ||
11075 image->page.y > 0 || (image->page.width &&
11076 (image->page.width+image->page.x < mng_info->page.width))
11077 || (image->page.height && (image->page.height+image->page.y
11078 < mng_info->page.height))))
11080 (void) WriteBlobMSBULong(image,6L);
11081 PNGType(chunk,mng_BACK);
11082 LogPNGChunk(logging,mng_BACK,6L);
11083 red=ScaleQuantumToShort(image->background_color.red);
11084 green=ScaleQuantumToShort(image->background_color.green);
11085 blue=ScaleQuantumToShort(image->background_color.blue);
11086 PNGShort(chunk+4,red);
11087 PNGShort(chunk+6,green);
11088 PNGShort(chunk+8,blue);
11089 (void) WriteBlob(image,10,chunk);
11090 (void) WriteBlobMSBULong(image,crc32(0,chunk,10));
11091 if (mng_info->equal_backgrounds)
11093 (void) WriteBlobMSBULong(image,6L);
11094 PNGType(chunk,mng_bKGD);
11095 LogPNGChunk(logging,mng_bKGD,6L);
11096 (void) WriteBlob(image,10,chunk);
11097 (void) WriteBlobMSBULong(image,crc32(0,chunk,10));
11101 #ifdef PNG_WRITE_EMPTY_PLTE_SUPPORTED
11102 if ((need_local_plte == MagickFalse) &&
11103 (image->storage_class == PseudoClass) &&
11104 (all_images_are_gray == MagickFalse))
11110 Write MNG PLTE chunk
11112 data_length=3*image->colors;
11113 (void) WriteBlobMSBULong(image,data_length);
11114 PNGType(chunk,mng_PLTE);
11115 LogPNGChunk(logging,mng_PLTE,data_length);
11117 for (i=0; i < (ssize_t) image->colors; i++)
11119 chunk[4+i*3]=ScaleQuantumToChar(image->colormap[i].red) & 0xff;
11120 chunk[5+i*3]=ScaleQuantumToChar(image->colormap[i].green) & 0xff;
11121 chunk[6+i*3]=ScaleQuantumToChar(image->colormap[i].blue) & 0xff;
11124 (void) WriteBlob(image,data_length+4,chunk);
11125 (void) WriteBlobMSBULong(image,crc32(0,chunk,(uInt) (data_length+4)));
11126 mng_info->have_write_global_plte=MagickTrue;
11132 #if defined(PNG_WRITE_EMPTY_PLTE_SUPPORTED) || \
11133 defined(PNG_MNG_FEATURES_SUPPORTED)
11134 mng_info->equal_palettes=MagickFalse;
11138 if (mng_info->adjoin)
11140 #if defined(PNG_WRITE_EMPTY_PLTE_SUPPORTED) || \
11141 defined(PNG_MNG_FEATURES_SUPPORTED)
11143 If we aren't using a global palette for the entire MNG, check to
11144 see if we can use one for two or more consecutive images.
11146 if (need_local_plte && use_global_plte && !all_images_are_gray)
11148 if (mng_info->IsPalette)
11151 When equal_palettes is true, this image has the same palette
11152 as the previous PseudoClass image
11154 mng_info->have_write_global_plte=mng_info->equal_palettes;
11155 mng_info->equal_palettes=PalettesAreEqual(image,image->next);
11156 if (mng_info->equal_palettes && !mng_info->have_write_global_plte)
11159 Write MNG PLTE chunk
11164 data_length=3*image->colors;
11165 (void) WriteBlobMSBULong(image,data_length);
11166 PNGType(chunk,mng_PLTE);
11167 LogPNGChunk(logging,mng_PLTE,data_length);
11169 for (i=0; i < (ssize_t) image->colors; i++)
11171 chunk[4+i*3]=ScaleQuantumToChar(image->colormap[i].red);
11172 chunk[5+i*3]=ScaleQuantumToChar(image->colormap[i].green);
11173 chunk[6+i*3]=ScaleQuantumToChar(image->colormap[i].blue);
11176 (void) WriteBlob(image,data_length+4,chunk);
11177 (void) WriteBlobMSBULong(image,crc32(0,chunk,
11178 (uInt) (data_length+4)));
11179 mng_info->have_write_global_plte=MagickTrue;
11183 mng_info->have_write_global_plte=MagickFalse;
11194 previous_x=mng_info->page.x;
11195 previous_y=mng_info->page.y;
11202 mng_info->page=image->page;
11203 if ((mng_info->page.x != previous_x) ||
11204 (mng_info->page.y != previous_y))
11206 (void) WriteBlobMSBULong(image,12L); /* data length=12 */
11207 PNGType(chunk,mng_DEFI);
11208 LogPNGChunk(logging,mng_DEFI,12L);
11209 chunk[4]=0; /* object 0 MSB */
11210 chunk[5]=0; /* object 0 LSB */
11211 chunk[6]=0; /* visible */
11212 chunk[7]=0; /* abstract */
11213 PNGLong(chunk+8,(png_uint_32) mng_info->page.x);
11214 PNGLong(chunk+12,(png_uint_32) mng_info->page.y);
11215 (void) WriteBlob(image,16,chunk);
11216 (void) WriteBlobMSBULong(image,crc32(0,chunk,16));
11221 mng_info->write_mng=write_mng;
11223 if ((int) image->dispose >= 3)
11224 mng_info->framing_mode=3;
11226 if (mng_info->need_fram && mng_info->adjoin &&
11227 ((image->delay != mng_info->delay) ||
11228 (mng_info->framing_mode != mng_info->old_framing_mode)))
11230 if (image->delay == mng_info->delay)
11233 Write a MNG FRAM chunk with the new framing mode.
11235 (void) WriteBlobMSBULong(image,1L); /* data length=1 */
11236 PNGType(chunk,mng_FRAM);
11237 LogPNGChunk(logging,mng_FRAM,1L);
11238 chunk[4]=(unsigned char) mng_info->framing_mode;
11239 (void) WriteBlob(image,5,chunk);
11240 (void) WriteBlobMSBULong(image,crc32(0,chunk,5));
11245 Write a MNG FRAM chunk with the delay.
11247 (void) WriteBlobMSBULong(image,10L); /* data length=10 */
11248 PNGType(chunk,mng_FRAM);
11249 LogPNGChunk(logging,mng_FRAM,10L);
11250 chunk[4]=(unsigned char) mng_info->framing_mode;
11251 chunk[5]=0; /* frame name separator (no name) */
11252 chunk[6]=2; /* flag for changing default delay */
11253 chunk[7]=0; /* flag for changing frame timeout */
11254 chunk[8]=0; /* flag for changing frame clipping */
11255 chunk[9]=0; /* flag for changing frame sync_id */
11256 PNGLong(chunk+10,(png_uint_32)
11257 ((mng_info->ticks_per_second*
11258 image->delay)/MagickMax(image->ticks_per_second,1)));
11259 (void) WriteBlob(image,14,chunk);
11260 (void) WriteBlobMSBULong(image,crc32(0,chunk,14));
11261 mng_info->delay=(png_uint_32) image->delay;
11263 mng_info->old_framing_mode=mng_info->framing_mode;
11266 #if defined(JNG_SUPPORTED)
11267 if (image_info->compression == JPEGCompression)
11272 if (logging != MagickFalse)
11273 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11274 " Writing JNG object.");
11275 /* To do: specify the desired alpha compression method. */
11276 write_info=CloneImageInfo(image_info);
11277 write_info->compression=UndefinedCompression;
11278 status=WriteOneJNGImage(mng_info,write_info,image);
11279 write_info=DestroyImageInfo(write_info);
11284 if (logging != MagickFalse)
11285 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11286 " Writing PNG object.");
11288 mng_info->need_blob = MagickFalse;
11290 /* We don't want any ancillary chunks written */
11291 mng_info->ping_exclude_bKGD=MagickTrue;
11292 mng_info->ping_exclude_cHRM=MagickTrue;
11293 mng_info->ping_exclude_EXIF=MagickTrue;
11294 mng_info->ping_exclude_gAMA=MagickTrue;
11295 mng_info->ping_exclude_cHRM=MagickTrue;
11296 mng_info->ping_exclude_iCCP=MagickTrue;
11297 /* mng_info->ping_exclude_iTXt=MagickTrue; */
11298 mng_info->ping_exclude_oFFs=MagickTrue;
11299 mng_info->ping_exclude_pHYs=MagickTrue;
11300 mng_info->ping_exclude_sRGB=MagickTrue;
11301 mng_info->ping_exclude_tEXt=MagickTrue;
11302 mng_info->ping_exclude_tRNS=MagickTrue;
11303 mng_info->ping_exclude_vpAg=MagickTrue;
11304 mng_info->ping_exclude_zCCP=MagickTrue;
11305 mng_info->ping_exclude_zTXt=MagickTrue;
11307 status=WriteOnePNGImage(mng_info,image_info,image);
11310 if (status == MagickFalse)
11312 MngInfoFreeStruct(mng_info,&have_mng_structure);
11313 (void) CloseBlob(image);
11314 return(MagickFalse);
11316 (void) CatchImageException(image);
11317 if (GetNextImageInList(image) == (Image *) NULL)
11319 image=SyncNextImageInList(image);
11320 status=SetImageProgress(image,SaveImagesTag,scene++,
11321 GetImageListLength(image));
11323 if (status == MagickFalse)
11326 } while (mng_info->adjoin);
11330 while (GetPreviousImageInList(image) != (Image *) NULL)
11331 image=GetPreviousImageInList(image);
11333 Write the MEND chunk.
11335 (void) WriteBlobMSBULong(image,0x00000000L);
11336 PNGType(chunk,mng_MEND);
11337 LogPNGChunk(logging,mng_MEND,0L);
11338 (void) WriteBlob(image,4,chunk);
11339 (void) WriteBlobMSBULong(image,crc32(0,chunk,4));
11342 Relinquish resources.
11344 (void) CloseBlob(image);
11345 MngInfoFreeStruct(mng_info,&have_mng_structure);
11347 if (logging != MagickFalse)
11348 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"exit WriteMNGImage()");
11350 return(MagickTrue);
11352 #else /* PNG_LIBPNG_VER > 10011 */
11354 static MagickBooleanType WritePNGImage(const ImageInfo *image_info,Image *image)
11357 printf("Your PNG library is too old: You have libpng-%s\n",
11358 PNG_LIBPNG_VER_STRING);
11360 ThrowBinaryException(CoderError,"PNG library is too old",
11361 image_info->filename);
11364 static MagickBooleanType WriteMNGImage(const ImageInfo *image_info,Image *image)
11366 return(WritePNGImage(image_info,image));
11368 #endif /* PNG_LIBPNG_VER > 10011 */