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 else if (ping_color_type ==
8028 PNG_COLOR_TYPE_GRAY && image_colors < 17 &&
8029 mng_info->IsPalette)
8032 /* Check if grayscale is reducible */
8034 depth_4_ok=MagickTrue,
8035 depth_2_ok=MagickTrue,
8036 depth_1_ok=MagickTrue;
8038 for (i=0; i < (ssize_t) image_colors; i++)
8043 intensity=ScaleQuantumToChar(image->colormap[i].red);
8045 if ((intensity & 0x0f) != ((intensity & 0xf0) >> 4))
8046 depth_4_ok=depth_2_ok=depth_1_ok=MagickFalse;
8048 else if ((intensity & 0x03) != ((intensity & 0x0c) >> 2))
8049 depth_2_ok=depth_1_ok=MagickFalse;
8051 else if ((intensity & 0x01) != ((intensity & 0x02) >> 1))
8052 depth_1_ok=MagickFalse;
8055 if (depth_1_ok && mng_info->write_png_depth <= 1)
8058 else if (depth_2_ok && mng_info->write_png_depth <= 2)
8061 else if (depth_4_ok && mng_info->write_png_depth <= 4)
8066 image_depth=ping_bit_depth;
8071 if (mng_info->IsPalette)
8073 number_colors=image_colors;
8075 if (image_depth <= 8)
8080 ping_color_type=(png_byte) PNG_COLOR_TYPE_PALETTE;
8082 if (mng_info->have_write_global_plte && matte == MagickFalse)
8084 png_set_PLTE(ping,ping_info,NULL,0);
8086 if (logging != MagickFalse)
8087 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8088 " Setting up empty PLTE chunk");
8093 for (i=0; i < (ssize_t) number_colors; i++)
8095 palette[i].red=ScaleQuantumToChar(image->colormap[i].red);
8096 palette[i].green=ScaleQuantumToChar(image->colormap[i].green);
8097 palette[i].blue=ScaleQuantumToChar(image->colormap[i].blue);
8100 if (logging != MagickFalse)
8101 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8102 " Setting up PLTE chunk with %d colors",
8105 ping_have_PLTE=MagickTrue;
8108 /* color_type is PNG_COLOR_TYPE_PALETTE */
8109 if (mng_info->write_png_depth == 0)
8117 while ((one << ping_bit_depth) < number_colors)
8118 ping_bit_depth <<= 1;
8123 if (matte != MagickFalse)
8126 * Set up trans_colors array.
8128 assert(number_colors <= 256);
8130 ping_num_trans=(unsigned short) (number_transparent +
8131 number_semitransparent);
8133 if (ping_num_trans == 0)
8134 ping_have_tRNS=MagickFalse;
8138 if (logging != MagickFalse)
8140 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8141 " Scaling ping_trans_color (1)");
8143 ping_have_tRNS=MagickTrue;
8145 for (i=0; i < ping_num_trans; i++)
8147 ping_trans_alpha[i]= (png_byte) (255-
8148 ScaleQuantumToChar(image->colormap[i].opacity));
8158 if (image_depth < 8)
8161 if ((save_image_depth == 16) && (image_depth == 8))
8163 if (logging != MagickFalse)
8165 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8166 " Scaling ping_trans_color from (%d,%d,%d)",
8167 (int) ping_trans_color.red,
8168 (int) ping_trans_color.green,
8169 (int) ping_trans_color.blue);
8172 ping_trans_color.red*=0x0101;
8173 ping_trans_color.green*=0x0101;
8174 ping_trans_color.blue*=0x0101;
8175 ping_trans_color.gray*=0x0101;
8177 if (logging != MagickFalse)
8179 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8181 (int) ping_trans_color.red,
8182 (int) ping_trans_color.green,
8183 (int) ping_trans_color.blue);
8188 if (ping_bit_depth < (ssize_t) mng_info->write_png_depth)
8189 ping_bit_depth = (ssize_t) mng_info->write_png_depth;
8192 Adjust background and transparency samples in sub-8-bit grayscale files.
8194 if (ping_bit_depth < 8 && ping_color_type ==
8195 PNG_COLOR_TYPE_GRAY)
8203 maxval=(png_uint_16) ((one << ping_bit_depth)-1);
8205 if (ping_exclude_bKGD == MagickFalse)
8208 ping_background.gray=(png_uint_16)
8209 (QuantumScale*(maxval*(PixelIntensity(&image->background_color))));
8211 if (logging != MagickFalse)
8212 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8213 " Setting up bKGD chunk (2)");
8215 ping_have_bKGD = MagickTrue;
8218 ping_trans_color.gray=(png_uint_16) (QuantumScale*(maxval*
8219 ping_trans_color.gray));
8222 if (ping_exclude_bKGD == MagickFalse)
8224 if ((int) ping_color_type == PNG_COLOR_TYPE_PALETTE)
8227 Identify which colormap entry is the background color.
8230 number_colors=image_colors;
8232 for (i=0; i < (ssize_t) MagickMax(1L*number_colors,1L); i++)
8233 if (IsPNGColorEqual(image->background_color,image->colormap[i]))
8236 ping_background.index=(png_byte) i;
8238 if (logging != MagickFalse)
8240 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8241 " Setting up bKGD chunk with index=%d",(int) i);
8244 if (i < (ssize_t) number_colors)
8246 ping_have_bKGD = MagickTrue;
8248 if (logging != MagickFalse)
8250 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8251 " background =(%d,%d,%d)",
8252 (int) ping_background.red,
8253 (int) ping_background.green,
8254 (int) ping_background.blue);
8258 else /* Can't happen */
8260 if (logging != MagickFalse)
8261 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8262 " No room in PLTE to add bKGD color");
8263 ping_have_bKGD = MagickFalse;
8268 if (logging != MagickFalse)
8269 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8270 " PNG color type: %d",ping_color_type);
8272 Initialize compression level and filtering.
8274 if (logging != MagickFalse)
8276 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8277 " Setting up deflate compression");
8279 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8280 " Compression buffer size: 32768");
8283 png_set_compression_buffer_size(ping,32768L);
8285 if (logging != MagickFalse)
8286 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8287 " Compression mem level: 9");
8289 png_set_compression_mem_level(ping, 9);
8291 quality=image->quality == UndefinedCompressionQuality ? 75UL :
8299 level=(int) MagickMin((ssize_t) quality/10,9);
8301 if (logging != MagickFalse)
8302 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8303 " Compression level: %d",level);
8305 png_set_compression_level(ping,level);
8310 if (logging != MagickFalse)
8311 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8312 " Compression strategy: Z_HUFFMAN_ONLY");
8314 png_set_compression_strategy(ping, Z_HUFFMAN_ONLY);
8317 if (logging != MagickFalse)
8318 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8319 " Setting up filtering");
8321 #if defined(PNG_MNG_FEATURES_SUPPORTED) && defined(PNG_INTRAPIXEL_DIFFERENCING)
8322 /* This became available in libpng-1.0.9. Output must be a MNG. */
8323 if (mng_info->write_mng && ((quality % 10) == 7))
8325 if (logging != MagickFalse)
8326 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8327 " Filter_type: PNG_INTRAPIXEL_DIFFERENCING");
8329 ping_filter_method=PNG_INTRAPIXEL_DIFFERENCING;
8333 if (logging != MagickFalse)
8334 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8342 if ((quality % 10) > 5)
8343 base_filter=PNG_ALL_FILTERS;
8346 if ((quality % 10) != 5)
8347 base_filter=(int) quality % 10;
8350 if (((int) ping_color_type == PNG_COLOR_TYPE_GRAY) ||
8351 ((int) ping_color_type == PNG_COLOR_TYPE_PALETTE) ||
8353 base_filter=PNG_NO_FILTERS;
8356 base_filter=PNG_ALL_FILTERS;
8358 if (logging != MagickFalse)
8360 if (base_filter == PNG_ALL_FILTERS)
8361 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8362 " Base filter method: ADAPTIVE");
8364 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8365 " Base filter method: NONE");
8368 png_set_filter(ping,PNG_FILTER_TYPE_BASE,base_filter);
8371 if (ping_exclude_iCCP == MagickFalse || ping_exclude_zCCP == MagickFalse)
8373 ResetImageProfileIterator(image);
8374 for (name=GetNextImageProfile(image); name != (const char *) NULL; )
8376 profile=GetImageProfile(image,name);
8378 if (profile != (StringInfo *) NULL)
8380 #ifdef PNG_WRITE_iCCP_SUPPORTED
8381 if ((LocaleCompare(name,"ICC") == 0) ||
8382 (LocaleCompare(name,"ICM") == 0))
8385 if (ping_exclude_iCCP == MagickFalse)
8387 png_set_iCCP(ping,ping_info,(const png_charp) name,0,
8388 #if (PNG_LIBPNG_VER < 10500)
8389 (png_charp) GetStringInfoDatum(profile),
8391 (png_const_bytep) GetStringInfoDatum(profile),
8393 (png_uint_32) GetStringInfoLength(profile));
8399 if (ping_exclude_zCCP == MagickFalse)
8401 Magick_png_write_raw_profile(image_info,ping,ping_info,
8402 (unsigned char *) name,(unsigned char *) name,
8403 GetStringInfoDatum(profile),
8404 (png_uint_32) GetStringInfoLength(profile));
8408 if (logging != MagickFalse)
8409 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8410 " Setting up text chunk with %s profile",name);
8412 name=GetNextImageProfile(image);
8416 #if defined(PNG_WRITE_sRGB_SUPPORTED)
8417 if ((mng_info->have_write_global_srgb == 0) &&
8418 ((image->rendering_intent != UndefinedIntent) ||
8419 (image->colorspace == sRGBColorspace)))
8421 if (ping_exclude_sRGB == MagickFalse)
8424 Note image rendering intent.
8426 if (logging != MagickFalse)
8427 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8428 " Setting up sRGB chunk");
8430 (void) png_set_sRGB(ping,ping_info,(
8431 Magick_RenderingIntent_to_PNG_RenderingIntent(
8432 image->rendering_intent)));
8434 if (ping_exclude_gAMA == MagickFalse)
8435 png_set_gAMA(ping,ping_info,0.45455);
8439 if ((!mng_info->write_mng) || (!png_get_valid(ping,ping_info,PNG_INFO_sRGB)))
8442 if (ping_exclude_gAMA == MagickFalse &&
8443 (ping_exclude_sRGB == MagickFalse ||
8444 (image->gamma < .45 || image->gamma > .46)))
8446 if ((mng_info->have_write_global_gama == 0) && (image->gamma != 0.0))
8450 To do: check for cHRM+gAMA == sRGB, and write sRGB instead.
8452 if (logging != MagickFalse)
8453 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8454 " Setting up gAMA chunk");
8456 png_set_gAMA(ping,ping_info,image->gamma);
8460 if (ping_exclude_cHRM == MagickFalse)
8462 if ((mng_info->have_write_global_chrm == 0) &&
8463 (image->chromaticity.red_primary.x != 0.0))
8466 Note image chromaticity.
8467 To do: check for cHRM+gAMA == sRGB, and write sRGB instead.
8475 wp=image->chromaticity.white_point;
8476 rp=image->chromaticity.red_primary;
8477 gp=image->chromaticity.green_primary;
8478 bp=image->chromaticity.blue_primary;
8480 if (logging != MagickFalse)
8481 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8482 " Setting up cHRM chunk");
8484 png_set_cHRM(ping,ping_info,wp.x,wp.y,rp.x,rp.y,gp.x,gp.y,
8490 ping_interlace_method=image_info->interlace != NoInterlace;
8492 if (mng_info->write_mng)
8493 png_set_sig_bytes(ping,8);
8495 /* Bail out if cannot meet defined PNG:bit-depth or PNG:color-type */
8497 if (mng_info->write_png_colortype != 0)
8499 if (mng_info->write_png_colortype-1 == PNG_COLOR_TYPE_GRAY)
8500 if (ImageIsGray(image) == MagickFalse)
8502 ping_color_type = PNG_COLOR_TYPE_RGB;
8504 if (ping_bit_depth < 8)
8508 if (mng_info->write_png_colortype-1 == PNG_COLOR_TYPE_GRAY_ALPHA)
8509 if (ImageIsGray(image) == MagickFalse)
8510 ping_color_type = PNG_COLOR_TYPE_RGB_ALPHA;
8513 if (ping_need_colortype_warning != MagickFalse ||
8514 ((mng_info->write_png_depth &&
8515 (int) mng_info->write_png_depth != ping_bit_depth) ||
8516 (mng_info->write_png_colortype &&
8517 ((int) mng_info->write_png_colortype-1 != ping_color_type &&
8518 mng_info->write_png_colortype != 7 &&
8519 !(mng_info->write_png_colortype == 5 && ping_color_type == 0)))))
8521 if (logging != MagickFalse)
8523 if (ping_need_colortype_warning != MagickFalse)
8525 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8526 " Image has transparency but tRNS chunk was excluded");
8529 if (mng_info->write_png_depth)
8531 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8532 " Defined PNG:bit-depth=%u, Computed depth=%u",
8533 mng_info->write_png_depth,
8537 if (mng_info->write_png_colortype)
8539 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8540 " Defined PNG:color-type=%u, Computed color type=%u",
8541 mng_info->write_png_colortype-1,
8547 "Cannot write image with defined PNG:bit-depth or PNG:color-type.");
8550 if (image_matte != MagickFalse && image->matte == MagickFalse)
8552 /* Add an opaque matte channel */
8553 image->matte = MagickTrue;
8554 (void) SetImageOpacity(image,0);
8556 if (logging != MagickFalse)
8557 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8558 " Added an opaque matte channel");
8561 if (number_transparent != 0 || number_semitransparent != 0)
8563 if (ping_color_type < 4)
8565 ping_have_tRNS=MagickTrue;
8566 if (logging != MagickFalse)
8567 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8568 " Setting ping_have_tRNS=MagickTrue.");
8572 if (logging != MagickFalse)
8573 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8574 " Writing PNG header chunks");
8576 png_set_IHDR(ping,ping_info,ping_width,ping_height,
8577 ping_bit_depth,ping_color_type,
8578 ping_interlace_method,ping_compression_method,
8579 ping_filter_method);
8581 if (ping_color_type == 3 && ping_have_PLTE != MagickFalse)
8583 png_set_PLTE(ping,ping_info,palette,number_colors);
8585 if (logging != MagickFalse)
8587 for (i=0; i< (ssize_t) number_colors; i++)
8589 if (i < ping_num_trans)
8590 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8591 " PLTE[%d] = (%d,%d,%d), tRNS[%d] = (%d)",
8593 (int) palette[i].red,
8594 (int) palette[i].green,
8595 (int) palette[i].blue,
8597 (int) ping_trans_alpha[i]);
8599 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8600 " PLTE[%d] = (%d,%d,%d)",
8602 (int) palette[i].red,
8603 (int) palette[i].green,
8604 (int) palette[i].blue);
8609 if (ping_exclude_bKGD == MagickFalse)
8611 if (ping_have_bKGD != MagickFalse)
8612 png_set_bKGD(ping,ping_info,&ping_background);
8615 if (ping_exclude_pHYs == MagickFalse)
8617 if (ping_have_pHYs != MagickFalse)
8619 png_set_pHYs(ping,ping_info,
8620 ping_pHYs_x_resolution,
8621 ping_pHYs_y_resolution,
8622 ping_pHYs_unit_type);
8626 #if defined(PNG_oFFs_SUPPORTED)
8627 if (ping_exclude_oFFs == MagickFalse)
8629 if (image->page.x || image->page.y)
8631 png_set_oFFs(ping,ping_info,(png_int_32) image->page.x,
8632 (png_int_32) image->page.y, 0);
8634 if (logging != MagickFalse)
8635 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8636 " Setting up oFFs chunk with x=%d, y=%d, units=0",
8637 (int) image->page.x, (int) image->page.y);
8642 png_write_info_before_PLTE(ping, ping_info);
8644 if (ping_have_tRNS != MagickFalse && ping_color_type < 4)
8646 if (logging != MagickFalse)
8648 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8649 " Calling png_set_tRNS with num_trans=%d",ping_num_trans);
8652 if (ping_color_type == 3)
8653 (void) png_set_tRNS(ping, ping_info,
8660 (void) png_set_tRNS(ping, ping_info,
8665 if (logging != MagickFalse)
8667 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8668 " tRNS color =(%d,%d,%d)",
8669 (int) ping_trans_color.red,
8670 (int) ping_trans_color.green,
8671 (int) ping_trans_color.blue);
8676 /* write any png-chunk-b profiles */
8677 (void) Magick_png_write_chunk_from_profile(image,"PNG-chunk-b",logging);
8678 png_write_info(ping,ping_info);
8680 /* write any PNG-chunk-m profiles */
8681 (void) Magick_png_write_chunk_from_profile(image,"PNG-chunk-m",logging);
8683 if (ping_exclude_vpAg == MagickFalse)
8685 if ((image->page.width != 0 && image->page.width != image->columns) ||
8686 (image->page.height != 0 && image->page.height != image->rows))
8691 (void) WriteBlobMSBULong(image,9L); /* data length=8 */
8692 PNGType(chunk,mng_vpAg);
8693 LogPNGChunk(logging,mng_vpAg,9L);
8694 PNGLong(chunk+4,(png_uint_32) image->page.width);
8695 PNGLong(chunk+8,(png_uint_32) image->page.height);
8696 chunk[12]=0; /* unit = pixels */
8697 (void) WriteBlob(image,13,chunk);
8698 (void) WriteBlobMSBULong(image,crc32(0,chunk,13));
8702 #if (PNG_LIBPNG_VER == 10206)
8703 /* avoid libpng-1.2.6 bug by setting PNG_HAVE_IDAT flag */
8704 #define PNG_HAVE_IDAT 0x04
8705 ping->mode |= PNG_HAVE_IDAT;
8706 #undef PNG_HAVE_IDAT
8709 png_set_packing(ping);
8713 rowbytes=image->columns;
8714 if (image_depth > 8)
8716 switch (ping_color_type)
8718 case PNG_COLOR_TYPE_RGB:
8722 case PNG_COLOR_TYPE_GRAY_ALPHA:
8726 case PNG_COLOR_TYPE_RGBA:
8734 if (logging != MagickFalse)
8736 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8737 " Writing PNG image data");
8739 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8740 " Allocating %.20g bytes of memory for pixels",(double) rowbytes);
8742 ping_pixels=(unsigned char *) AcquireQuantumMemory(rowbytes,
8743 sizeof(*ping_pixels));
8745 if (ping_pixels == (unsigned char *) NULL)
8746 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
8749 Initialize image scanlines.
8751 if (setjmp(png_jmpbuf(ping)))
8757 if (image_info->verbose)
8758 (void) printf("PNG write has failed.\n");
8760 png_destroy_write_struct(&ping,&ping_info);
8761 if (quantum_info != (QuantumInfo *) NULL)
8762 quantum_info=DestroyQuantumInfo(quantum_info);
8763 if (ping_pixels != (unsigned char *) NULL)
8764 ping_pixels=(unsigned char *) RelinquishMagickMemory(ping_pixels);
8765 #if defined(PNG_SETJMP_NOT_THREAD_SAFE)
8766 UnlockSemaphoreInfo(ping_semaphore);
8768 if (mng_info->need_blob != MagickFalse)
8769 (void) CloseBlob(image);
8770 image_info=DestroyImageInfo(image_info);
8771 image=DestroyImage(image);
8772 return(MagickFalse);
8774 quantum_info=AcquireQuantumInfo(image_info,image);
8775 if (quantum_info == (QuantumInfo *) NULL)
8776 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
8777 quantum_info->format=UndefinedQuantumFormat;
8778 quantum_info->depth=image_depth;
8779 num_passes=png_set_interlace_handling(ping);
8781 if ((!mng_info->write_png8 && !mng_info->write_png24 &&
8782 !mng_info->write_png32) &&
8783 (mng_info->IsPalette ||
8784 (image_info->type == BilevelType)) &&
8785 image_matte == MagickFalse && ImageIsMonochrome(image))
8787 /* Palette, Bilevel, or Opaque Monochrome */
8788 register const PixelPacket
8791 quantum_info->depth=8;
8792 for (pass=0; pass < num_passes; pass++)
8795 Convert PseudoClass image to a PNG monochrome image.
8797 for (y=0; y < (ssize_t) image->rows; y++)
8800 if (logging != MagickFalse)
8801 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8802 " Writing row of pixels (0)");
8804 p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception);
8806 if (p == (const PixelPacket *) NULL)
8809 if (mng_info->IsPalette)
8811 (void) ExportQuantumPixels(image,(const CacheView *) NULL,
8812 quantum_info,GrayQuantum,ping_pixels,&image->exception);
8813 if (mng_info->write_png_colortype-1 == PNG_COLOR_TYPE_PALETTE &&
8814 mng_info->write_png_depth &&
8815 mng_info->write_png_depth != old_bit_depth)
8817 /* Undo pixel scaling */
8818 for (i=0; i < (ssize_t) image->columns; i++)
8819 *(ping_pixels+i)=(unsigned char) (*(ping_pixels+i)
8820 >> (8-old_bit_depth));
8826 (void) ExportQuantumPixels(image,(const CacheView *) NULL,
8827 quantum_info,RedQuantum,ping_pixels,&image->exception);
8830 if (mng_info->write_png_colortype-1 != PNG_COLOR_TYPE_PALETTE)
8831 for (i=0; i < (ssize_t) image->columns; i++)
8832 *(ping_pixels+i)=(unsigned char) ((*(ping_pixels+i) > 127) ?
8835 if (logging != MagickFalse && y == 0)
8836 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8837 " Writing row of pixels (1)");
8839 png_write_row(ping,ping_pixels);
8841 if (image->previous == (Image *) NULL)
8843 status=SetImageProgress(image,LoadImageTag,pass,num_passes);
8844 if (status == MagickFalse)
8850 else /* Not Palette, Bilevel, or Opaque Monochrome */
8852 if ((!mng_info->write_png8 && !mng_info->write_png24 &&
8853 !mng_info->write_png32) &&
8854 (image_matte != MagickFalse ||
8855 (ping_bit_depth >= MAGICKCORE_QUANTUM_DEPTH)) &&
8856 (mng_info->IsPalette) && ImageIsGray(image))
8858 register const PixelPacket
8861 for (pass=0; pass < num_passes; pass++)
8864 for (y=0; y < (ssize_t) image->rows; y++)
8866 p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception);
8868 if (p == (const PixelPacket *) NULL)
8871 if (ping_color_type == PNG_COLOR_TYPE_GRAY)
8873 if (mng_info->IsPalette)
8874 (void) ExportQuantumPixels(image,(const CacheView *) NULL,
8875 quantum_info,GrayQuantum,ping_pixels,&image->exception);
8878 (void) ExportQuantumPixels(image,(const CacheView *) NULL,
8879 quantum_info,RedQuantum,ping_pixels,&image->exception);
8881 if (logging != MagickFalse && y == 0)
8882 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8883 " Writing GRAY PNG pixels (2)");
8886 else /* PNG_COLOR_TYPE_GRAY_ALPHA */
8888 if (logging != MagickFalse && y == 0)
8889 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8890 " Writing GRAY_ALPHA PNG pixels (2)");
8892 (void) ExportQuantumPixels(image,(const CacheView *) NULL,
8893 quantum_info,GrayAlphaQuantum,ping_pixels,&image->exception);
8896 if (logging != MagickFalse && y == 0)
8897 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8898 " Writing row of pixels (2)");
8900 png_write_row(ping,ping_pixels);
8903 if (image->previous == (Image *) NULL)
8905 status=SetImageProgress(image,LoadImageTag,pass,num_passes);
8906 if (status == MagickFalse)
8914 register const PixelPacket
8917 for (pass=0; pass < num_passes; pass++)
8919 if ((image_depth > 8) || (mng_info->write_png24 ||
8920 mng_info->write_png32 ||
8921 (!mng_info->write_png8 && !mng_info->IsPalette)))
8923 for (y=0; y < (ssize_t) image->rows; y++)
8925 p=GetVirtualPixels(image,0,y,image->columns,1,
8928 if (p == (const PixelPacket *) NULL)
8931 if (ping_color_type == PNG_COLOR_TYPE_GRAY)
8933 if (image->storage_class == DirectClass)
8934 (void) ExportQuantumPixels(image,(const CacheView *) NULL,
8935 quantum_info,RedQuantum,ping_pixels,&image->exception);
8938 (void) ExportQuantumPixels(image,(const CacheView *) NULL,
8939 quantum_info,GrayQuantum,ping_pixels,&image->exception);
8942 else if (ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
8944 (void) ExportQuantumPixels(image,(const CacheView *) NULL,
8945 quantum_info,GrayAlphaQuantum,ping_pixels,
8948 if (logging != MagickFalse && y == 0)
8949 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8950 " Writing GRAY_ALPHA PNG pixels (3)");
8953 else if (image_matte != MagickFalse)
8954 (void) ExportQuantumPixels(image,(const CacheView *) NULL,
8955 quantum_info,RGBAQuantum,ping_pixels,&image->exception);
8958 (void) ExportQuantumPixels(image,(const CacheView *) NULL,
8959 quantum_info,RGBQuantum,ping_pixels,&image->exception);
8961 if (logging != MagickFalse && y == 0)
8962 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8963 " Writing row of pixels (3)");
8965 png_write_row(ping,ping_pixels);
8970 /* not ((image_depth > 8) || (mng_info->write_png24 ||
8971 mng_info->write_png32 ||
8972 (!mng_info->write_png8 && !mng_info->IsPalette))) */
8974 if ((ping_color_type != PNG_COLOR_TYPE_GRAY) &&
8975 (ping_color_type != PNG_COLOR_TYPE_GRAY_ALPHA))
8977 if (logging != MagickFalse)
8978 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8979 " pass %d, Image Is not GRAY or GRAY_ALPHA",pass);
8981 quantum_info->depth=8;
8985 for (y=0; y < (ssize_t) image->rows; y++)
8987 if (logging != MagickFalse && y == 0)
8988 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8989 " pass %d, Image Is RGB, 16-bit GRAY, or GRAY_ALPHA",pass);
8991 p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception);
8993 if (p == (const PixelPacket *) NULL)
8996 if (ping_color_type == PNG_COLOR_TYPE_GRAY)
8997 (void) ExportQuantumPixels(image,(const CacheView *) NULL,
8998 quantum_info,GrayQuantum,ping_pixels,&image->exception);
9000 else if (ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
9002 if (logging != MagickFalse && y == 0)
9003 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9004 " Writing GRAY_ALPHA PNG pixels (4)");
9006 (void) ExportQuantumPixels(image,(const CacheView *) NULL,
9007 quantum_info,GrayAlphaQuantum,ping_pixels,
9012 (void) ExportQuantumPixels(image,(const CacheView *) NULL,
9013 quantum_info,IndexQuantum,ping_pixels,&image->exception);
9015 if (logging != MagickFalse && y <= 2)
9017 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9018 " Writing row of pixels (4)");
9020 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9021 " ping_pixels[0]=%d,ping_pixels[1]=%d",
9022 (int)ping_pixels[0],(int)ping_pixels[1]);
9024 png_write_row(ping,ping_pixels);
9028 if (image->previous == (Image *) NULL)
9030 status=SetImageProgress(image,LoadImageTag,pass,num_passes);
9031 if (status == MagickFalse)
9038 if (quantum_info != (QuantumInfo *) NULL)
9039 quantum_info=DestroyQuantumInfo(quantum_info);
9041 if (logging != MagickFalse)
9043 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9044 " Wrote PNG image data");
9046 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9047 " Width: %.20g",(double) ping_width);
9049 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9050 " Height: %.20g",(double) ping_height);
9052 if (mng_info->write_png_depth)
9054 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9055 " Defined PNG:bit-depth: %d",mng_info->write_png_depth);
9058 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9059 " PNG bit-depth written: %d",ping_bit_depth);
9061 if (mng_info->write_png_colortype)
9063 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9064 " Defined PNG:color-type: %d",mng_info->write_png_colortype-1);
9067 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9068 " PNG color-type written: %d",ping_color_type);
9070 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9071 " PNG Interlace method: %d",ping_interlace_method);
9074 Generate text chunks.
9076 if (ping_exclude_tEXt == MagickFalse && ping_exclude_zTXt == MagickFalse)
9078 ResetImagePropertyIterator(image);
9079 property=GetNextImageProperty(image);
9080 while (property != (const char *) NULL)
9085 value=GetImageProperty(image,property);
9086 if (value != (const char *) NULL)
9088 text=(png_textp) png_malloc(ping,(png_uint_32) sizeof(png_text));
9089 text[0].key=(char *) property;
9090 text[0].text=(char *) value;
9091 text[0].text_length=strlen(value);
9093 if (ping_exclude_tEXt != MagickFalse)
9094 text[0].compression=PNG_TEXT_COMPRESSION_zTXt;
9096 else if (ping_exclude_zTXt != MagickFalse)
9097 text[0].compression=PNG_TEXT_COMPRESSION_NONE;
9101 text[0].compression=image_info->compression == NoCompression ||
9102 (image_info->compression == UndefinedCompression &&
9103 text[0].text_length < 128) ? PNG_TEXT_COMPRESSION_NONE :
9104 PNG_TEXT_COMPRESSION_zTXt ;
9107 if (logging != MagickFalse)
9109 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9110 " Setting up text chunk");
9112 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9113 " keyword: %s",text[0].key);
9116 png_set_text(ping,ping_info,text,1);
9117 png_free(ping,text);
9119 property=GetNextImageProperty(image);
9123 /* write any PNG-chunk-e profiles */
9124 (void) Magick_png_write_chunk_from_profile(image,"PNG-chunk-e",logging);
9126 if (logging != MagickFalse)
9127 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9128 " Writing PNG end info");
9130 png_write_end(ping,ping_info);
9132 if (mng_info->need_fram && (int) image->dispose == BackgroundDispose)
9134 if (mng_info->page.x || mng_info->page.y ||
9135 (ping_width != mng_info->page.width) ||
9136 (ping_height != mng_info->page.height))
9142 Write FRAM 4 with clipping boundaries followed by FRAM 1.
9144 (void) WriteBlobMSBULong(image,27L); /* data length=27 */
9145 PNGType(chunk,mng_FRAM);
9146 LogPNGChunk(logging,mng_FRAM,27L);
9148 chunk[5]=0; /* frame name separator (no name) */
9149 chunk[6]=1; /* flag for changing delay, for next frame only */
9150 chunk[7]=0; /* flag for changing frame timeout */
9151 chunk[8]=1; /* flag for changing frame clipping for next frame */
9152 chunk[9]=0; /* flag for changing frame sync_id */
9153 PNGLong(chunk+10,(png_uint_32) (0L)); /* temporary 0 delay */
9154 chunk[14]=0; /* clipping boundaries delta type */
9155 PNGLong(chunk+15,(png_uint_32) (mng_info->page.x)); /* left cb */
9157 (png_uint_32) (mng_info->page.x + ping_width));
9158 PNGLong(chunk+23,(png_uint_32) (mng_info->page.y)); /* top cb */
9160 (png_uint_32) (mng_info->page.y + ping_height));
9161 (void) WriteBlob(image,31,chunk);
9162 (void) WriteBlobMSBULong(image,crc32(0,chunk,31));
9163 mng_info->old_framing_mode=4;
9164 mng_info->framing_mode=1;
9168 mng_info->framing_mode=3;
9170 if (mng_info->write_mng && !mng_info->need_fram &&
9171 ((int) image->dispose == 3))
9172 (void) ThrowMagickException(&image->exception,GetMagickModule(),
9173 CoderError,"Cannot convert GIF with disposal method 3 to MNG-LC",
9174 "`%s'",image->filename);
9180 png_destroy_write_struct(&ping,&ping_info);
9182 ping_pixels=(unsigned char *) RelinquishMagickMemory(ping_pixels);
9184 #if defined(PNG_SETJMP_NOT_THREAD_SAFE)
9185 UnlockSemaphoreInfo(ping_semaphore);
9188 if (mng_info->need_blob != MagickFalse)
9189 (void) CloseBlob(image);
9191 image_info=DestroyImageInfo(image_info);
9192 image=DestroyImage(image);
9194 /* Store bit depth actually written */
9195 s[0]=(char) ping_bit_depth;
9198 (void) SetImageProperty(IMimage,"png:bit-depth-written",s);
9200 if (logging != MagickFalse)
9201 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9202 " exit WriteOnePNGImage()");
9205 /* End write one PNG image */
9209 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
9213 % W r i t e P N G I m a g e %
9217 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
9219 % WritePNGImage() writes a Portable Network Graphics (PNG) or
9220 % Multiple-image Network Graphics (MNG) image file.
9222 % MNG support written by Glenn Randers-Pehrson, glennrp@image...
9224 % The format of the WritePNGImage method is:
9226 % MagickBooleanType WritePNGImage(const ImageInfo *image_info,Image *image)
9228 % A description of each parameter follows:
9230 % o image_info: the image info.
9232 % o image: The image.
9234 % Returns MagickTrue on success, MagickFalse on failure.
9236 % Communicating with the PNG encoder:
9238 % While the datastream written is always in PNG format and normally would
9239 % be given the "png" file extension, this method also writes the following
9240 % pseudo-formats which are subsets of PNG:
9242 % o PNG8: An 8-bit indexed PNG datastream is written. If transparency
9243 % is present, the tRNS chunk must only have values 0 and 255
9244 % (i.e., transparency is binary: fully opaque or fully
9245 % transparent). The pixels contain 8-bit indices even if
9246 % they could be represented with 1, 2, or 4 bits. Note: grayscale
9247 % images will be written as indexed PNG files even though the
9248 % PNG grayscale type might be slightly more efficient.
9250 % o PNG24: An 8-bit per sample RGB PNG datastream is written. The tRNS
9251 % chunk can be present to convey binary transparency by naming
9252 % one of the colors as transparent.
9254 % o PNG32: An 8-bit per sample RGBA PNG is written. Partial
9255 % transparency is permitted, i.e., the alpha sample for
9256 % each pixel can have any value from 0 to 255. The alpha
9257 % channel is present even if the image is fully opaque.
9259 % o -define: For more precise control of the PNG output, you can use the
9260 % Image options "png:bit-depth" and "png:color-type". These
9261 % can be set from the commandline with "-define" and also
9262 % from the application programming interfaces. The options
9263 % are case-independent and are converted to lowercase before
9264 % being passed to this encoder.
9266 % png:color-type can be 0, 2, 3, 4, or 6.
9268 % When png:color-type is 0 (Grayscale), png:bit-depth can
9269 % be 1, 2, 4, 8, or 16.
9271 % When png:color-type is 2 (RGB), png:bit-depth can
9274 % When png:color-type is 3 (Indexed), png:bit-depth can
9275 % be 1, 2, 4, or 8. This refers to the number of bits
9276 % used to store the index. The color samples always have
9277 % bit-depth 8 in indexed PNG files.
9279 % When png:color-type is 4 (Gray-Matte) or 6 (RGB-Matte),
9280 % png:bit-depth can be 8 or 16.
9282 % If the image cannot be written without loss in the requested PNG8, PNG24,
9283 % or PNG32 format or with the requested bit-depth and color-type without loss,
9284 % a PNG file will not be written, and the encoder will return MagickFalse.
9285 % Since image encoders should not be responsible for the "heavy lifting",
9286 % the user should make sure that ImageMagick has already reduced the
9287 % image depth and number of colors and limit transparency to binary
9288 % transparency prior to attempting to write the image in a format that
9289 % is subject to depth, color, or transparency limitations.
9291 % TODO: Enforce the previous paragraph.
9293 % Note that another definition, "png:bit-depth-written" exists, but it
9294 % is not intended for external use. It is only used internally by the
9295 % PNG encoder to inform the JNG encoder of the depth of the alpha channel.
9297 % It is possible to request that the PNG encoder write previously-formatted
9298 % ancillary chunks in the output PNG file, using the "-profile" commandline
9299 % option as shown below or by setting the profile via a programming
9302 % -profile PNG-chunk-x:<file>
9304 % where x is a location flag and <file> is a file containing the chunk
9305 % name in the first 4 bytes, then a colon (":"), followed by the chunk data.
9306 % This encoder will compute the chunk length and CRC, so those must not
9307 % be included in the file.
9309 % "x" can be "b" (before PLTE), "m" (middle, i.e., between PLTE and IDAT),
9310 % or "e" (end, i.e., after IDAT). If you want to write multiple chunks
9311 % of the same type, then add a short unique string after the "x" to prevent
9312 % subsequent profiles from overwriting the preceding ones, e.g.,
9314 % -profile PNG-chunk-b01:file01 -profile PNG-chunk-b02:file02
9316 % As of version 6.6.6 the following optimizations are always done:
9318 % o 32-bit depth is reduced to 16.
9319 % o 16-bit depth is reduced to 8 if all pixels contain samples whose
9320 % high byte and low byte are identical.
9321 % o Palette is sorted to remove unused entries and to put a
9322 % transparent color first, if BUILD_PNG_PALETTE is defined.
9323 % o Opaque matte channel is removed when writing an indexed PNG.
9324 % o Grayscale images are reduced to 1, 2, or 4 bit depth if
9325 % this can be done without loss and a larger bit depth N was not
9326 % requested via the "-define PNG:bit-depth=N" option.
9327 % o If matte channel is present but only one transparent color is
9328 % present, RGB+tRNS is written instead of RGBA
9329 % o Opaque matte channel is removed (or added, if color-type 4 or 6
9330 % was requested when converting an opaque image).
9332 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
9334 static MagickBooleanType WritePNGImage(const ImageInfo *image_info,
9356 assert(image_info != (const ImageInfo *) NULL);
9357 assert(image_info->signature == MagickSignature);
9358 assert(image != (Image *) NULL);
9359 assert(image->signature == MagickSignature);
9360 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
9361 logging=LogMagickEvent(CoderEvent,GetMagickModule(),"enter WritePNGImage()");
9363 Allocate a MngInfo structure.
9365 have_mng_structure=MagickFalse;
9366 mng_info=(MngInfo *) AcquireMagickMemory(sizeof(MngInfo));
9368 if (mng_info == (MngInfo *) NULL)
9369 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
9372 Initialize members of the MngInfo structure.
9374 (void) ResetMagickMemory(mng_info,0,sizeof(MngInfo));
9375 mng_info->image=image;
9376 mng_info->equal_backgrounds=MagickTrue;
9377 have_mng_structure=MagickTrue;
9379 /* See if user has requested a specific PNG subformat */
9381 mng_info->write_png8=LocaleCompare(image_info->magick,"PNG8") == 0;
9382 mng_info->write_png24=LocaleCompare(image_info->magick,"PNG24") == 0;
9383 mng_info->write_png32=LocaleCompare(image_info->magick,"PNG32") == 0;
9385 if (mng_info->write_png8)
9387 mng_info->write_png_colortype = /* 3 */ 4;
9388 mng_info->write_png_depth = 8;
9392 if (mng_info->write_png24)
9394 mng_info->write_png_colortype = /* 2 */ 3;
9395 mng_info->write_png_depth = 8;
9398 if (image->matte == MagickTrue)
9399 (void) SetImageType(image,TrueColorMatteType);
9402 (void) SetImageType(image,TrueColorType);
9404 (void) SyncImage(image);
9407 if (mng_info->write_png32)
9409 mng_info->write_png_colortype = /* 6 */ 7;
9410 mng_info->write_png_depth = 8;
9413 if (image->matte == MagickTrue)
9414 (void) SetImageType(image,TrueColorMatteType);
9417 (void) SetImageType(image,TrueColorType);
9419 (void) SyncImage(image);
9422 value=GetImageOption(image_info,"png:bit-depth");
9424 if (value != (char *) NULL)
9426 if (LocaleCompare(value,"1") == 0)
9427 mng_info->write_png_depth = 1;
9429 else if (LocaleCompare(value,"2") == 0)
9430 mng_info->write_png_depth = 2;
9432 else if (LocaleCompare(value,"4") == 0)
9433 mng_info->write_png_depth = 4;
9435 else if (LocaleCompare(value,"8") == 0)
9436 mng_info->write_png_depth = 8;
9438 else if (LocaleCompare(value,"16") == 0)
9439 mng_info->write_png_depth = 16;
9442 (void) ThrowMagickException(&image->exception,
9443 GetMagickModule(),CoderWarning,
9444 "ignoring invalid defined png:bit-depth",
9447 if (logging != MagickFalse)
9448 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9449 " png:bit-depth=%d was defined.\n",mng_info->write_png_depth);
9452 value=GetImageOption(image_info,"png:color-type");
9454 if (value != (char *) NULL)
9456 /* We must store colortype+1 because 0 is a valid colortype */
9457 if (LocaleCompare(value,"0") == 0)
9458 mng_info->write_png_colortype = 1;
9460 else if (LocaleCompare(value,"2") == 0)
9461 mng_info->write_png_colortype = 3;
9463 else if (LocaleCompare(value,"3") == 0)
9464 mng_info->write_png_colortype = 4;
9466 else if (LocaleCompare(value,"4") == 0)
9467 mng_info->write_png_colortype = 5;
9469 else if (LocaleCompare(value,"6") == 0)
9470 mng_info->write_png_colortype = 7;
9473 (void) ThrowMagickException(&image->exception,
9474 GetMagickModule(),CoderWarning,
9475 "ignoring invalid defined png:color-type",
9478 if (logging != MagickFalse)
9479 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9480 " png:color-type=%d was defined.\n",mng_info->write_png_colortype-1);
9483 /* Check for chunks to be excluded:
9485 * The default is to not exclude any known chunks except for any
9486 * listed in the "unused_chunks" array, above.
9488 * Chunks can be listed for exclusion via a "PNG:exclude-chunk"
9489 * define (in the image properties or in the image artifacts)
9490 * or via a mng_info member. For convenience, in addition
9491 * to or instead of a comma-separated list of chunks, the
9492 * "exclude-chunk" string can be simply "all" or "none".
9494 * The exclude-chunk define takes priority over the mng_info.
9496 * A "PNG:include-chunk" define takes priority over both the
9497 * mng_info and the "PNG:exclude-chunk" define. Like the
9498 * "exclude-chunk" string, it can define "all" or "none" as
9499 * well as a comma-separated list. Chunks that are unknown to
9500 * ImageMagick are always excluded, regardless of their "copy-safe"
9501 * status according to the PNG specification, and even if they
9502 * appear in the "include-chunk" list.
9504 * Finally, all chunks listed in the "unused_chunks" array are
9505 * automatically excluded, regardless of the other instructions
9508 * if you exclude sRGB but not gAMA (recommended), then sRGB chunk
9509 * will not be written and the gAMA chunk will only be written if it
9510 * is not between .45 and .46, or approximately (1.0/2.2).
9512 * If you exclude tRNS and the image has transparency, the colortype
9513 * is forced to be 4 or 6 (GRAY_ALPHA or RGB_ALPHA).
9515 * The -strip option causes StripImage() to set the png:include-chunk
9516 * artifact to "none,gama".
9519 mng_info->ping_exclude_bKGD=MagickFalse;
9520 mng_info->ping_exclude_cHRM=MagickFalse;
9521 mng_info->ping_exclude_EXIF=MagickFalse; /* hex-encoded EXIF in zTXt */
9522 mng_info->ping_exclude_gAMA=MagickFalse;
9523 mng_info->ping_exclude_cHRM=MagickFalse;
9524 mng_info->ping_exclude_iCCP=MagickFalse;
9525 /* mng_info->ping_exclude_iTXt=MagickFalse; */
9526 mng_info->ping_exclude_oFFs=MagickFalse;
9527 mng_info->ping_exclude_pHYs=MagickFalse;
9528 mng_info->ping_exclude_sRGB=MagickFalse;
9529 mng_info->ping_exclude_tEXt=MagickFalse;
9530 mng_info->ping_exclude_tRNS=MagickFalse;
9531 mng_info->ping_exclude_vpAg=MagickFalse;
9532 mng_info->ping_exclude_zCCP=MagickFalse; /* hex-encoded iCCP in zTXt */
9533 mng_info->ping_exclude_zTXt=MagickFalse;
9535 excluding=MagickFalse;
9537 for (source=0; source<1; source++)
9541 value=GetImageArtifact(image,"png:exclude-chunk");
9544 value=GetImageArtifact(image,"png:exclude-chunks");
9548 value=GetImageOption(image_info,"png:exclude-chunk");
9551 value=GetImageOption(image_info,"png:exclude-chunks");
9560 excluding=MagickTrue;
9562 if (logging != MagickFalse)
9565 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9566 " png:exclude-chunk=%s found in image artifacts.\n", value);
9568 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9569 " png:exclude-chunk=%s found in image properties.\n", value);
9574 for (i=0; i<(int) last; i+=5)
9577 if (LocaleNCompare(value+i,"all",3) == 0)
9579 mng_info->ping_exclude_bKGD=MagickTrue;
9580 mng_info->ping_exclude_cHRM=MagickTrue;
9581 mng_info->ping_exclude_EXIF=MagickTrue;
9582 mng_info->ping_exclude_gAMA=MagickTrue;
9583 mng_info->ping_exclude_iCCP=MagickTrue;
9584 /* mng_info->ping_exclude_iTXt=MagickTrue; */
9585 mng_info->ping_exclude_oFFs=MagickTrue;
9586 mng_info->ping_exclude_pHYs=MagickTrue;
9587 mng_info->ping_exclude_sRGB=MagickTrue;
9588 mng_info->ping_exclude_tEXt=MagickTrue;
9589 mng_info->ping_exclude_tRNS=MagickTrue;
9590 mng_info->ping_exclude_vpAg=MagickTrue;
9591 mng_info->ping_exclude_zCCP=MagickTrue;
9592 mng_info->ping_exclude_zTXt=MagickTrue;
9596 if (LocaleNCompare(value+i,"none",4) == 0)
9598 mng_info->ping_exclude_bKGD=MagickFalse;
9599 mng_info->ping_exclude_cHRM=MagickFalse;
9600 mng_info->ping_exclude_EXIF=MagickFalse;
9601 mng_info->ping_exclude_gAMA=MagickFalse;
9602 mng_info->ping_exclude_iCCP=MagickFalse;
9603 /* mng_info->ping_exclude_iTXt=MagickFalse; */
9604 mng_info->ping_exclude_oFFs=MagickFalse;
9605 mng_info->ping_exclude_pHYs=MagickFalse;
9606 mng_info->ping_exclude_sRGB=MagickFalse;
9607 mng_info->ping_exclude_tEXt=MagickFalse;
9608 mng_info->ping_exclude_tRNS=MagickFalse;
9609 mng_info->ping_exclude_vpAg=MagickFalse;
9610 mng_info->ping_exclude_zCCP=MagickFalse;
9611 mng_info->ping_exclude_zTXt=MagickFalse;
9614 if (LocaleNCompare(value+i,"bkgd",4) == 0)
9615 mng_info->ping_exclude_bKGD=MagickTrue;
9617 if (LocaleNCompare(value+i,"chrm",4) == 0)
9618 mng_info->ping_exclude_cHRM=MagickTrue;
9620 if (LocaleNCompare(value+i,"exif",4) == 0)
9621 mng_info->ping_exclude_EXIF=MagickTrue;
9623 if (LocaleNCompare(value+i,"gama",4) == 0)
9624 mng_info->ping_exclude_gAMA=MagickTrue;
9626 if (LocaleNCompare(value+i,"iccp",4) == 0)
9627 mng_info->ping_exclude_iCCP=MagickTrue;
9630 if (LocaleNCompare(value+i,"itxt",4) == 0)
9631 mng_info->ping_exclude_iTXt=MagickTrue;
9634 if (LocaleNCompare(value+i,"gama",4) == 0)
9635 mng_info->ping_exclude_gAMA=MagickTrue;
9637 if (LocaleNCompare(value+i,"offs",4) == 0)
9638 mng_info->ping_exclude_oFFs=MagickTrue;
9640 if (LocaleNCompare(value+i,"phys",4) == 0)
9641 mng_info->ping_exclude_pHYs=MagickTrue;
9643 if (LocaleNCompare(value+i,"srgb",4) == 0)
9644 mng_info->ping_exclude_sRGB=MagickTrue;
9646 if (LocaleNCompare(value+i,"text",4) == 0)
9647 mng_info->ping_exclude_tEXt=MagickTrue;
9649 if (LocaleNCompare(value+i,"trns",4) == 0)
9650 mng_info->ping_exclude_tRNS=MagickTrue;
9652 if (LocaleNCompare(value+i,"vpag",4) == 0)
9653 mng_info->ping_exclude_vpAg=MagickTrue;
9655 if (LocaleNCompare(value+i,"zccp",4) == 0)
9656 mng_info->ping_exclude_zCCP=MagickTrue;
9658 if (LocaleNCompare(value+i,"ztxt",4) == 0)
9659 mng_info->ping_exclude_zTXt=MagickTrue;
9665 for (source=0; source<1; source++)
9669 value=GetImageArtifact(image,"png:include-chunk");
9672 value=GetImageArtifact(image,"png:include-chunks");
9676 value=GetImageOption(image_info,"png:include-chunk");
9679 value=GetImageOption(image_info,"png:include-chunks");
9687 excluding=MagickTrue;
9689 if (logging != MagickFalse)
9692 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9693 " png:include-chunk=%s found in image artifacts.\n", value);
9695 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9696 " png:include-chunk=%s found in image properties.\n", value);
9701 for (i=0; i<(int) last; i+=5)
9703 if (LocaleNCompare(value+i,"all",3) == 0)
9705 mng_info->ping_exclude_bKGD=MagickFalse;
9706 mng_info->ping_exclude_cHRM=MagickFalse;
9707 mng_info->ping_exclude_EXIF=MagickFalse;
9708 mng_info->ping_exclude_gAMA=MagickFalse;
9709 mng_info->ping_exclude_iCCP=MagickFalse;
9710 /* mng_info->ping_exclude_iTXt=MagickFalse; */
9711 mng_info->ping_exclude_oFFs=MagickFalse;
9712 mng_info->ping_exclude_pHYs=MagickFalse;
9713 mng_info->ping_exclude_sRGB=MagickFalse;
9714 mng_info->ping_exclude_tEXt=MagickFalse;
9715 mng_info->ping_exclude_tRNS=MagickFalse;
9716 mng_info->ping_exclude_vpAg=MagickFalse;
9717 mng_info->ping_exclude_zCCP=MagickFalse;
9718 mng_info->ping_exclude_zTXt=MagickFalse;
9722 if (LocaleNCompare(value+i,"none",4) == 0)
9724 mng_info->ping_exclude_bKGD=MagickTrue;
9725 mng_info->ping_exclude_cHRM=MagickTrue;
9726 mng_info->ping_exclude_EXIF=MagickTrue;
9727 mng_info->ping_exclude_gAMA=MagickTrue;
9728 mng_info->ping_exclude_iCCP=MagickTrue;
9729 /* mng_info->ping_exclude_iTXt=MagickTrue; */
9730 mng_info->ping_exclude_oFFs=MagickTrue;
9731 mng_info->ping_exclude_pHYs=MagickTrue;
9732 mng_info->ping_exclude_sRGB=MagickTrue;
9733 mng_info->ping_exclude_tEXt=MagickTrue;
9734 mng_info->ping_exclude_tRNS=MagickTrue;
9735 mng_info->ping_exclude_vpAg=MagickTrue;
9736 mng_info->ping_exclude_zCCP=MagickTrue;
9737 mng_info->ping_exclude_zTXt=MagickTrue;
9740 if (LocaleNCompare(value+i,"bkgd",4) == 0)
9741 mng_info->ping_exclude_bKGD=MagickFalse;
9743 if (LocaleNCompare(value+i,"chrm",4) == 0)
9744 mng_info->ping_exclude_cHRM=MagickFalse;
9746 if (LocaleNCompare(value+i,"exif",4) == 0)
9747 mng_info->ping_exclude_EXIF=MagickFalse;
9749 if (LocaleNCompare(value+i,"gama",4) == 0)
9750 mng_info->ping_exclude_gAMA=MagickFalse;
9752 if (LocaleNCompare(value+i,"iccp",4) == 0)
9753 mng_info->ping_exclude_iCCP=MagickFalse;
9756 if (LocaleNCompare(value+i,"itxt",4) == 0)
9757 mng_info->ping_exclude_iTXt=MagickFalse;
9760 if (LocaleNCompare(value+i,"gama",4) == 0)
9761 mng_info->ping_exclude_gAMA=MagickFalse;
9763 if (LocaleNCompare(value+i,"offs",4) == 0)
9764 mng_info->ping_exclude_oFFs=MagickFalse;
9766 if (LocaleNCompare(value+i,"phys",4) == 0)
9767 mng_info->ping_exclude_pHYs=MagickFalse;
9769 if (LocaleNCompare(value+i,"srgb",4) == 0)
9770 mng_info->ping_exclude_sRGB=MagickFalse;
9772 if (LocaleNCompare(value+i,"text",4) == 0)
9773 mng_info->ping_exclude_tEXt=MagickFalse;
9775 if (LocaleNCompare(value+i,"trns",4) == 0)
9776 mng_info->ping_exclude_tRNS=MagickFalse;
9778 if (LocaleNCompare(value+i,"vpag",4) == 0)
9779 mng_info->ping_exclude_vpAg=MagickFalse;
9781 if (LocaleNCompare(value+i,"zccp",4) == 0)
9782 mng_info->ping_exclude_zCCP=MagickFalse;
9784 if (LocaleNCompare(value+i,"ztxt",4) == 0)
9785 mng_info->ping_exclude_zTXt=MagickFalse;
9791 if (excluding != MagickFalse && logging != MagickFalse)
9793 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9794 " Chunks to be excluded from the output PNG:");
9795 if (mng_info->ping_exclude_bKGD != MagickFalse)
9796 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9798 if (mng_info->ping_exclude_cHRM != MagickFalse)
9799 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9801 if (mng_info->ping_exclude_EXIF != MagickFalse)
9802 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9804 if (mng_info->ping_exclude_gAMA != MagickFalse)
9805 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9807 if (mng_info->ping_exclude_iCCP != MagickFalse)
9808 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9811 if (mng_info->ping_exclude_iTXt != MagickFalse)
9812 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9815 if (mng_info->ping_exclude_oFFs != MagickFalse)
9816 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9818 if (mng_info->ping_exclude_pHYs != MagickFalse)
9819 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9821 if (mng_info->ping_exclude_sRGB != MagickFalse)
9822 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9824 if (mng_info->ping_exclude_tEXt != MagickFalse)
9825 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9827 if (mng_info->ping_exclude_tRNS != MagickFalse)
9828 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9830 if (mng_info->ping_exclude_vpAg != MagickFalse)
9831 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9833 if (mng_info->ping_exclude_zCCP != MagickFalse)
9834 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9836 if (mng_info->ping_exclude_zTXt != MagickFalse)
9837 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9841 mng_info->need_blob = MagickTrue;
9843 status=WriteOnePNGImage(mng_info,image_info,image);
9845 MngInfoFreeStruct(mng_info,&have_mng_structure);
9847 if (logging != MagickFalse)
9848 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"exit WritePNGImage()");
9853 #if defined(JNG_SUPPORTED)
9855 /* Write one JNG image */
9856 static MagickBooleanType WriteOneJNGImage(MngInfo *mng_info,
9857 const ImageInfo *image_info,Image *image)
9878 jng_alpha_compression_method,
9879 jng_alpha_sample_depth,
9886 logging=LogMagickEvent(CoderEvent,GetMagickModule(),
9887 " enter WriteOneJNGImage()");
9889 blob=(unsigned char *) NULL;
9890 jpeg_image=(Image *) NULL;
9891 jpeg_image_info=(ImageInfo *) NULL;
9894 transparent=image_info->type==GrayscaleMatteType ||
9895 image_info->type==TrueColorMatteType;
9897 jng_alpha_sample_depth=0;
9898 jng_quality=image_info->quality == 0UL ? 75UL : image_info->quality;
9899 jng_alpha_compression_method=0;
9901 if (image->matte != MagickFalse)
9903 /* if any pixels are transparent */
9904 transparent=MagickTrue;
9905 if (image_info->compression==JPEGCompression)
9906 jng_alpha_compression_method=8;
9913 /* Create JPEG blob, image, and image_info */
9914 if (logging != MagickFalse)
9915 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9916 " Creating jpeg_image_info for opacity.");
9918 jpeg_image_info=(ImageInfo *) CloneImageInfo(image_info);
9920 if (jpeg_image_info == (ImageInfo *) NULL)
9921 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
9923 if (logging != MagickFalse)
9924 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9925 " Creating jpeg_image.");
9927 jpeg_image=CloneImage(image,0,0,MagickTrue,&image->exception);
9929 if (jpeg_image == (Image *) NULL)
9930 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
9932 (void) CopyMagickString(jpeg_image->magick,"JPEG",MaxTextExtent);
9933 status=SeparateImageChannel(jpeg_image,OpacityChannel);
9934 status=NegateImage(jpeg_image,MagickFalse);
9935 jpeg_image->matte=MagickFalse;
9937 if (jng_quality >= 1000)
9938 jpeg_image_info->quality=jng_quality/1000;
9941 jpeg_image_info->quality=jng_quality;
9943 jpeg_image_info->type=GrayscaleType;
9944 (void) SetImageType(jpeg_image,GrayscaleType);
9945 (void) AcquireUniqueFilename(jpeg_image->filename);
9946 (void) FormatMagickString(jpeg_image_info->filename,MaxTextExtent,
9947 "%s",jpeg_image->filename);
9950 /* To do: check bit depth of PNG alpha channel */
9952 /* Check if image is grayscale. */
9953 if (image_info->type != TrueColorMatteType && image_info->type !=
9954 TrueColorType && ImageIsGray(image))
9959 if (jng_alpha_compression_method==0)
9964 /* Encode opacity as a grayscale PNG blob */
9965 status=OpenBlob(jpeg_image_info,jpeg_image,WriteBinaryBlobMode,
9967 if (logging != MagickFalse)
9968 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9969 " Creating PNG blob.");
9972 (void) CopyMagickString(jpeg_image_info->magick,"PNG",MaxTextExtent);
9973 (void) CopyMagickString(jpeg_image->magick,"PNG",MaxTextExtent);
9974 jpeg_image_info->interlace=NoInterlace;
9976 blob=ImageToBlob(jpeg_image_info,jpeg_image,&length,
9979 /* Retrieve sample depth used */
9980 value=GetImageProperty(jpeg_image,"png:bit-depth-written");
9981 if (value != (char *) NULL)
9982 jng_alpha_sample_depth= (unsigned int) value[0];
9986 /* Encode opacity as a grayscale JPEG blob */
9988 status=OpenBlob(jpeg_image_info,jpeg_image,WriteBinaryBlobMode,
9991 (void) CopyMagickString(jpeg_image_info->magick,"JPEG",MaxTextExtent);
9992 (void) CopyMagickString(jpeg_image->magick,"JPEG",MaxTextExtent);
9993 jpeg_image_info->interlace=NoInterlace;
9994 if (logging != MagickFalse)
9995 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9997 blob=ImageToBlob(jpeg_image_info,jpeg_image,&length,
9999 jng_alpha_sample_depth=8;
10001 if (logging != MagickFalse)
10002 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10003 " Successfully read jpeg_image into a blob, length=%.20g.",
10007 /* Destroy JPEG image and image_info */
10008 jpeg_image=DestroyImage(jpeg_image);
10009 (void) RelinquishUniqueFileResource(jpeg_image_info->filename);
10010 jpeg_image_info=DestroyImageInfo(jpeg_image_info);
10013 /* Write JHDR chunk */
10014 (void) WriteBlobMSBULong(image,16L); /* chunk data length=16 */
10015 PNGType(chunk,mng_JHDR);
10016 LogPNGChunk(logging,mng_JHDR,16L);
10017 PNGLong(chunk+4,(png_uint_32) image->columns);
10018 PNGLong(chunk+8,(png_uint_32) image->rows);
10019 chunk[12]=jng_color_type;
10020 chunk[13]=8; /* sample depth */
10021 chunk[14]=8; /*jng_image_compression_method */
10022 chunk[15]=(unsigned char) (image_info->interlace == NoInterlace ? 0 : 8);
10023 chunk[16]=jng_alpha_sample_depth;
10024 chunk[17]=jng_alpha_compression_method;
10025 chunk[18]=0; /*jng_alpha_filter_method */
10026 chunk[19]=0; /*jng_alpha_interlace_method */
10027 (void) WriteBlob(image,20,chunk);
10028 (void) WriteBlobMSBULong(image,crc32(0,chunk,20));
10029 if (logging != MagickFalse)
10031 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10032 " JNG width:%15lu",(unsigned long) image->columns);
10034 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10035 " JNG height:%14lu",(unsigned long) image->rows);
10037 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10038 " JNG color type:%10d",jng_color_type);
10040 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10041 " JNG sample depth:%8d",8);
10043 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10044 " JNG compression:%9d",8);
10046 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10047 " JNG interlace:%11d",0);
10049 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10050 " JNG alpha depth:%9d",jng_alpha_sample_depth);
10052 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10053 " JNG alpha compression:%3d",jng_alpha_compression_method);
10055 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10056 " JNG alpha filter:%8d",0);
10058 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10059 " JNG alpha interlace:%5d",0);
10062 /* Write any JNG-chunk-b profiles */
10063 (void) Magick_png_write_chunk_from_profile(image,"JNG-chunk-b",logging);
10066 Write leading ancillary chunks
10072 Write JNG bKGD chunk
10083 if (jng_color_type == 8 || jng_color_type == 12)
10087 (void) WriteBlobMSBULong(image,(size_t) (num_bytes-4L));
10088 PNGType(chunk,mng_bKGD);
10089 LogPNGChunk(logging,mng_bKGD,(size_t) (num_bytes-4L));
10090 red=ScaleQuantumToChar(image->background_color.red);
10091 green=ScaleQuantumToChar(image->background_color.green);
10092 blue=ScaleQuantumToChar(image->background_color.blue);
10099 (void) WriteBlob(image,(size_t) num_bytes,chunk);
10100 (void) WriteBlobMSBULong(image,crc32(0,chunk,(uInt) num_bytes));
10103 if ((image->colorspace == sRGBColorspace || image->rendering_intent))
10106 Write JNG sRGB chunk
10108 (void) WriteBlobMSBULong(image,1L);
10109 PNGType(chunk,mng_sRGB);
10110 LogPNGChunk(logging,mng_sRGB,1L);
10112 if (image->rendering_intent != UndefinedIntent)
10113 chunk[4]=(unsigned char)
10114 Magick_RenderingIntent_to_PNG_RenderingIntent(
10115 (image->rendering_intent));
10118 chunk[4]=(unsigned char)
10119 Magick_RenderingIntent_to_PNG_RenderingIntent(
10120 (PerceptualIntent));
10122 (void) WriteBlob(image,5,chunk);
10123 (void) WriteBlobMSBULong(image,crc32(0,chunk,5));
10127 if (image->gamma != 0.0)
10130 Write JNG gAMA chunk
10132 (void) WriteBlobMSBULong(image,4L);
10133 PNGType(chunk,mng_gAMA);
10134 LogPNGChunk(logging,mng_gAMA,4L);
10135 PNGLong(chunk+4,(png_uint_32) (100000*image->gamma+0.5));
10136 (void) WriteBlob(image,8,chunk);
10137 (void) WriteBlobMSBULong(image,crc32(0,chunk,8));
10140 if ((mng_info->equal_chrms == MagickFalse) &&
10141 (image->chromaticity.red_primary.x != 0.0))
10147 Write JNG cHRM chunk
10149 (void) WriteBlobMSBULong(image,32L);
10150 PNGType(chunk,mng_cHRM);
10151 LogPNGChunk(logging,mng_cHRM,32L);
10152 primary=image->chromaticity.white_point;
10153 PNGLong(chunk+4,(png_uint_32) (100000*primary.x+0.5));
10154 PNGLong(chunk+8,(png_uint_32) (100000*primary.y+0.5));
10155 primary=image->chromaticity.red_primary;
10156 PNGLong(chunk+12,(png_uint_32) (100000*primary.x+0.5));
10157 PNGLong(chunk+16,(png_uint_32) (100000*primary.y+0.5));
10158 primary=image->chromaticity.green_primary;
10159 PNGLong(chunk+20,(png_uint_32) (100000*primary.x+0.5));
10160 PNGLong(chunk+24,(png_uint_32) (100000*primary.y+0.5));
10161 primary=image->chromaticity.blue_primary;
10162 PNGLong(chunk+28,(png_uint_32) (100000*primary.x+0.5));
10163 PNGLong(chunk+32,(png_uint_32) (100000*primary.y+0.5));
10164 (void) WriteBlob(image,36,chunk);
10165 (void) WriteBlobMSBULong(image,crc32(0,chunk,36));
10169 if (image->x_resolution && image->y_resolution && !mng_info->equal_physs)
10172 Write JNG pHYs chunk
10174 (void) WriteBlobMSBULong(image,9L);
10175 PNGType(chunk,mng_pHYs);
10176 LogPNGChunk(logging,mng_pHYs,9L);
10177 if (image->units == PixelsPerInchResolution)
10179 PNGLong(chunk+4,(png_uint_32)
10180 (image->x_resolution*100.0/2.54+0.5));
10182 PNGLong(chunk+8,(png_uint_32)
10183 (image->y_resolution*100.0/2.54+0.5));
10190 if (image->units == PixelsPerCentimeterResolution)
10192 PNGLong(chunk+4,(png_uint_32)
10193 (image->x_resolution*100.0+0.5));
10195 PNGLong(chunk+8,(png_uint_32)
10196 (image->y_resolution*100.0+0.5));
10203 PNGLong(chunk+4,(png_uint_32) (image->x_resolution+0.5));
10204 PNGLong(chunk+8,(png_uint_32) (image->y_resolution+0.5));
10208 (void) WriteBlob(image,13,chunk);
10209 (void) WriteBlobMSBULong(image,crc32(0,chunk,13));
10212 if (mng_info->write_mng == 0 && (image->page.x || image->page.y))
10215 Write JNG oFFs chunk
10217 (void) WriteBlobMSBULong(image,9L);
10218 PNGType(chunk,mng_oFFs);
10219 LogPNGChunk(logging,mng_oFFs,9L);
10220 PNGsLong(chunk+4,(ssize_t) (image->page.x));
10221 PNGsLong(chunk+8,(ssize_t) (image->page.y));
10223 (void) WriteBlob(image,13,chunk);
10224 (void) WriteBlobMSBULong(image,crc32(0,chunk,13));
10226 if (mng_info->write_mng == 0 && (image->page.width || image->page.height))
10228 (void) WriteBlobMSBULong(image,9L); /* data length=8 */
10229 PNGType(chunk,mng_vpAg);
10230 LogPNGChunk(logging,mng_vpAg,9L);
10231 PNGLong(chunk+4,(png_uint_32) image->page.width);
10232 PNGLong(chunk+8,(png_uint_32) image->page.height);
10233 chunk[12]=0; /* unit = pixels */
10234 (void) WriteBlob(image,13,chunk);
10235 (void) WriteBlobMSBULong(image,crc32(0,chunk,13));
10241 if (jng_alpha_compression_method==0)
10249 /* Write IDAT chunk header */
10250 if (logging != MagickFalse)
10251 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10252 " Write IDAT chunks from blob, length=%.20g.",(double)
10255 /* Copy IDAT chunks */
10258 for (i=8; i<(ssize_t) length; i+=len+12)
10260 len=(*p<<24)|((*(p+1))<<16)|((*(p+2))<<8)|(*(p+3));
10263 if (*(p)==73 && *(p+1)==68 && *(p+2)==65 && *(p+3)==84) /* IDAT */
10265 /* Found an IDAT chunk. */
10266 (void) WriteBlobMSBULong(image,(size_t) len);
10267 LogPNGChunk(logging,mng_IDAT,(size_t) len);
10268 (void) WriteBlob(image,(size_t) len+4,p);
10269 (void) WriteBlobMSBULong(image,
10270 crc32(0,p,(uInt) len+4));
10275 if (logging != MagickFalse)
10276 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10277 " Skipping %c%c%c%c chunk, length=%.20g.",
10278 *(p),*(p+1),*(p+2),*(p+3),(double) len);
10285 /* Write JDAA chunk header */
10286 if (logging != MagickFalse)
10287 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10288 " Write JDAA chunk, length=%.20g.",(double) length);
10289 (void) WriteBlobMSBULong(image,(size_t) length);
10290 PNGType(chunk,mng_JDAA);
10291 LogPNGChunk(logging,mng_JDAA,length);
10292 /* Write JDAT chunk(s) data */
10293 (void) WriteBlob(image,4,chunk);
10294 (void) WriteBlob(image,length,blob);
10295 (void) WriteBlobMSBULong(image,crc32(crc32(0,chunk,4),blob,
10298 blob=(unsigned char *) RelinquishMagickMemory(blob);
10301 /* Encode image as a JPEG blob */
10302 if (logging != MagickFalse)
10303 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10304 " Creating jpeg_image_info.");
10305 jpeg_image_info=(ImageInfo *) CloneImageInfo(image_info);
10306 if (jpeg_image_info == (ImageInfo *) NULL)
10307 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
10309 if (logging != MagickFalse)
10310 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10311 " Creating jpeg_image.");
10313 jpeg_image=CloneImage(image,0,0,MagickTrue,&image->exception);
10314 if (jpeg_image == (Image *) NULL)
10315 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
10316 (void) CopyMagickString(jpeg_image->magick,"JPEG",MaxTextExtent);
10318 (void) AcquireUniqueFilename(jpeg_image->filename);
10319 (void) FormatMagickString(jpeg_image_info->filename,MaxTextExtent,"%s",
10320 jpeg_image->filename);
10322 status=OpenBlob(jpeg_image_info,jpeg_image,WriteBinaryBlobMode,
10323 &image->exception);
10325 if (logging != MagickFalse)
10326 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10327 " Created jpeg_image, %.20g x %.20g.",(double) jpeg_image->columns,
10328 (double) jpeg_image->rows);
10330 if (jng_color_type == 8 || jng_color_type == 12)
10331 jpeg_image_info->type=GrayscaleType;
10333 jpeg_image_info->quality=jng_quality % 1000;
10334 (void) CopyMagickString(jpeg_image_info->magick,"JPEG",MaxTextExtent);
10335 (void) CopyMagickString(jpeg_image->magick,"JPEG",MaxTextExtent);
10337 if (logging != MagickFalse)
10338 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10339 " Creating blob.");
10341 blob=ImageToBlob(jpeg_image_info,jpeg_image,&length,&image->exception);
10343 if (logging != MagickFalse)
10345 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10346 " Successfully read jpeg_image into a blob, length=%.20g.",
10349 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10350 " Write JDAT chunk, length=%.20g.",(double) length);
10353 /* Write JDAT chunk(s) */
10354 (void) WriteBlobMSBULong(image,(size_t) length);
10355 PNGType(chunk,mng_JDAT);
10356 LogPNGChunk(logging,mng_JDAT,length);
10357 (void) WriteBlob(image,4,chunk);
10358 (void) WriteBlob(image,length,blob);
10359 (void) WriteBlobMSBULong(image,crc32(crc32(0,chunk,4),blob,(uInt) length));
10361 jpeg_image=DestroyImage(jpeg_image);
10362 (void) RelinquishUniqueFileResource(jpeg_image_info->filename);
10363 jpeg_image_info=DestroyImageInfo(jpeg_image_info);
10364 blob=(unsigned char *) RelinquishMagickMemory(blob);
10366 /* Write any JNG-chunk-e profiles */
10367 (void) Magick_png_write_chunk_from_profile(image,"JNG-chunk-e",logging);
10369 /* Write IEND chunk */
10370 (void) WriteBlobMSBULong(image,0L);
10371 PNGType(chunk,mng_IEND);
10372 LogPNGChunk(logging,mng_IEND,0);
10373 (void) WriteBlob(image,4,chunk);
10374 (void) WriteBlobMSBULong(image,crc32(0,chunk,4));
10376 if (logging != MagickFalse)
10377 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10378 " exit WriteOneJNGImage()");
10385 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
10389 % W r i t e J N G I m a g e %
10393 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
10395 % WriteJNGImage() writes a JPEG Network Graphics (JNG) image file.
10397 % JNG support written by Glenn Randers-Pehrson, glennrp@image...
10399 % The format of the WriteJNGImage method is:
10401 % MagickBooleanType WriteJNGImage(const ImageInfo *image_info,Image *image)
10403 % A description of each parameter follows:
10405 % o image_info: the image info.
10407 % o image: The image.
10409 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
10411 static MagickBooleanType WriteJNGImage(const ImageInfo *image_info,Image *image)
10414 have_mng_structure,
10424 assert(image_info != (const ImageInfo *) NULL);
10425 assert(image_info->signature == MagickSignature);
10426 assert(image != (Image *) NULL);
10427 assert(image->signature == MagickSignature);
10428 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
10429 logging=LogMagickEvent(CoderEvent,GetMagickModule(),"enter WriteJNGImage()");
10430 status=OpenBlob(image_info,image,WriteBinaryBlobMode,&image->exception);
10431 if (status == MagickFalse)
10435 Allocate a MngInfo structure.
10437 have_mng_structure=MagickFalse;
10438 mng_info=(MngInfo *) AcquireMagickMemory(sizeof(MngInfo));
10439 if (mng_info == (MngInfo *) NULL)
10440 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
10442 Initialize members of the MngInfo structure.
10444 (void) ResetMagickMemory(mng_info,0,sizeof(MngInfo));
10445 mng_info->image=image;
10446 have_mng_structure=MagickTrue;
10448 (void) WriteBlob(image,8,(const unsigned char *) "\213JNG\r\n\032\n");
10450 status=WriteOneJNGImage(mng_info,image_info,image);
10451 (void) CloseBlob(image);
10453 (void) CatchImageException(image);
10454 MngInfoFreeStruct(mng_info,&have_mng_structure);
10455 if (logging != MagickFalse)
10456 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"exit WriteJNGImage()");
10463 static MagickBooleanType WriteMNGImage(const ImageInfo *image_info,Image *image)
10472 have_mng_structure,
10475 volatile MagickBooleanType
10487 #if defined(PNG_WRITE_EMPTY_PLTE_SUPPORTED) || \
10488 defined(PNG_MNG_FEATURES_SUPPORTED)
10491 all_images_are_gray,
10501 volatile unsigned int
10512 #if (PNG_LIBPNG_VER < 10200)
10513 if (image_info->verbose)
10514 printf("Your PNG library (libpng-%s) is rather old.\n",
10515 PNG_LIBPNG_VER_STRING);
10521 assert(image_info != (const ImageInfo *) NULL);
10522 assert(image_info->signature == MagickSignature);
10523 assert(image != (Image *) NULL);
10524 assert(image->signature == MagickSignature);
10525 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
10526 logging=LogMagickEvent(CoderEvent,GetMagickModule(),"enter WriteMNGImage()");
10527 status=OpenBlob(image_info,image,WriteBinaryBlobMode,&image->exception);
10528 if (status == MagickFalse)
10532 Allocate a MngInfo structure.
10534 have_mng_structure=MagickFalse;
10535 mng_info=(MngInfo *) AcquireMagickMemory(sizeof(MngInfo));
10536 if (mng_info == (MngInfo *) NULL)
10537 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
10539 Initialize members of the MngInfo structure.
10541 (void) ResetMagickMemory(mng_info,0,sizeof(MngInfo));
10542 mng_info->image=image;
10543 have_mng_structure=MagickTrue;
10544 write_mng=LocaleCompare(image_info->magick,"MNG") == 0;
10547 * See if user has requested a specific PNG subformat to be used
10548 * for all of the PNGs in the MNG being written, e.g.,
10550 * convert *.png png8:animation.mng
10552 * To do: check -define png:bit_depth and png:color_type as well,
10553 * or perhaps use mng:bit_depth and mng:color_type instead for
10557 mng_info->write_png8=LocaleCompare(image_info->magick,"PNG8") == 0;
10558 mng_info->write_png24=LocaleCompare(image_info->magick,"PNG24") == 0;
10559 mng_info->write_png32=LocaleCompare(image_info->magick,"PNG32") == 0;
10561 write_jng=MagickFalse;
10562 if (image_info->compression == JPEGCompression)
10563 write_jng=MagickTrue;
10565 mng_info->adjoin=image_info->adjoin &&
10566 (GetNextImageInList(image) != (Image *) NULL) && write_mng;
10568 if (logging != MagickFalse)
10570 /* Log some info about the input */
10574 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10575 " Checking input image(s)");
10577 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10578 " Image_info depth: %.20g",(double) image_info->depth);
10580 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10581 " Type: %d",image_info->type);
10584 for (p=image; p != (Image *) NULL; p=GetNextImageInList(p))
10586 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10587 " Scene: %.20g",(double) scene++);
10589 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10590 " Image depth: %.20g",(double) p->depth);
10593 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10597 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10600 if (p->storage_class == PseudoClass)
10601 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10602 " Storage class: PseudoClass");
10605 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10606 " Storage class: DirectClass");
10609 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10610 " Number of colors: %.20g",(double) p->colors);
10613 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10614 " Number of colors: unspecified");
10616 if (mng_info->adjoin == MagickFalse)
10621 use_global_plte=MagickFalse;
10622 all_images_are_gray=MagickFalse;
10623 #ifdef PNG_WRITE_EMPTY_PLTE_SUPPORTED
10624 need_local_plte=MagickTrue;
10626 need_defi=MagickFalse;
10627 need_matte=MagickFalse;
10628 mng_info->framing_mode=1;
10629 mng_info->old_framing_mode=1;
10632 if (image_info->page != (char *) NULL)
10635 Determine image bounding box.
10637 SetGeometry(image,&mng_info->page);
10638 (void) ParseMetaGeometry(image_info->page,&mng_info->page.x,
10639 &mng_info->page.y,&mng_info->page.width,&mng_info->page.height);
10651 mng_info->page=image->page;
10652 need_geom=MagickTrue;
10653 if (mng_info->page.width || mng_info->page.height)
10654 need_geom=MagickFalse;
10656 Check all the scenes.
10658 initial_delay=image->delay;
10659 need_iterations=MagickFalse;
10660 mng_info->equal_chrms=image->chromaticity.red_primary.x != 0.0;
10661 mng_info->equal_physs=MagickTrue,
10662 mng_info->equal_gammas=MagickTrue;
10663 mng_info->equal_srgbs=MagickTrue;
10664 mng_info->equal_backgrounds=MagickTrue;
10666 #if defined(PNG_WRITE_EMPTY_PLTE_SUPPORTED) || \
10667 defined(PNG_MNG_FEATURES_SUPPORTED)
10668 all_images_are_gray=MagickTrue;
10669 mng_info->equal_palettes=MagickFalse;
10670 need_local_plte=MagickFalse;
10672 for (next_image=image; next_image != (Image *) NULL; )
10676 if ((next_image->columns+next_image->page.x) > mng_info->page.width)
10677 mng_info->page.width=next_image->columns+next_image->page.x;
10679 if ((next_image->rows+next_image->page.y) > mng_info->page.height)
10680 mng_info->page.height=next_image->rows+next_image->page.y;
10683 if (next_image->page.x || next_image->page.y)
10684 need_defi=MagickTrue;
10686 if (next_image->matte)
10687 need_matte=MagickTrue;
10689 if ((int) next_image->dispose >= BackgroundDispose)
10690 if (next_image->matte || next_image->page.x || next_image->page.y ||
10691 ((next_image->columns < mng_info->page.width) &&
10692 (next_image->rows < mng_info->page.height)))
10693 mng_info->need_fram=MagickTrue;
10695 if (next_image->iterations)
10696 need_iterations=MagickTrue;
10698 final_delay=next_image->delay;
10700 if (final_delay != initial_delay || final_delay > 1UL*
10701 next_image->ticks_per_second)
10702 mng_info->need_fram=1;
10704 #if defined(PNG_WRITE_EMPTY_PLTE_SUPPORTED) || \
10705 defined(PNG_MNG_FEATURES_SUPPORTED)
10707 check for global palette possibility.
10709 if (image->matte != MagickFalse)
10710 need_local_plte=MagickTrue;
10712 if (need_local_plte == 0)
10714 if (ImageIsGray(image) == MagickFalse)
10715 all_images_are_gray=MagickFalse;
10716 mng_info->equal_palettes=PalettesAreEqual(image,next_image);
10717 if (use_global_plte == 0)
10718 use_global_plte=mng_info->equal_palettes;
10719 need_local_plte=!mng_info->equal_palettes;
10722 if (GetNextImageInList(next_image) != (Image *) NULL)
10724 if (next_image->background_color.red !=
10725 next_image->next->background_color.red ||
10726 next_image->background_color.green !=
10727 next_image->next->background_color.green ||
10728 next_image->background_color.blue !=
10729 next_image->next->background_color.blue)
10730 mng_info->equal_backgrounds=MagickFalse;
10732 if (next_image->gamma != next_image->next->gamma)
10733 mng_info->equal_gammas=MagickFalse;
10735 if (next_image->rendering_intent !=
10736 next_image->next->rendering_intent)
10737 mng_info->equal_srgbs=MagickFalse;
10739 if ((next_image->units != next_image->next->units) ||
10740 (next_image->x_resolution != next_image->next->x_resolution) ||
10741 (next_image->y_resolution != next_image->next->y_resolution))
10742 mng_info->equal_physs=MagickFalse;
10744 if (mng_info->equal_chrms)
10746 if (next_image->chromaticity.red_primary.x !=
10747 next_image->next->chromaticity.red_primary.x ||
10748 next_image->chromaticity.red_primary.y !=
10749 next_image->next->chromaticity.red_primary.y ||
10750 next_image->chromaticity.green_primary.x !=
10751 next_image->next->chromaticity.green_primary.x ||
10752 next_image->chromaticity.green_primary.y !=
10753 next_image->next->chromaticity.green_primary.y ||
10754 next_image->chromaticity.blue_primary.x !=
10755 next_image->next->chromaticity.blue_primary.x ||
10756 next_image->chromaticity.blue_primary.y !=
10757 next_image->next->chromaticity.blue_primary.y ||
10758 next_image->chromaticity.white_point.x !=
10759 next_image->next->chromaticity.white_point.x ||
10760 next_image->chromaticity.white_point.y !=
10761 next_image->next->chromaticity.white_point.y)
10762 mng_info->equal_chrms=MagickFalse;
10766 next_image=GetNextImageInList(next_image);
10768 if (image_count < 2)
10770 mng_info->equal_backgrounds=MagickFalse;
10771 mng_info->equal_chrms=MagickFalse;
10772 mng_info->equal_gammas=MagickFalse;
10773 mng_info->equal_srgbs=MagickFalse;
10774 mng_info->equal_physs=MagickFalse;
10775 use_global_plte=MagickFalse;
10776 #ifdef PNG_WRITE_EMPTY_PLTE_SUPPORTED
10777 need_local_plte=MagickTrue;
10779 need_iterations=MagickFalse;
10782 if (mng_info->need_fram == MagickFalse)
10785 Only certain framing rates 100/n are exactly representable without
10786 the FRAM chunk but we'll allow some slop in VLC files
10788 if (final_delay == 0)
10790 if (need_iterations != MagickFalse)
10793 It's probably a GIF with loop; don't run it *too* fast.
10795 if (mng_info->adjoin)
10798 (void) ThrowMagickException(&image->exception,
10799 GetMagickModule(),CoderWarning,
10800 "input has zero delay between all frames; assuming",
10805 mng_info->ticks_per_second=0;
10807 if (final_delay != 0)
10808 mng_info->ticks_per_second=(png_uint_32)
10809 (image->ticks_per_second/final_delay);
10810 if (final_delay > 50)
10811 mng_info->ticks_per_second=2;
10813 if (final_delay > 75)
10814 mng_info->ticks_per_second=1;
10816 if (final_delay > 125)
10817 mng_info->need_fram=MagickTrue;
10819 if (need_defi && final_delay > 2 && (final_delay != 4) &&
10820 (final_delay != 5) && (final_delay != 10) && (final_delay != 20) &&
10821 (final_delay != 25) && (final_delay != 50) && (final_delay !=
10822 1UL*image->ticks_per_second))
10823 mng_info->need_fram=MagickTrue; /* make it exact; cannot be VLC */
10826 if (mng_info->need_fram != MagickFalse)
10827 mng_info->ticks_per_second=1UL*image->ticks_per_second;
10829 If pseudocolor, we should also check to see if all the
10830 palettes are identical and write a global PLTE if they are.
10834 Write the MNG version 1.0 signature and MHDR chunk.
10836 (void) WriteBlob(image,8,(const unsigned char *) "\212MNG\r\n\032\n");
10837 (void) WriteBlobMSBULong(image,28L); /* chunk data length=28 */
10838 PNGType(chunk,mng_MHDR);
10839 LogPNGChunk(logging,mng_MHDR,28L);
10840 PNGLong(chunk+4,(png_uint_32) mng_info->page.width);
10841 PNGLong(chunk+8,(png_uint_32) mng_info->page.height);
10842 PNGLong(chunk+12,mng_info->ticks_per_second);
10843 PNGLong(chunk+16,0L); /* layer count=unknown */
10844 PNGLong(chunk+20,0L); /* frame count=unknown */
10845 PNGLong(chunk+24,0L); /* play time=unknown */
10850 if (need_defi || mng_info->need_fram || use_global_plte)
10851 PNGLong(chunk+28,27L); /* simplicity=LC+JNG */
10854 PNGLong(chunk+28,25L); /* simplicity=VLC+JNG */
10859 if (need_defi || mng_info->need_fram || use_global_plte)
10860 PNGLong(chunk+28,19L); /* simplicity=LC+JNG, no transparency */
10863 PNGLong(chunk+28,17L); /* simplicity=VLC+JNG, no transparency */
10871 if (need_defi || mng_info->need_fram || use_global_plte)
10872 PNGLong(chunk+28,11L); /* simplicity=LC */
10875 PNGLong(chunk+28,9L); /* simplicity=VLC */
10880 if (need_defi || mng_info->need_fram || use_global_plte)
10881 PNGLong(chunk+28,3L); /* simplicity=LC, no transparency */
10884 PNGLong(chunk+28,1L); /* simplicity=VLC, no transparency */
10887 (void) WriteBlob(image,32,chunk);
10888 (void) WriteBlobMSBULong(image,crc32(0,chunk,32));
10889 option=GetImageOption(image_info,"mng:need-cacheoff");
10890 if (option != (const char *) NULL)
10896 Write "nEED CACHEOFF" to turn playback caching off for streaming MNG.
10898 PNGType(chunk,mng_nEED);
10899 length=CopyMagickString((char *) chunk+4,"CACHEOFF",20);
10900 (void) WriteBlobMSBULong(image,(size_t) length);
10901 LogPNGChunk(logging,mng_nEED,(size_t) length);
10903 (void) WriteBlob(image,length,chunk);
10904 (void) WriteBlobMSBULong(image,crc32(0,chunk,(uInt) length));
10906 if ((GetPreviousImageInList(image) == (Image *) NULL) &&
10907 (GetNextImageInList(image) != (Image *) NULL) &&
10908 (image->iterations != 1))
10911 Write MNG TERM chunk
10913 (void) WriteBlobMSBULong(image,10L); /* data length=10 */
10914 PNGType(chunk,mng_TERM);
10915 LogPNGChunk(logging,mng_TERM,10L);
10916 chunk[4]=3; /* repeat animation */
10917 chunk[5]=0; /* show last frame when done */
10918 PNGLong(chunk+6,(png_uint_32) (mng_info->ticks_per_second*
10919 final_delay/MagickMax(image->ticks_per_second,1)));
10921 if (image->iterations == 0)
10922 PNGLong(chunk+10,PNG_UINT_31_MAX);
10925 PNGLong(chunk+10,(png_uint_32) image->iterations);
10927 if (logging != MagickFalse)
10929 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10930 " TERM delay: %.20g",(double) (mng_info->ticks_per_second*
10931 final_delay/MagickMax(image->ticks_per_second,1)));
10933 if (image->iterations == 0)
10934 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10935 " TERM iterations: %.20g",(double) PNG_UINT_31_MAX);
10938 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10939 " Image iterations: %.20g",(double) image->iterations);
10941 (void) WriteBlob(image,14,chunk);
10942 (void) WriteBlobMSBULong(image,crc32(0,chunk,14));
10945 To do: check for cHRM+gAMA == sRGB, and write sRGB instead.
10947 if ((image->colorspace == sRGBColorspace || image->rendering_intent) &&
10948 mng_info->equal_srgbs)
10951 Write MNG sRGB chunk
10953 (void) WriteBlobMSBULong(image,1L);
10954 PNGType(chunk,mng_sRGB);
10955 LogPNGChunk(logging,mng_sRGB,1L);
10957 if (image->rendering_intent != UndefinedIntent)
10958 chunk[4]=(unsigned char)
10959 Magick_RenderingIntent_to_PNG_RenderingIntent(
10960 (image->rendering_intent));
10963 chunk[4]=(unsigned char)
10964 Magick_RenderingIntent_to_PNG_RenderingIntent(
10965 (PerceptualIntent));
10967 (void) WriteBlob(image,5,chunk);
10968 (void) WriteBlobMSBULong(image,crc32(0,chunk,5));
10969 mng_info->have_write_global_srgb=MagickTrue;
10974 if (image->gamma && mng_info->equal_gammas)
10977 Write MNG gAMA chunk
10979 (void) WriteBlobMSBULong(image,4L);
10980 PNGType(chunk,mng_gAMA);
10981 LogPNGChunk(logging,mng_gAMA,4L);
10982 PNGLong(chunk+4,(png_uint_32) (100000*image->gamma+0.5));
10983 (void) WriteBlob(image,8,chunk);
10984 (void) WriteBlobMSBULong(image,crc32(0,chunk,8));
10985 mng_info->have_write_global_gama=MagickTrue;
10987 if (mng_info->equal_chrms)
10993 Write MNG cHRM chunk
10995 (void) WriteBlobMSBULong(image,32L);
10996 PNGType(chunk,mng_cHRM);
10997 LogPNGChunk(logging,mng_cHRM,32L);
10998 primary=image->chromaticity.white_point;
10999 PNGLong(chunk+4,(png_uint_32) (100000*primary.x+0.5));
11000 PNGLong(chunk+8,(png_uint_32) (100000*primary.y+0.5));
11001 primary=image->chromaticity.red_primary;
11002 PNGLong(chunk+12,(png_uint_32) (100000*primary.x+0.5));
11003 PNGLong(chunk+16,(png_uint_32) (100000*primary.y+0.5));
11004 primary=image->chromaticity.green_primary;
11005 PNGLong(chunk+20,(png_uint_32) (100000*primary.x+0.5));
11006 PNGLong(chunk+24,(png_uint_32) (100000*primary.y+0.5));
11007 primary=image->chromaticity.blue_primary;
11008 PNGLong(chunk+28,(png_uint_32) (100000*primary.x+0.5));
11009 PNGLong(chunk+32,(png_uint_32) (100000*primary.y+0.5));
11010 (void) WriteBlob(image,36,chunk);
11011 (void) WriteBlobMSBULong(image,crc32(0,chunk,36));
11012 mng_info->have_write_global_chrm=MagickTrue;
11015 if (image->x_resolution && image->y_resolution && mng_info->equal_physs)
11018 Write MNG pHYs chunk
11020 (void) WriteBlobMSBULong(image,9L);
11021 PNGType(chunk,mng_pHYs);
11022 LogPNGChunk(logging,mng_pHYs,9L);
11024 if (image->units == PixelsPerInchResolution)
11026 PNGLong(chunk+4,(png_uint_32)
11027 (image->x_resolution*100.0/2.54+0.5));
11029 PNGLong(chunk+8,(png_uint_32)
11030 (image->y_resolution*100.0/2.54+0.5));
11037 if (image->units == PixelsPerCentimeterResolution)
11039 PNGLong(chunk+4,(png_uint_32)
11040 (image->x_resolution*100.0+0.5));
11042 PNGLong(chunk+8,(png_uint_32)
11043 (image->y_resolution*100.0+0.5));
11050 PNGLong(chunk+4,(png_uint_32) (image->x_resolution+0.5));
11051 PNGLong(chunk+8,(png_uint_32) (image->y_resolution+0.5));
11055 (void) WriteBlob(image,13,chunk);
11056 (void) WriteBlobMSBULong(image,crc32(0,chunk,13));
11059 Write MNG BACK chunk and global bKGD chunk, if the image is transparent
11060 or does not cover the entire frame.
11062 if (write_mng && (image->matte || image->page.x > 0 ||
11063 image->page.y > 0 || (image->page.width &&
11064 (image->page.width+image->page.x < mng_info->page.width))
11065 || (image->page.height && (image->page.height+image->page.y
11066 < mng_info->page.height))))
11068 (void) WriteBlobMSBULong(image,6L);
11069 PNGType(chunk,mng_BACK);
11070 LogPNGChunk(logging,mng_BACK,6L);
11071 red=ScaleQuantumToShort(image->background_color.red);
11072 green=ScaleQuantumToShort(image->background_color.green);
11073 blue=ScaleQuantumToShort(image->background_color.blue);
11074 PNGShort(chunk+4,red);
11075 PNGShort(chunk+6,green);
11076 PNGShort(chunk+8,blue);
11077 (void) WriteBlob(image,10,chunk);
11078 (void) WriteBlobMSBULong(image,crc32(0,chunk,10));
11079 if (mng_info->equal_backgrounds)
11081 (void) WriteBlobMSBULong(image,6L);
11082 PNGType(chunk,mng_bKGD);
11083 LogPNGChunk(logging,mng_bKGD,6L);
11084 (void) WriteBlob(image,10,chunk);
11085 (void) WriteBlobMSBULong(image,crc32(0,chunk,10));
11089 #ifdef PNG_WRITE_EMPTY_PLTE_SUPPORTED
11090 if ((need_local_plte == MagickFalse) &&
11091 (image->storage_class == PseudoClass) &&
11092 (all_images_are_gray == MagickFalse))
11098 Write MNG PLTE chunk
11100 data_length=3*image->colors;
11101 (void) WriteBlobMSBULong(image,data_length);
11102 PNGType(chunk,mng_PLTE);
11103 LogPNGChunk(logging,mng_PLTE,data_length);
11105 for (i=0; i < (ssize_t) image->colors; i++)
11107 chunk[4+i*3]=ScaleQuantumToChar(image->colormap[i].red) & 0xff;
11108 chunk[5+i*3]=ScaleQuantumToChar(image->colormap[i].green) & 0xff;
11109 chunk[6+i*3]=ScaleQuantumToChar(image->colormap[i].blue) & 0xff;
11112 (void) WriteBlob(image,data_length+4,chunk);
11113 (void) WriteBlobMSBULong(image,crc32(0,chunk,(uInt) (data_length+4)));
11114 mng_info->have_write_global_plte=MagickTrue;
11120 #if defined(PNG_WRITE_EMPTY_PLTE_SUPPORTED) || \
11121 defined(PNG_MNG_FEATURES_SUPPORTED)
11122 mng_info->equal_palettes=MagickFalse;
11126 if (mng_info->adjoin)
11128 #if defined(PNG_WRITE_EMPTY_PLTE_SUPPORTED) || \
11129 defined(PNG_MNG_FEATURES_SUPPORTED)
11131 If we aren't using a global palette for the entire MNG, check to
11132 see if we can use one for two or more consecutive images.
11134 if (need_local_plte && use_global_plte && !all_images_are_gray)
11136 if (mng_info->IsPalette)
11139 When equal_palettes is true, this image has the same palette
11140 as the previous PseudoClass image
11142 mng_info->have_write_global_plte=mng_info->equal_palettes;
11143 mng_info->equal_palettes=PalettesAreEqual(image,image->next);
11144 if (mng_info->equal_palettes && !mng_info->have_write_global_plte)
11147 Write MNG PLTE chunk
11152 data_length=3*image->colors;
11153 (void) WriteBlobMSBULong(image,data_length);
11154 PNGType(chunk,mng_PLTE);
11155 LogPNGChunk(logging,mng_PLTE,data_length);
11157 for (i=0; i < (ssize_t) image->colors; i++)
11159 chunk[4+i*3]=ScaleQuantumToChar(image->colormap[i].red);
11160 chunk[5+i*3]=ScaleQuantumToChar(image->colormap[i].green);
11161 chunk[6+i*3]=ScaleQuantumToChar(image->colormap[i].blue);
11164 (void) WriteBlob(image,data_length+4,chunk);
11165 (void) WriteBlobMSBULong(image,crc32(0,chunk,
11166 (uInt) (data_length+4)));
11167 mng_info->have_write_global_plte=MagickTrue;
11171 mng_info->have_write_global_plte=MagickFalse;
11182 previous_x=mng_info->page.x;
11183 previous_y=mng_info->page.y;
11190 mng_info->page=image->page;
11191 if ((mng_info->page.x != previous_x) ||
11192 (mng_info->page.y != previous_y))
11194 (void) WriteBlobMSBULong(image,12L); /* data length=12 */
11195 PNGType(chunk,mng_DEFI);
11196 LogPNGChunk(logging,mng_DEFI,12L);
11197 chunk[4]=0; /* object 0 MSB */
11198 chunk[5]=0; /* object 0 LSB */
11199 chunk[6]=0; /* visible */
11200 chunk[7]=0; /* abstract */
11201 PNGLong(chunk+8,(png_uint_32) mng_info->page.x);
11202 PNGLong(chunk+12,(png_uint_32) mng_info->page.y);
11203 (void) WriteBlob(image,16,chunk);
11204 (void) WriteBlobMSBULong(image,crc32(0,chunk,16));
11209 mng_info->write_mng=write_mng;
11211 if ((int) image->dispose >= 3)
11212 mng_info->framing_mode=3;
11214 if (mng_info->need_fram && mng_info->adjoin &&
11215 ((image->delay != mng_info->delay) ||
11216 (mng_info->framing_mode != mng_info->old_framing_mode)))
11218 if (image->delay == mng_info->delay)
11221 Write a MNG FRAM chunk with the new framing mode.
11223 (void) WriteBlobMSBULong(image,1L); /* data length=1 */
11224 PNGType(chunk,mng_FRAM);
11225 LogPNGChunk(logging,mng_FRAM,1L);
11226 chunk[4]=(unsigned char) mng_info->framing_mode;
11227 (void) WriteBlob(image,5,chunk);
11228 (void) WriteBlobMSBULong(image,crc32(0,chunk,5));
11233 Write a MNG FRAM chunk with the delay.
11235 (void) WriteBlobMSBULong(image,10L); /* data length=10 */
11236 PNGType(chunk,mng_FRAM);
11237 LogPNGChunk(logging,mng_FRAM,10L);
11238 chunk[4]=(unsigned char) mng_info->framing_mode;
11239 chunk[5]=0; /* frame name separator (no name) */
11240 chunk[6]=2; /* flag for changing default delay */
11241 chunk[7]=0; /* flag for changing frame timeout */
11242 chunk[8]=0; /* flag for changing frame clipping */
11243 chunk[9]=0; /* flag for changing frame sync_id */
11244 PNGLong(chunk+10,(png_uint_32)
11245 ((mng_info->ticks_per_second*
11246 image->delay)/MagickMax(image->ticks_per_second,1)));
11247 (void) WriteBlob(image,14,chunk);
11248 (void) WriteBlobMSBULong(image,crc32(0,chunk,14));
11249 mng_info->delay=(png_uint_32) image->delay;
11251 mng_info->old_framing_mode=mng_info->framing_mode;
11254 #if defined(JNG_SUPPORTED)
11255 if (image_info->compression == JPEGCompression)
11260 if (logging != MagickFalse)
11261 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11262 " Writing JNG object.");
11263 /* To do: specify the desired alpha compression method. */
11264 write_info=CloneImageInfo(image_info);
11265 write_info->compression=UndefinedCompression;
11266 status=WriteOneJNGImage(mng_info,write_info,image);
11267 write_info=DestroyImageInfo(write_info);
11272 if (logging != MagickFalse)
11273 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11274 " Writing PNG object.");
11276 mng_info->need_blob = MagickFalse;
11278 /* We don't want any ancillary chunks written */
11279 mng_info->ping_exclude_bKGD=MagickTrue;
11280 mng_info->ping_exclude_cHRM=MagickTrue;
11281 mng_info->ping_exclude_EXIF=MagickTrue;
11282 mng_info->ping_exclude_gAMA=MagickTrue;
11283 mng_info->ping_exclude_cHRM=MagickTrue;
11284 mng_info->ping_exclude_iCCP=MagickTrue;
11285 /* mng_info->ping_exclude_iTXt=MagickTrue; */
11286 mng_info->ping_exclude_oFFs=MagickTrue;
11287 mng_info->ping_exclude_pHYs=MagickTrue;
11288 mng_info->ping_exclude_sRGB=MagickTrue;
11289 mng_info->ping_exclude_tEXt=MagickTrue;
11290 mng_info->ping_exclude_tRNS=MagickTrue;
11291 mng_info->ping_exclude_vpAg=MagickTrue;
11292 mng_info->ping_exclude_zCCP=MagickTrue;
11293 mng_info->ping_exclude_zTXt=MagickTrue;
11295 status=WriteOnePNGImage(mng_info,image_info,image);
11298 if (status == MagickFalse)
11300 MngInfoFreeStruct(mng_info,&have_mng_structure);
11301 (void) CloseBlob(image);
11302 return(MagickFalse);
11304 (void) CatchImageException(image);
11305 if (GetNextImageInList(image) == (Image *) NULL)
11307 image=SyncNextImageInList(image);
11308 status=SetImageProgress(image,SaveImagesTag,scene++,
11309 GetImageListLength(image));
11311 if (status == MagickFalse)
11314 } while (mng_info->adjoin);
11318 while (GetPreviousImageInList(image) != (Image *) NULL)
11319 image=GetPreviousImageInList(image);
11321 Write the MEND chunk.
11323 (void) WriteBlobMSBULong(image,0x00000000L);
11324 PNGType(chunk,mng_MEND);
11325 LogPNGChunk(logging,mng_MEND,0L);
11326 (void) WriteBlob(image,4,chunk);
11327 (void) WriteBlobMSBULong(image,crc32(0,chunk,4));
11330 Relinquish resources.
11332 (void) CloseBlob(image);
11333 MngInfoFreeStruct(mng_info,&have_mng_structure);
11335 if (logging != MagickFalse)
11336 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"exit WriteMNGImage()");
11338 return(MagickTrue);
11340 #else /* PNG_LIBPNG_VER > 10011 */
11342 static MagickBooleanType WritePNGImage(const ImageInfo *image_info,Image *image)
11345 printf("Your PNG library is too old: You have libpng-%s\n",
11346 PNG_LIBPNG_VER_STRING);
11348 ThrowBinaryException(CoderError,"PNG library is too old",
11349 image_info->filename);
11352 static MagickBooleanType WriteMNGImage(const ImageInfo *image_info,Image *image)
11354 return(WritePNGImage(image_info,image));
11356 #endif /* PNG_LIBPNG_VER > 10011 */