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 ((((size_t) image->colormap[indx].opacity >> 8) & 0xff)
534 == ((size_t) image->colormap[indx].opacity & 0xff))) ?
535 MagickTrue : MagickFalse;
536 if (ok_to_reduce == MagickFalse)
541 if ((ok_to_reduce != MagickFalse) &&
542 (image->storage_class != PseudoClass))
550 for (y=0; y < (ssize_t) image->rows; y++)
552 p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception);
554 if (p == (const PixelPacket *) NULL)
556 ok_to_reduce = MagickFalse;
560 for (x=(ssize_t) image->columns-1; x >= 0; x--)
563 (((size_t) p->red >> 8) & 0xff) ==
564 ((size_t) p->red & 0xff)) &&
565 ((((size_t) p->green >> 8) & 0xff) ==
566 ((size_t) p->green & 0xff)) &&
567 ((((size_t) p->blue >> 8) & 0xff) ==
568 ((size_t) p->blue & 0xff)) &&
570 (((size_t) p->opacity >> 8) & 0xff) ==
571 ((size_t) p->opacity & 0xff))))) ? MagickTrue : MagickFalse;
573 if (ok_to_reduce == MagickFalse)
583 if (ok_to_reduce != MagickFalse)
585 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
586 " OK to reduce PNG bit depth to 8 without loss of info");
590 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
591 " Not OK to reduce PNG bit depth to 8 without loss of info");
597 #endif /* MAGICKCORE_QUANTUM_DEPTH >= 16 */
600 Magick_RenderingIntent_to_PNG_RenderingIntent(const RenderingIntent intent)
604 case PerceptualIntent:
610 case SaturationIntent:
621 static RenderingIntent
622 Magick_RenderingIntent_from_PNG_RenderingIntent(const int ping_intent)
627 return PerceptualIntent;
630 return RelativeIntent;
633 return SaturationIntent;
636 return AbsoluteIntent;
639 return UndefinedIntent;
643 static inline ssize_t MagickMax(const ssize_t x,const ssize_t y)
651 static inline ssize_t MagickMin(const ssize_t x,const ssize_t y)
661 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
665 % I m a g e I s G r a y %
669 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
671 % Like IsGrayImage except does not change DirectClass to PseudoClass %
673 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
675 static MagickBooleanType ImageIsGray(Image *image)
677 register const PixelPacket
685 assert(image != (Image *) NULL);
686 assert(image->signature == MagickSignature);
687 if (image->debug != MagickFalse)
688 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
690 if (image->storage_class == PseudoClass)
692 for (i=0; i < (ssize_t) image->colors; i++)
693 if (IsGray(image->colormap+i) == MagickFalse)
697 for (y=0; y < (ssize_t) image->rows; y++)
699 p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception);
700 if (p == (const PixelPacket *) NULL)
702 for (x=(ssize_t) image->columns-1; x >= 0; x--)
704 if (IsGray(p) == MagickFalse)
713 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
717 % I m a g e I s M o n o c h r o m e %
721 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
723 % Like IsMonochromeImage except does not change DirectClass to PseudoClass %
724 % and is more accurate. %
726 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
728 static MagickBooleanType ImageIsMonochrome(Image *image)
730 register const PixelPacket
738 assert(image != (Image *) NULL);
739 assert(image->signature == MagickSignature);
740 if (image->debug != MagickFalse)
741 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
742 if (image->storage_class == PseudoClass)
744 for (i=0; i < (ssize_t) image->colors; i++)
746 if ((IsGray(image->colormap+i) == MagickFalse) ||
747 ((image->colormap[i].red != 0) &&
748 (image->colormap[i].red != (Quantum) QuantumRange)))
753 for (y=0; y < (ssize_t) image->rows; y++)
755 p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception);
756 if (p == (const PixelPacket *) NULL)
758 for (x=(ssize_t) image->columns-1; x >= 0; x--)
760 if ((p->red != 0) && (p->red != (Quantum) QuantumRange))
763 if (IsGray(p) == MagickFalse)
766 if ((p->opacity != OpaqueOpacity) &&
767 (p->opacity != (Quantum) TransparentOpacity))
775 #endif /* PNG_LIBPNG_VER > 10011 */
776 #endif /* MAGICKCORE_PNG_DELEGATE */
779 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
787 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
789 % IsMNG() returns MagickTrue if the image format type, identified by the
790 % magick string, is MNG.
792 % The format of the IsMNG method is:
794 % MagickBooleanType IsMNG(const unsigned char *magick,const size_t length)
796 % A description of each parameter follows:
798 % o magick: compare image format pattern against these bytes.
800 % o length: Specifies the length of the magick string.
804 static MagickBooleanType IsMNG(const unsigned char *magick,const size_t length)
809 if (memcmp(magick,"\212MNG\r\n\032\n",8) == 0)
816 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
824 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
826 % IsJNG() returns MagickTrue if the image format type, identified by the
827 % magick string, is JNG.
829 % The format of the IsJNG method is:
831 % MagickBooleanType IsJNG(const unsigned char *magick,const size_t length)
833 % A description of each parameter follows:
835 % o magick: compare image format pattern against these bytes.
837 % o length: Specifies the length of the magick string.
841 static MagickBooleanType IsJNG(const unsigned char *magick,const size_t length)
846 if (memcmp(magick,"\213JNG\r\n\032\n",8) == 0)
853 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
861 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
863 % IsPNG() returns MagickTrue if the image format type, identified by the
864 % magick string, is PNG.
866 % The format of the IsPNG method is:
868 % MagickBooleanType IsPNG(const unsigned char *magick,const size_t length)
870 % A description of each parameter follows:
872 % o magick: compare image format pattern against these bytes.
874 % o length: Specifies the length of the magick string.
877 static MagickBooleanType IsPNG(const unsigned char *magick,const size_t length)
882 if (memcmp(magick,"\211PNG\r\n\032\n",8) == 0)
888 #if defined(MAGICKCORE_PNG_DELEGATE)
889 #if defined(__cplusplus) || defined(c_plusplus)
893 #if (PNG_LIBPNG_VER > 10011)
894 static size_t WriteBlobMSBULong(Image *image,const size_t value)
899 assert(image != (Image *) NULL);
900 assert(image->signature == MagickSignature);
901 buffer[0]=(unsigned char) (value >> 24);
902 buffer[1]=(unsigned char) (value >> 16);
903 buffer[2]=(unsigned char) (value >> 8);
904 buffer[3]=(unsigned char) value;
905 return((size_t) WriteBlob(image,4,buffer));
908 static void PNGLong(png_bytep p,png_uint_32 value)
910 *p++=(png_byte) ((value >> 24) & 0xff);
911 *p++=(png_byte) ((value >> 16) & 0xff);
912 *p++=(png_byte) ((value >> 8) & 0xff);
913 *p++=(png_byte) (value & 0xff);
916 #if defined(JNG_SUPPORTED)
917 static void PNGsLong(png_bytep p,png_int_32 value)
919 *p++=(png_byte) ((value >> 24) & 0xff);
920 *p++=(png_byte) ((value >> 16) & 0xff);
921 *p++=(png_byte) ((value >> 8) & 0xff);
922 *p++=(png_byte) (value & 0xff);
926 static void PNGShort(png_bytep p,png_uint_16 value)
928 *p++=(png_byte) ((value >> 8) & 0xff);
929 *p++=(png_byte) (value & 0xff);
932 static void PNGType(png_bytep p,png_bytep type)
934 (void) CopyMagickMemory(p,type,4*sizeof(png_byte));
937 static void LogPNGChunk(MagickBooleanType logging, png_bytep type,
940 if (logging != MagickFalse)
941 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
942 " Writing %c%c%c%c chunk, length: %.20g",
943 type[0],type[1],type[2],type[3],(double) length);
945 #endif /* PNG_LIBPNG_VER > 10011 */
947 #if defined(__cplusplus) || defined(c_plusplus)
951 #if PNG_LIBPNG_VER > 10011
953 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
957 % R e a d P N G I m a g e %
961 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
963 % ReadPNGImage() reads a Portable Network Graphics (PNG) or
964 % Multiple-image Network Graphics (MNG) image file and returns it. It
965 % allocates the memory necessary for the new Image structure and returns a
966 % pointer to the new image or set of images.
968 % MNG support written by Glenn Randers-Pehrson, glennrp@image...
970 % The format of the ReadPNGImage method is:
972 % Image *ReadPNGImage(const ImageInfo *image_info,ExceptionInfo *exception)
974 % A description of each parameter follows:
976 % o image_info: the image info.
978 % o exception: return any errors or warnings in this structure.
980 % To do, more or less in chronological order (as of version 5.5.2,
981 % November 26, 2002 -- glennrp -- see also "To do" under WriteMNGImage):
983 % Get 16-bit cheap transparency working.
985 % (At this point, PNG decoding is supposed to be in full MNG-LC compliance)
987 % Preserve all unknown and not-yet-handled known chunks found in input
988 % PNG file and copy them into output PNG files according to the PNG
991 % (At this point, PNG encoding should be in full MNG compliance)
993 % Provide options for choice of background to use when the MNG BACK
994 % chunk is not present or is not mandatory (i.e., leave transparent,
995 % user specified, MNG BACK, PNG bKGD)
997 % Implement LOOP/ENDL [done, but could do discretionary loops more
998 % efficiently by linking in the duplicate frames.].
1000 % Decode and act on the MHDR simplicity profile (offer option to reject
1001 % files or attempt to process them anyway when the profile isn't LC or VLC).
1003 % Upgrade to full MNG without Delta-PNG.
1005 % o BACK [done a while ago except for background image ID]
1006 % o MOVE [done 15 May 1999]
1007 % o CLIP [done 15 May 1999]
1008 % o DISC [done 19 May 1999]
1009 % o SAVE [partially done 19 May 1999 (marks objects frozen)]
1010 % o SEEK [partially done 19 May 1999 (discard function only)]
1014 % o MNG-level tEXt/iTXt/zTXt
1019 % o iTXt (wait for libpng implementation).
1021 % Use the scene signature to discover when an identical scene is
1022 % being reused, and just point to the original image->exception instead
1023 % of storing another set of pixels. This not specific to MNG
1024 % but could be applied generally.
1026 % Upgrade to full MNG with Delta-PNG.
1028 % JNG tEXt/iTXt/zTXt
1030 % We will not attempt to read files containing the CgBI chunk.
1031 % They are really Xcode files meant for display on the iPhone.
1032 % These are not valid PNG files and it is impossible to recover
1033 % the orginal PNG from files that have been converted to Xcode-PNG,
1034 % since irretrievable loss of color data has occurred due to the
1035 % use of premultiplied alpha.
1038 #if defined(__cplusplus) || defined(c_plusplus)
1043 This the function that does the actual reading of data. It is
1044 the same as the one supplied in libpng, except that it receives the
1045 datastream from the ReadBlob() function instead of standard input.
1047 static void png_get_data(png_structp png_ptr,png_bytep data,png_size_t length)
1052 image=(Image *) png_get_io_ptr(png_ptr);
1058 check=(png_size_t) ReadBlob(image,(size_t) length,data);
1059 if (check != length)
1064 (void) FormatMagickString(msg,MaxTextExtent,
1065 "Expected %.20g bytes; found %.20g bytes",(double) length,
1067 png_warning(png_ptr,msg);
1068 png_error(png_ptr,"Read Exception");
1073 #if !defined(PNG_READ_EMPTY_PLTE_SUPPORTED) && \
1074 !defined(PNG_MNG_FEATURES_SUPPORTED)
1075 /* We use mng_get_data() instead of png_get_data() if we have a libpng
1076 * older than libpng-1.0.3a, which was the first to allow the empty
1077 * PLTE, or a newer libpng in which PNG_MNG_FEATURES_SUPPORTED was
1078 * ifdef'ed out. Earlier versions would crash if the bKGD chunk was
1079 * encountered after an empty PLTE, so we have to look ahead for bKGD
1080 * chunks and remove them from the datastream that is passed to libpng,
1081 * and store their contents for later use.
1083 static void mng_get_data(png_structp png_ptr,png_bytep data,png_size_t length)
1098 mng_info=(MngInfo *) png_get_io_ptr(png_ptr);
1099 image=(Image *) mng_info->image;
1100 while (mng_info->bytes_in_read_buffer && length)
1102 data[i]=mng_info->read_buffer[i];
1103 mng_info->bytes_in_read_buffer--;
1109 check=(png_size_t) ReadBlob(image,(size_t) length,(char *) data);
1111 if (check != length)
1112 png_error(png_ptr,"Read Exception");
1116 if ((data[0] == 0) && (data[1] == 0) && (data[2] == 0) &&
1119 check=(png_size_t) ReadBlob(image,(size_t) length,
1120 (char *) mng_info->read_buffer);
1121 mng_info->read_buffer[4]=0;
1122 mng_info->bytes_in_read_buffer=4;
1123 if (memcmp(mng_info->read_buffer,mng_PLTE,4) == 0)
1124 mng_info->found_empty_plte=MagickTrue;
1125 if (memcmp(mng_info->read_buffer,mng_IEND,4) == 0)
1127 mng_info->found_empty_plte=MagickFalse;
1128 mng_info->have_saved_bkgd_index=MagickFalse;
1132 if ((data[0] == 0) && (data[1] == 0) && (data[2] == 0) &&
1135 check=(png_size_t) ReadBlob(image,(size_t) length,
1136 (char *) mng_info->read_buffer);
1137 mng_info->read_buffer[4]=0;
1138 mng_info->bytes_in_read_buffer=4;
1139 if (memcmp(mng_info->read_buffer,mng_bKGD,4) == 0)
1140 if (mng_info->found_empty_plte)
1143 Skip the bKGD data byte and CRC.
1146 ReadBlob(image,5,(char *) mng_info->read_buffer);
1147 check=(png_size_t) ReadBlob(image,(size_t) length,
1148 (char *) mng_info->read_buffer);
1149 mng_info->saved_bkgd_index=mng_info->read_buffer[0];
1150 mng_info->have_saved_bkgd_index=MagickTrue;
1151 mng_info->bytes_in_read_buffer=0;
1159 static void png_put_data(png_structp png_ptr,png_bytep data,png_size_t length)
1164 image=(Image *) png_get_io_ptr(png_ptr);
1170 check=(png_size_t) WriteBlob(image,(size_t) length,data);
1172 if (check != length)
1173 png_error(png_ptr,"WriteBlob Failed");
1177 static void png_flush_data(png_structp png_ptr)
1182 #ifdef PNG_WRITE_EMPTY_PLTE_SUPPORTED
1183 static int PalettesAreEqual(Image *a,Image *b)
1188 if ((a == (Image *) NULL) || (b == (Image *) NULL))
1189 return((int) MagickFalse);
1191 if (a->storage_class != PseudoClass || b->storage_class != PseudoClass)
1192 return((int) MagickFalse);
1194 if (a->colors != b->colors)
1195 return((int) MagickFalse);
1197 for (i=0; i < (ssize_t) a->colors; i++)
1199 if ((a->colormap[i].red != b->colormap[i].red) ||
1200 (a->colormap[i].green != b->colormap[i].green) ||
1201 (a->colormap[i].blue != b->colormap[i].blue))
1202 return((int) MagickFalse);
1205 return((int) MagickTrue);
1209 static void MngInfoDiscardObject(MngInfo *mng_info,int i)
1211 if (i && (i < MNG_MAX_OBJECTS) && (mng_info != (MngInfo *) NULL) &&
1212 mng_info->exists[i] && !mng_info->frozen[i])
1214 #ifdef MNG_OBJECT_BUFFERS
1215 if (mng_info->ob[i] != (MngBuffer *) NULL)
1217 if (mng_info->ob[i]->reference_count > 0)
1218 mng_info->ob[i]->reference_count--;
1220 if (mng_info->ob[i]->reference_count == 0)
1222 if (mng_info->ob[i]->image != (Image *) NULL)
1223 mng_info->ob[i]->image=DestroyImage(mng_info->ob[i]->image);
1225 mng_info->ob[i]=DestroyString(mng_info->ob[i]);
1228 mng_info->ob[i]=(MngBuffer *) NULL;
1230 mng_info->exists[i]=MagickFalse;
1231 mng_info->invisible[i]=MagickFalse;
1232 mng_info->viewable[i]=MagickFalse;
1233 mng_info->frozen[i]=MagickFalse;
1234 mng_info->x_off[i]=0;
1235 mng_info->y_off[i]=0;
1236 mng_info->object_clip[i].left=0;
1237 mng_info->object_clip[i].right=(ssize_t) PNG_UINT_31_MAX;
1238 mng_info->object_clip[i].top=0;
1239 mng_info->object_clip[i].bottom=(ssize_t) PNG_UINT_31_MAX;
1243 static void MngInfoFreeStruct(MngInfo *mng_info,
1244 MagickBooleanType *have_mng_structure)
1246 if (*have_mng_structure != MagickFalse && (mng_info != (MngInfo *) NULL))
1251 for (i=1; i < MNG_MAX_OBJECTS; i++)
1252 MngInfoDiscardObject(mng_info,i);
1254 if (mng_info->global_plte != (png_colorp) NULL)
1255 mng_info->global_plte=(png_colorp)
1256 RelinquishMagickMemory(mng_info->global_plte);
1258 mng_info=(MngInfo *) RelinquishMagickMemory(mng_info);
1259 *have_mng_structure=MagickFalse;
1263 static MngBox mng_minimum_box(MngBox box1,MngBox box2)
1269 if (box.left < box2.left)
1272 if (box.top < box2.top)
1275 if (box.right > box2.right)
1276 box.right=box2.right;
1278 if (box.bottom > box2.bottom)
1279 box.bottom=box2.bottom;
1284 static MngBox mng_read_box(MngBox previous_box,char delta_type,unsigned char *p)
1290 Read clipping boundaries from DEFI, CLIP, FRAM, or PAST chunk.
1292 box.left=(ssize_t) ((p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]);
1293 box.right=(ssize_t) ((p[4] << 24) | (p[5] << 16) | (p[6] << 8) | p[7]);
1294 box.top=(ssize_t) ((p[8] << 24) | (p[9] << 16) | (p[10] << 8) | p[11]);
1295 box.bottom=(ssize_t) ((p[12] << 24) | (p[13] << 16) | (p[14] << 8) | p[15]);
1296 if (delta_type != 0)
1298 box.left+=previous_box.left;
1299 box.right+=previous_box.right;
1300 box.top+=previous_box.top;
1301 box.bottom+=previous_box.bottom;
1307 static MngPair mng_read_pair(MngPair previous_pair,int delta_type,
1313 Read two ssize_ts from CLON, MOVE or PAST chunk
1315 pair.a=(long) ((p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]);
1316 pair.b=(long) ((p[4] << 24) | (p[5] << 16) | (p[6] << 8) | p[7]);
1318 if (delta_type != 0)
1320 pair.a+=previous_pair.a;
1321 pair.b+=previous_pair.b;
1327 static long mng_get_long(unsigned char *p)
1329 return((long) ((p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]));
1332 static void MagickPNGErrorHandler(png_struct *ping,png_const_charp message)
1337 image=(Image *) png_get_error_ptr(ping);
1339 if (image->debug != MagickFalse)
1340 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1341 " libpng-%s error: %s", PNG_LIBPNG_VER_STRING,message);
1343 (void) ThrowMagickException(&image->exception,GetMagickModule(),CoderError,
1344 message,"`%s'",image->filename);
1346 #if (PNG_LIBPNG_VER < 10500)
1347 longjmp(ping->jmpbuf,1);
1349 png_longjmp(ping,1);
1353 static void MagickPNGWarningHandler(png_struct *ping,png_const_charp message)
1358 if (LocaleCompare(message, "Missing PLTE before tRNS") == 0)
1359 png_error(ping, message);
1361 image=(Image *) png_get_error_ptr(ping);
1362 if (image->debug != MagickFalse)
1363 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1364 " libpng-%s warning: %s", PNG_LIBPNG_VER_STRING,message);
1366 (void) ThrowMagickException(&image->exception,GetMagickModule(),CoderWarning,
1367 message,"`%s'",image->filename);
1370 #ifdef PNG_USER_MEM_SUPPORTED
1371 static png_voidp Magick_png_malloc(png_structp png_ptr,png_uint_32 size)
1373 #if (PNG_LIBPNG_VER < 10011)
1378 ret=((png_voidp) AcquireMagickMemory((size_t) size));
1381 png_error("Insufficient memory.");
1386 return((png_voidp) AcquireMagickMemory((size_t) size));
1391 Free a pointer. It is removed from the list at the same time.
1393 static png_free_ptr Magick_png_free(png_structp png_ptr,png_voidp ptr)
1396 ptr=RelinquishMagickMemory(ptr);
1397 return((png_free_ptr) NULL);
1401 #if defined(__cplusplus) || defined(c_plusplus)
1406 Magick_png_read_raw_profile(Image *image, const ImageInfo *image_info,
1407 png_textp text,int ii)
1412 register unsigned char
1426 unhex[103]={0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,
1427 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,
1428 0,0,0,0,0,0,0,0,0,1, 2,3,4,5,6,7,8,9,0,0,
1429 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,
1430 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,10,11,12,
1434 /* look for newline */
1438 /* look for length */
1439 while (*sp == '\0' || *sp == ' ' || *sp == '\n')
1442 length=(png_uint_32) StringToLong(sp);
1444 while (*sp != ' ' && *sp != '\n')
1447 /* allocate space */
1450 (void) ThrowMagickException(&image->exception,GetMagickModule(),
1451 CoderWarning,"UnableToCopyProfile","`%s'","invalid profile length");
1452 return(MagickFalse);
1455 profile=AcquireStringInfo(length);
1457 if (profile == (StringInfo *) NULL)
1459 (void) ThrowMagickException(&image->exception,GetMagickModule(),
1460 ResourceLimitError,"MemoryAllocationFailed","`%s'",
1461 "unable to copy profile");
1462 return(MagickFalse);
1465 /* copy profile, skipping white space and column 1 "=" signs */
1466 dp=GetStringInfoDatum(profile);
1469 for (i=0; i < (ssize_t) nibbles; i++)
1471 while (*sp < '0' || (*sp > '9' && *sp < 'a') || *sp > 'f')
1475 (void) ThrowMagickException(&image->exception,GetMagickModule(),
1476 CoderWarning,"UnableToCopyProfile","`%s'","ran out of data");
1477 profile=DestroyStringInfo(profile);
1478 return(MagickFalse);
1484 *dp=(unsigned char) (16*unhex[(int) *sp++]);
1487 (*dp++)+=unhex[(int) *sp++];
1490 We have already read "Raw profile type.
1492 (void) SetImageProfile(image,&text[ii].key[17],profile);
1493 profile=DestroyStringInfo(profile);
1495 if (image_info->verbose)
1496 (void) printf(" Found a generic profile, type %s\n",&text[ii].key[17]);
1501 #if defined(PNG_UNKNOWN_CHUNKS_SUPPORTED)
1502 static int read_vpag_chunk_callback(png_struct *ping, png_unknown_chunkp chunk)
1508 /* The unknown chunk structure contains the chunk data:
1513 Note that libpng has already taken care of the CRC handling.
1517 if (chunk->name[0] != 118 || chunk->name[1] != 112 ||
1518 chunk->name[2] != 65 ||chunk-> name[3] != 103)
1519 return(0); /* Did not recognize */
1521 /* recognized vpAg */
1523 if (chunk->size != 9)
1524 return(-1); /* Error return */
1526 if (chunk->data[8] != 0)
1527 return(0); /* ImageMagick requires pixel units */
1529 image=(Image *) png_get_user_chunk_ptr(ping);
1531 image->page.width=(size_t) ((chunk->data[0] << 24) |
1532 (chunk->data[1] << 16) | (chunk->data[2] << 8) | chunk->data[3]);
1534 image->page.height=(size_t) ((chunk->data[4] << 24) |
1535 (chunk->data[5] << 16) | (chunk->data[6] << 8) | chunk->data[7]);
1537 /* Return one of the following: */
1538 /* return(-n); chunk had an error */
1539 /* return(0); did not recognize */
1540 /* return(n); success */
1548 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1552 % R e a d O n e P N G I m a g e %
1556 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1558 % ReadOnePNGImage() reads a Portable Network Graphics (PNG) image file
1559 % (minus the 8-byte signature) and returns it. It allocates the memory
1560 % necessary for the new Image structure and returns a pointer to the new
1563 % The format of the ReadOnePNGImage method is:
1565 % Image *ReadOnePNGImage(MngInfo *mng_info, const ImageInfo *image_info,
1566 % ExceptionInfo *exception)
1568 % A description of each parameter follows:
1570 % o mng_info: Specifies a pointer to a MngInfo structure.
1572 % o image_info: the image info.
1574 % o exception: return any errors or warnings in this structure.
1577 static Image *ReadOnePNGImage(MngInfo *mng_info,
1578 const ImageInfo *image_info, ExceptionInfo *exception)
1580 /* Read one PNG image */
1591 ping_interlace_method,
1592 ping_compression_method,
1634 register unsigned char
1637 register IndexPacket
1644 register PixelPacket
1651 #if defined(PNG_UNKNOWN_CHUNKS_SUPPORTED)
1652 png_byte unused_chunks[]=
1654 104, 73, 83, 84, (png_byte) '\0', /* hIST */
1655 105, 84, 88, 116, (png_byte) '\0', /* iTXt */
1656 112, 67, 65, 76, (png_byte) '\0', /* pCAL */
1657 115, 67, 65, 76, (png_byte) '\0', /* sCAL */
1658 115, 80, 76, 84, (png_byte) '\0', /* sPLT */
1659 116, 73, 77, 69, (png_byte) '\0', /* tIME */
1663 logging=LogMagickEvent(CoderEvent,GetMagickModule(),
1664 " enter ReadOnePNGImage()");
1666 #if defined(PNG_SETJMP_NOT_THREAD_SAFE)
1667 LockSemaphoreInfo(ping_semaphore);
1670 #if (PNG_LIBPNG_VER < 10200)
1671 if (image_info->verbose)
1672 printf("Your PNG library (libpng-%s) is rather old.\n",
1673 PNG_LIBPNG_VER_STRING);
1676 #if (PNG_LIBPNG_VER >= 10400)
1677 # ifndef PNG_TRANSFORM_GRAY_TO_RGB /* Added at libpng-1.4.0beta67 */
1678 if (image_info->verbose)
1680 printf("Your PNG library (libpng-%s) is an old beta version.\n",
1681 PNG_LIBPNG_VER_STRING);
1682 printf("Please update it.\n");
1688 quantum_info = (QuantumInfo *) NULL;
1689 image=mng_info->image;
1691 if (logging != MagickFalse)
1692 (void)LogMagickEvent(CoderEvent,GetMagickModule(),
1693 " image->matte=%d",(int) image->matte);
1695 /* Set to an out-of-range color unless tRNS chunk is present */
1696 transparent_color.red=65537;
1697 transparent_color.green=65537;
1698 transparent_color.blue=65537;
1699 transparent_color.opacity=65537;
1702 Allocate the PNG structures
1704 #ifdef PNG_USER_MEM_SUPPORTED
1705 ping=png_create_read_struct_2(PNG_LIBPNG_VER_STRING, image,
1706 MagickPNGErrorHandler,MagickPNGWarningHandler, NULL,
1707 (png_malloc_ptr) Magick_png_malloc,(png_free_ptr) Magick_png_free);
1709 ping=png_create_read_struct(PNG_LIBPNG_VER_STRING,image,
1710 MagickPNGErrorHandler,MagickPNGWarningHandler);
1712 if (ping == (png_struct *) NULL)
1713 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1715 ping_info=png_create_info_struct(ping);
1717 if (ping_info == (png_info *) NULL)
1719 png_destroy_read_struct(&ping,(png_info **) NULL,(png_info **) NULL);
1720 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1723 end_info=png_create_info_struct(ping);
1725 if (end_info == (png_info *) NULL)
1727 png_destroy_read_struct(&ping,&ping_info,(png_info **) NULL);
1728 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1731 ping_pixels=(unsigned char *) NULL;
1733 if (setjmp(png_jmpbuf(ping)))
1736 PNG image is corrupt.
1738 png_destroy_read_struct(&ping,&ping_info,&end_info);
1739 #if defined(PNG_SETJMP_NOT_THREAD_SAFE)
1740 UnlockSemaphoreInfo(ping_semaphore);
1742 if (logging != MagickFalse)
1743 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1744 " exit ReadOnePNGImage() with error.");
1746 if (image != (Image *) NULL)
1748 InheritException(exception,&image->exception);
1752 return(GetFirstImageInList(image));
1755 Prepare PNG for reading.
1758 mng_info->image_found++;
1759 png_set_sig_bytes(ping,8);
1761 if (LocaleCompare(image_info->magick,"MNG") == 0)
1763 #if defined(PNG_MNG_FEATURES_SUPPORTED)
1764 (void) png_permit_mng_features(ping,PNG_ALL_MNG_FEATURES);
1765 png_set_read_fn(ping,image,png_get_data);
1767 #if defined(PNG_READ_EMPTY_PLTE_SUPPORTED)
1768 png_permit_empty_plte(ping,MagickTrue);
1769 png_set_read_fn(ping,image,png_get_data);
1771 mng_info->image=image;
1772 mng_info->bytes_in_read_buffer=0;
1773 mng_info->found_empty_plte=MagickFalse;
1774 mng_info->have_saved_bkgd_index=MagickFalse;
1775 png_set_read_fn(ping,mng_info,mng_get_data);
1781 png_set_read_fn(ping,image,png_get_data);
1783 #if defined(PNG_UNKNOWN_CHUNKS_SUPPORTED)
1784 /* Ignore unused chunks and all unknown chunks except for vpAg */
1785 png_set_keep_unknown_chunks(ping, 1, NULL, 0);
1786 png_set_keep_unknown_chunks(ping, 2, mng_vpAg, 1);
1787 png_set_keep_unknown_chunks(ping, 1, unused_chunks,
1788 (int)sizeof(unused_chunks)/5);
1789 /* Callback for other unknown chunks */
1790 png_set_read_user_chunk_fn(ping, image, read_vpag_chunk_callback);
1793 #if (PNG_LIBPNG_VER < 10400)
1794 # if defined(PNG_USE_PNGGCCRD) && defined(PNG_ASSEMBLER_CODE_SUPPORTED) && \
1795 (PNG_LIBPNG_VER >= 10200) && (PNG_LIBPNG_VER < 10220) && defined(__i386__)
1796 /* Disable thread-unsafe features of pnggccrd */
1797 if (png_access_version_number() >= 10200)
1799 png_uint_32 mmx_disable_mask=0;
1800 png_uint_32 asm_flags;
1802 mmx_disable_mask |= ( PNG_ASM_FLAG_MMX_READ_COMBINE_ROW \
1803 | PNG_ASM_FLAG_MMX_READ_FILTER_SUB \
1804 | PNG_ASM_FLAG_MMX_READ_FILTER_AVG \
1805 | PNG_ASM_FLAG_MMX_READ_FILTER_PAETH );
1806 asm_flags=png_get_asm_flags(ping);
1807 png_set_asm_flags(ping, asm_flags & ~mmx_disable_mask);
1812 png_read_info(ping,ping_info);
1814 png_get_IHDR(ping,ping_info,&ping_width,&ping_height,
1815 &ping_bit_depth,&ping_color_type,
1816 &ping_interlace_method,&ping_compression_method,
1817 &ping_filter_method);
1819 (void) png_get_tRNS(ping, ping_info, &ping_trans_alpha, &ping_num_trans,
1822 (void) png_get_bKGD(ping, ping_info, &ping_background);
1824 if (ping_bit_depth < 8)
1826 if (((int) ping_color_type == PNG_COLOR_TYPE_PALETTE))
1828 png_set_packing(ping);
1833 image->depth=ping_bit_depth;
1834 image->depth=GetImageQuantumDepth(image,MagickFalse);
1835 image->interlace=ping_interlace_method != 0 ? PNGInterlace : NoInterlace;
1836 if (logging != MagickFalse)
1838 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1839 " PNG width: %.20g, height: %.20g",
1840 (double) ping_width, (double) ping_height);
1842 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1843 " PNG color_type: %d, bit_depth: %d",
1844 ping_color_type, ping_bit_depth);
1846 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1847 " PNG compression_method: %d",
1848 ping_compression_method);
1850 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1851 " PNG interlace_method: %d, filter_method: %d",
1852 ping_interlace_method,ping_filter_method);
1855 #ifdef PNG_READ_iCCP_SUPPORTED
1856 if (png_get_valid(ping,ping_info,PNG_INFO_iCCP))
1861 #if (PNG_LIBPNG_VER < 10500)
1875 (void) png_get_iCCP(ping,ping_info,&name,(int *) &compression,&info,
1878 if (profile_length != 0)
1883 if (logging != MagickFalse)
1884 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1885 " Reading PNG iCCP chunk.");
1886 profile=AcquireStringInfo(profile_length);
1887 SetStringInfoDatum(profile,(const unsigned char *) info);
1888 (void) SetImageProfile(image,"icc",profile);
1889 profile=DestroyStringInfo(profile);
1893 #if defined(PNG_READ_sRGB_SUPPORTED)
1898 if (mng_info->have_global_srgb)
1899 image->rendering_intent=Magick_RenderingIntent_from_PNG_RenderingIntent
1900 (mng_info->global_srgb_intent);
1902 if (png_get_sRGB(ping,ping_info,&intent))
1904 image->rendering_intent=Magick_RenderingIntent_from_PNG_RenderingIntent
1907 if (logging != MagickFalse)
1908 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1909 " Reading PNG sRGB chunk: rendering_intent: %d",intent);
1917 if (!png_get_gAMA(ping,ping_info,&file_gamma))
1918 if (mng_info->have_global_gama)
1919 png_set_gAMA(ping,ping_info,mng_info->global_gamma);
1921 if (png_get_gAMA(ping,ping_info,&file_gamma))
1923 image->gamma=(float) file_gamma;
1924 if (logging != MagickFalse)
1925 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1926 " Reading PNG gAMA chunk: gamma: %f",file_gamma);
1929 if (!png_get_valid(ping,ping_info,PNG_INFO_cHRM))
1931 if (mng_info->have_global_chrm != MagickFalse)
1933 (void) png_set_cHRM(ping,ping_info,
1934 mng_info->global_chrm.white_point.x,
1935 mng_info->global_chrm.white_point.y,
1936 mng_info->global_chrm.red_primary.x,
1937 mng_info->global_chrm.red_primary.y,
1938 mng_info->global_chrm.green_primary.x,
1939 mng_info->global_chrm.green_primary.y,
1940 mng_info->global_chrm.blue_primary.x,
1941 mng_info->global_chrm.blue_primary.y);
1945 if (png_get_valid(ping,ping_info,PNG_INFO_cHRM))
1947 (void) png_get_cHRM(ping,ping_info,
1948 &image->chromaticity.white_point.x,
1949 &image->chromaticity.white_point.y,
1950 &image->chromaticity.red_primary.x,
1951 &image->chromaticity.red_primary.y,
1952 &image->chromaticity.green_primary.x,
1953 &image->chromaticity.green_primary.y,
1954 &image->chromaticity.blue_primary.x,
1955 &image->chromaticity.blue_primary.y);
1957 if (logging != MagickFalse)
1958 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1959 " Reading PNG cHRM chunk.");
1962 if (image->rendering_intent != UndefinedIntent)
1964 png_set_sRGB(ping,ping_info,
1965 Magick_RenderingIntent_to_PNG_RenderingIntent
1966 (image->rendering_intent));
1967 png_set_gAMA(ping,ping_info,0.45455f);
1968 png_set_cHRM(ping,ping_info,
1969 0.6400f, 0.3300f, 0.3000f, 0.6000f,
1970 0.1500f, 0.0600f, 0.3127f, 0.3290f);
1972 #if defined(PNG_oFFs_SUPPORTED)
1973 if (png_get_valid(ping,ping_info,PNG_INFO_oFFs))
1975 image->page.x=png_get_x_offset_pixels(ping, ping_info);
1976 image->page.y=png_get_y_offset_pixels(ping, ping_info);
1978 if (logging != MagickFalse)
1979 if (image->page.x || image->page.y)
1980 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1981 " Reading PNG oFFs chunk: x: %.20g, y: %.20g.",(double)
1982 image->page.x,(double) image->page.y);
1985 #if defined(PNG_pHYs_SUPPORTED)
1986 if (!png_get_valid(ping,ping_info,PNG_INFO_pHYs))
1988 if (mng_info->have_global_phys)
1990 png_set_pHYs(ping,ping_info,
1991 mng_info->global_x_pixels_per_unit,
1992 mng_info->global_y_pixels_per_unit,
1993 mng_info->global_phys_unit_type);
1997 if (png_get_valid(ping,ping_info,PNG_INFO_pHYs))
2007 Set image resolution.
2009 (void) png_get_pHYs(ping,ping_info,&x_resolution,&y_resolution,
2011 image->x_resolution=(double) x_resolution;
2012 image->y_resolution=(double) y_resolution;
2014 if (unit_type == PNG_RESOLUTION_METER)
2016 image->units=PixelsPerCentimeterResolution;
2017 image->x_resolution=(double) x_resolution/100.0;
2018 image->y_resolution=(double) y_resolution/100.0;
2021 if (logging != MagickFalse)
2022 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2023 " Reading PNG pHYs chunk: xres: %.20g, yres: %.20g, units: %d.",
2024 (double) x_resolution,(double) y_resolution,unit_type);
2027 if (png_get_valid(ping,ping_info,PNG_INFO_PLTE))
2035 (void) png_get_PLTE(ping,ping_info,&palette,&number_colors);
2037 if ((number_colors == 0) &&
2038 ((int) ping_color_type == PNG_COLOR_TYPE_PALETTE))
2040 if (mng_info->global_plte_length)
2042 png_set_PLTE(ping,ping_info,mng_info->global_plte,
2043 (int) mng_info->global_plte_length);
2045 if (!png_get_valid(ping,ping_info,PNG_INFO_tRNS))
2046 if (mng_info->global_trns_length)
2048 if (mng_info->global_trns_length >
2049 mng_info->global_plte_length)
2050 (void) ThrowMagickException(&image->exception,
2051 GetMagickModule(),CoderError,
2052 "global tRNS has more entries than global PLTE",
2053 "`%s'",image_info->filename);
2054 png_set_tRNS(ping,ping_info,mng_info->global_trns,
2055 (int) mng_info->global_trns_length,NULL);
2057 #if defined(PNG_READ_bKGD_SUPPORTED)
2059 #ifndef PNG_READ_EMPTY_PLTE_SUPPORTED
2060 mng_info->have_saved_bkgd_index ||
2062 png_get_valid(ping,ping_info,PNG_INFO_bKGD))
2067 #ifndef PNG_READ_EMPTY_PLTE_SUPPORTED
2068 if (mng_info->have_saved_bkgd_index)
2069 background.index=mng_info->saved_bkgd_index;
2071 if (png_get_valid(ping, ping_info, PNG_INFO_bKGD))
2072 background.index=ping_background->index;
2074 background.red=(png_uint_16)
2075 mng_info->global_plte[background.index].red;
2077 background.green=(png_uint_16)
2078 mng_info->global_plte[background.index].green;
2080 background.blue=(png_uint_16)
2081 mng_info->global_plte[background.index].blue;
2083 png_set_bKGD(ping,ping_info,&background);
2088 (void) ThrowMagickException(&image->exception,GetMagickModule(),
2089 CoderError,"No global PLTE in file","`%s'",
2090 image_info->filename);
2094 #if defined(PNG_READ_bKGD_SUPPORTED)
2095 if (mng_info->have_global_bkgd &&
2096 (!png_get_valid(ping,ping_info,PNG_INFO_bKGD)))
2097 image->background_color=mng_info->mng_global_bkgd;
2099 if (png_get_valid(ping,ping_info,PNG_INFO_bKGD))
2102 Set image background color.
2104 if (logging != MagickFalse)
2105 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2106 " Reading PNG bKGD chunk.");
2108 if (ping_bit_depth == MAGICKCORE_QUANTUM_DEPTH)
2110 image->background_color.red=ping_background->red;
2111 image->background_color.green=ping_background->green;
2112 image->background_color.blue=ping_background->blue;
2115 else /* Scale background components to 16-bit */
2120 if (logging != MagickFalse)
2121 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2122 " raw ping_background=(%d,%d,%d).",ping_background->red,
2123 ping_background->green,ping_background->blue);
2127 if (ping_bit_depth == 1)
2130 else if (ping_bit_depth == 2)
2133 else if (ping_bit_depth == 4)
2136 if (ping_bit_depth <= 8)
2139 ping_background->red *= bkgd_scale;
2140 ping_background->green *= bkgd_scale;
2141 ping_background->blue *= bkgd_scale;
2143 if (logging != MagickFalse)
2145 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2146 " bkgd_scale=%d.",bkgd_scale);
2148 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2149 " ping_background=(%d,%d,%d).",ping_background->red,
2150 ping_background->green,ping_background->blue);
2153 image->background_color.red=
2154 ScaleShortToQuantum(ping_background->red);
2156 image->background_color.green=
2157 ScaleShortToQuantum(ping_background->green);
2159 image->background_color.blue=
2160 ScaleShortToQuantum(ping_background->blue);
2162 image->background_color.opacity=OpaqueOpacity;
2164 if (logging != MagickFalse)
2165 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2166 " image->background_color=(%.20g,%.20g,%.20g).",
2167 (double) image->background_color.red,
2168 (double) image->background_color.green,
2169 (double) image->background_color.blue);
2174 if (png_get_valid(ping,ping_info,PNG_INFO_tRNS))
2177 Image has a tRNS chunk.
2185 if (logging != MagickFalse)
2186 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2187 " Reading PNG tRNS chunk.");
2189 max_sample = (int) ((one << ping_bit_depth) - 1);
2191 if ((ping_color_type == PNG_COLOR_TYPE_GRAY &&
2192 (int)ping_trans_color->gray > max_sample) ||
2193 (ping_color_type == PNG_COLOR_TYPE_RGB &&
2194 ((int)ping_trans_color->red > max_sample ||
2195 (int)ping_trans_color->green > max_sample ||
2196 (int)ping_trans_color->blue > max_sample)))
2198 if (logging != MagickFalse)
2199 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2200 " Ignoring PNG tRNS chunk with out-of-range sample.");
2201 png_free_data(ping, ping_info, PNG_FREE_TRNS, 0);
2202 png_set_invalid(ping,ping_info,PNG_INFO_tRNS);
2203 image->matte=MagickFalse;
2210 scale_to_short = 65535L/((1UL << ping_bit_depth)-1);
2212 /* Scale transparent_color to short */
2213 transparent_color.red= scale_to_short*ping_trans_color->red;
2214 transparent_color.green= scale_to_short*ping_trans_color->green;
2215 transparent_color.blue= scale_to_short*ping_trans_color->blue;
2216 transparent_color.opacity= scale_to_short*ping_trans_color->gray;
2218 if (ping_color_type == PNG_COLOR_TYPE_GRAY)
2220 if (logging != MagickFalse)
2222 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2223 " Raw tRNS graylevel is %d.",ping_trans_color->gray);
2225 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2226 " scaled graylevel is %d.",transparent_color.opacity);
2228 transparent_color.red=transparent_color.opacity;
2229 transparent_color.green=transparent_color.opacity;
2230 transparent_color.blue=transparent_color.opacity;
2234 #if defined(PNG_READ_sBIT_SUPPORTED)
2235 if (mng_info->have_global_sbit)
2237 if (!png_get_valid(ping,ping_info,PNG_INFO_sBIT))
2238 png_set_sBIT(ping,ping_info,&mng_info->global_sbit);
2241 num_passes=png_set_interlace_handling(ping);
2243 png_read_update_info(ping,ping_info);
2245 ping_rowbytes=png_get_rowbytes(ping,ping_info);
2248 Initialize image structure.
2250 mng_info->image_box.left=0;
2251 mng_info->image_box.right=(ssize_t) ping_width;
2252 mng_info->image_box.top=0;
2253 mng_info->image_box.bottom=(ssize_t) ping_height;
2254 if (mng_info->mng_type == 0)
2256 mng_info->mng_width=ping_width;
2257 mng_info->mng_height=ping_height;
2258 mng_info->frame=mng_info->image_box;
2259 mng_info->clip=mng_info->image_box;
2264 image->page.y=mng_info->y_off[mng_info->object_id];
2267 image->compression=ZipCompression;
2268 image->columns=ping_width;
2269 image->rows=ping_height;
2270 if (((int) ping_color_type == PNG_COLOR_TYPE_PALETTE) ||
2271 ((int) ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA) ||
2272 ((int) ping_color_type == PNG_COLOR_TYPE_GRAY))
2277 image->storage_class=PseudoClass;
2279 image->colors=one << ping_bit_depth;
2280 #if (MAGICKCORE_QUANTUM_DEPTH == 8)
2281 if (image->colors > 256)
2284 if (image->colors > 65536L)
2285 image->colors=65536L;
2287 if ((int) ping_color_type == PNG_COLOR_TYPE_PALETTE)
2295 (void) png_get_PLTE(ping,ping_info,&palette,&number_colors);
2296 image->colors=(size_t) number_colors;
2298 if (logging != MagickFalse)
2299 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2300 " Reading PNG PLTE chunk: number_colors: %d.",number_colors);
2304 if (image->storage_class == PseudoClass)
2307 Initialize image colormap.
2309 if (AcquireImageColormap(image,image->colors) == MagickFalse)
2310 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
2312 if ((int) ping_color_type == PNG_COLOR_TYPE_PALETTE)
2320 (void) png_get_PLTE(ping,ping_info,&palette,&number_colors);
2322 for (i=0; i < (ssize_t) image->colors; i++)
2324 image->colormap[i].red=ScaleCharToQuantum(palette[i].red);
2325 image->colormap[i].green=ScaleCharToQuantum(palette[i].green);
2326 image->colormap[i].blue=ScaleCharToQuantum(palette[i].blue);
2335 scale=(QuantumRange/((1UL << ping_bit_depth)-1));
2340 for (i=0; i < (ssize_t) image->colors; i++)
2342 image->colormap[i].red=(Quantum) (i*scale);
2343 image->colormap[i].green=(Quantum) (i*scale);
2344 image->colormap[i].blue=(Quantum) (i*scale);
2349 Read image scanlines.
2351 if (image->delay != 0)
2352 mng_info->scenes_found++;
2354 if ((mng_info->mng_type == 0 && (image->ping != MagickFalse)) || (
2355 (image_info->number_scenes != 0) && (mng_info->scenes_found > (ssize_t)
2356 (image_info->first_scene+image_info->number_scenes))))
2358 if (logging != MagickFalse)
2359 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2360 " Skipping PNG image data for scene %.20g",(double)
2361 mng_info->scenes_found-1);
2362 png_destroy_read_struct(&ping,&ping_info,&end_info);
2363 #if defined(PNG_SETJMP_NOT_THREAD_SAFE)
2364 UnlockSemaphoreInfo(ping_semaphore);
2366 if (logging != MagickFalse)
2367 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2368 " exit ReadOnePNGImage().");
2373 if (logging != MagickFalse)
2374 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2375 " Reading PNG IDAT chunk(s)");
2378 ping_pixels=(unsigned char *) AcquireQuantumMemory(image->rows,
2379 ping_rowbytes*sizeof(*ping_pixels));
2382 ping_pixels=(unsigned char *) AcquireQuantumMemory(ping_rowbytes,
2383 sizeof(*ping_pixels));
2385 if (ping_pixels == (unsigned char *) NULL)
2386 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
2388 if (logging != MagickFalse)
2389 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2390 " Converting PNG pixels to pixel packets");
2392 Convert PNG pixels to pixel packets.
2394 if (setjmp(png_jmpbuf(ping)))
2397 PNG image is corrupt.
2399 png_destroy_read_struct(&ping,&ping_info,&end_info);
2400 #if defined(PNG_SETJMP_NOT_THREAD_SAFE)
2401 UnlockSemaphoreInfo(ping_semaphore);
2403 if (quantum_info != (QuantumInfo *) NULL)
2404 quantum_info = DestroyQuantumInfo(quantum_info);
2406 if (ping_pixels != (unsigned char *) NULL)
2407 ping_pixels=(unsigned char *) RelinquishMagickMemory(ping_pixels);
2409 if (logging != MagickFalse)
2410 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2411 " exit ReadOnePNGImage() with error.");
2413 if (image != (Image *) NULL)
2415 InheritException(exception,&image->exception);
2419 return(GetFirstImageInList(image));
2422 quantum_info=AcquireQuantumInfo(image_info,image);
2424 if (quantum_info == (QuantumInfo *) NULL)
2425 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
2430 found_transparent_pixel;
2432 found_transparent_pixel=MagickFalse;
2434 if (image->storage_class == DirectClass)
2436 for (pass=0; pass < num_passes; pass++)
2439 Convert image to DirectClass pixel packets.
2441 #if (MAGICKCORE_QUANTUM_DEPTH == 8)
2445 depth=(ssize_t) ping_bit_depth;
2447 image->matte=(((int) ping_color_type == PNG_COLOR_TYPE_RGB_ALPHA) ||
2448 ((int) ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA) ||
2449 (png_get_valid(ping,ping_info,PNG_INFO_tRNS))) ?
2450 MagickTrue : MagickFalse;
2452 for (y=0; y < (ssize_t) image->rows; y++)
2455 row_offset=ping_rowbytes*y;
2460 png_read_row(ping,ping_pixels+row_offset,NULL);
2461 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
2463 if (q == (PixelPacket *) NULL)
2466 #if (0 && (MAGICKCORE_QUANTUM_DEPTH == 8) && !defined(MAGICKCORE_HDRI_SUPPORT))
2467 /* code deleted from version 6.6.6-8 */
2468 #else /* (MAGICKCORE_QUANTUM_DEPTH != 8) */
2470 if ((int) ping_color_type == PNG_COLOR_TYPE_GRAY)
2471 (void) ImportQuantumPixels(image,(CacheView *) NULL,quantum_info,
2472 GrayQuantum,ping_pixels+row_offset,exception);
2474 else if ((int) ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
2475 (void) ImportQuantumPixels(image,(CacheView *) NULL,quantum_info,
2476 GrayAlphaQuantum,ping_pixels+row_offset,exception);
2478 else if ((int) ping_color_type == PNG_COLOR_TYPE_RGB_ALPHA)
2479 (void) ImportQuantumPixels(image,(CacheView *) NULL,quantum_info,
2480 RGBAQuantum,ping_pixels+row_offset,exception);
2482 else if ((int) ping_color_type == PNG_COLOR_TYPE_PALETTE)
2483 (void) ImportQuantumPixels(image,(CacheView *) NULL,quantum_info,
2484 IndexQuantum,ping_pixels+row_offset,exception);
2486 else /* ping_color_type == PNG_COLOR_TYPE_RGB */
2487 (void) ImportQuantumPixels(image,(CacheView *) NULL,quantum_info,
2488 RGBQuantum,ping_pixels+row_offset,exception);
2490 if (found_transparent_pixel == MagickFalse)
2492 /* Is there a transparent pixel in the row? */
2493 if (y== 0 && logging != MagickFalse)
2494 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2495 " Looking for cheap transparent pixel");
2497 for (x=(ssize_t) image->columns-1; x >= 0; x--)
2499 if ((ping_color_type == PNG_COLOR_TYPE_RGBA ||
2500 ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA) &&
2501 (q->opacity != OpaqueOpacity))
2503 if (logging != MagickFalse)
2504 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2507 found_transparent_pixel = MagickTrue;
2510 if ((ping_color_type == PNG_COLOR_TYPE_RGB ||
2511 ping_color_type == PNG_COLOR_TYPE_GRAY) &&
2512 (ScaleQuantumToShort(q->red) == transparent_color.red &&
2513 ScaleQuantumToShort(q->green) == transparent_color.green &&
2514 ScaleQuantumToShort(q->blue) == transparent_color.blue))
2516 if (logging != MagickFalse)
2517 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2519 found_transparent_pixel = MagickTrue;
2526 if ((image->previous == (Image *) NULL) && (num_passes == 1))
2528 status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
2531 if (status == MagickFalse)
2534 if (SyncAuthenticPixels(image,exception) == MagickFalse)
2538 if ((image->previous == (Image *) NULL) && (num_passes != 1))
2540 status=SetImageProgress(image,LoadImageTag,pass,num_passes);
2541 if (status == MagickFalse)
2547 else /* image->storage_class != DirectClass */
2549 for (pass=0; pass < num_passes; pass++)
2558 Convert grayscale image to PseudoClass pixel packets.
2560 image->matte=ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA ?
2561 MagickTrue : MagickFalse;
2563 quantum_scanline=(Quantum *) AcquireQuantumMemory(image->columns,
2564 (image->matte ? 2 : 1)*sizeof(*quantum_scanline));
2566 if (quantum_scanline == (Quantum *) NULL)
2567 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
2569 for (y=0; y < (ssize_t) image->rows; y++)
2572 row_offset=ping_rowbytes*y;
2577 png_read_row(ping,ping_pixels+row_offset,NULL);
2578 q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
2580 if (q == (PixelPacket *) NULL)
2583 indexes=GetAuthenticIndexQueue(image);
2584 p=ping_pixels+row_offset;
2587 switch (ping_bit_depth)
2594 for (x=(ssize_t) image->columns-7; x > 0; x-=8)
2596 for (bit=7; bit >= 0; bit--)
2597 *r++=(Quantum) ((*p) & (0x01 << bit) ? 0x01 : 0x00);
2601 if ((image->columns % 8) != 0)
2603 for (bit=7; bit >= (ssize_t) (8-(image->columns % 8)); bit--)
2604 *r++=(Quantum) ((*p) & (0x01 << bit) ? 0x01 : 0x00);
2612 for (x=(ssize_t) image->columns-3; x > 0; x-=4)
2614 *r++=(*p >> 6) & 0x03;
2615 *r++=(*p >> 4) & 0x03;
2616 *r++=(*p >> 2) & 0x03;
2620 if ((image->columns % 4) != 0)
2622 for (i=3; i >= (ssize_t) (4-(image->columns % 4)); i--)
2623 *r++=(Quantum) ((*p >> (i*2)) & 0x03);
2631 for (x=(ssize_t) image->columns-1; x > 0; x-=2)
2633 *r++=(*p >> 4) & 0x0f;
2637 if ((image->columns % 2) != 0)
2638 *r++=(*p++ >> 4) & 0x0f;
2645 if (ping_color_type == 4)
2646 for (x=(ssize_t) image->columns-1; x >= 0; x--)
2649 /* In image.h, OpaqueOpacity is 0
2650 * TransparentOpacity is QuantumRange
2651 * In a PNG datastream, Opaque is QuantumRange
2652 * and Transparent is 0.
2654 q->opacity=ScaleCharToQuantum((unsigned char) (255-(*p++)));
2655 if (q->opacity != OpaqueOpacity)
2656 found_transparent_pixel = MagickTrue;
2661 for (x=(ssize_t) image->columns-1; x >= 0; x--)
2669 for (x=(ssize_t) image->columns-1; x >= 0; x--)
2671 #if (MAGICKCORE_QUANTUM_DEPTH == 16)
2675 if (image->colors > 256)
2683 *r=(Quantum) quantum;
2686 if (ping_color_type == 4)
2688 quantum=((*p++) << 8);
2690 q->opacity=(Quantum) (QuantumRange-quantum);
2691 if (q->opacity != OpaqueOpacity)
2692 found_transparent_pixel = MagickTrue;
2696 #if (MAGICKCORE_QUANTUM_DEPTH == 32)
2700 if (image->colors > 256)
2711 if (ping_color_type == 4)
2713 q->opacity=(*p << 8) | *(p+1);
2715 q->opacity=(Quantum) GetAlphaPixelComponent(q);
2716 if (q->opacity != OpaqueOpacity)
2717 found_transparent_pixel = MagickTrue;
2722 #else /* MAGICKCORE_QUANTUM_DEPTH == 8 */
2724 p++; /* strip low byte */
2726 if (ping_color_type == 4)
2728 q->opacity=(Quantum) (QuantumRange-(*p++));
2729 if (q->opacity != OpaqueOpacity)
2730 found_transparent_pixel = MagickTrue;
2745 Transfer image scanline.
2749 for (x=0; x < (ssize_t) image->columns; x++)
2750 indexes[x]=(IndexPacket) (*r++);
2752 if (SyncAuthenticPixels(image,exception) == MagickFalse)
2755 if ((image->previous == (Image *) NULL) && (num_passes == 1))
2757 status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
2760 if (status == MagickFalse)
2765 if ((image->previous == (Image *) NULL) && (num_passes != 1))
2767 status=SetImageProgress(image,LoadImageTag,pass,num_passes);
2769 if (status == MagickFalse)
2773 quantum_scanline=(Quantum *) RelinquishMagickMemory(quantum_scanline);
2776 image->matte=found_transparent_pixel;
2778 if (logging != MagickFalse)
2780 if (found_transparent_pixel != MagickFalse)
2781 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2782 " Found transparent pixel");
2785 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2786 " No transparent pixel was found");
2788 ping_color_type&=0x03;
2793 if (quantum_info != (QuantumInfo *) NULL)
2794 quantum_info=DestroyQuantumInfo(quantum_info);
2796 if (image->storage_class == PseudoClass)
2802 image->matte=MagickFalse;
2803 (void) SyncImage(image);
2807 png_read_end(ping,ping_info);
2809 if (image_info->number_scenes != 0 && mng_info->scenes_found-1 <
2810 (ssize_t) image_info->first_scene && image->delay != 0)
2812 png_destroy_read_struct(&ping,&ping_info,&end_info);
2813 ping_pixels=(unsigned char *) RelinquishMagickMemory(ping_pixels);
2815 (void) SetImageBackgroundColor(image);
2816 #if defined(PNG_SETJMP_NOT_THREAD_SAFE)
2817 UnlockSemaphoreInfo(ping_semaphore);
2819 if (logging != MagickFalse)
2820 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2821 " exit ReadOnePNGImage() early.");
2825 if (png_get_valid(ping,ping_info,PNG_INFO_tRNS))
2831 Image has a transparent background.
2833 storage_class=image->storage_class;
2834 image->matte=MagickTrue;
2836 /* Balfour fix from imagemagick discourse server, 5 Feb 2010 */
2838 if (storage_class == PseudoClass)
2840 if ((int) ping_color_type == PNG_COLOR_TYPE_PALETTE)
2842 for (x=0; x < ping_num_trans; x++)
2844 image->colormap[x].opacity =
2845 ScaleCharToQuantum((unsigned char)(255-ping_trans_alpha[x]));
2849 else if (ping_color_type == PNG_COLOR_TYPE_GRAY)
2851 for (x=0; x < (int) image->colors; x++)
2853 if (ScaleQuantumToShort(image->colormap[x].red) ==
2854 transparent_color.opacity)
2856 image->colormap[x].opacity = (Quantum) TransparentOpacity;
2860 (void) SyncImage(image);
2863 #if 1 /* Should have already been done above, but glennrp problem P10
2868 for (y=0; y < (ssize_t) image->rows; y++)
2870 image->storage_class=storage_class;
2871 q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
2873 if (q == (PixelPacket *) NULL)
2876 indexes=GetAuthenticIndexQueue(image);
2878 /* Caution: on a Q8 build, this does not distinguish between
2879 * 16-bit colors that differ only in the low byte
2881 for (x=(ssize_t) image->columns-1; x >= 0; x--)
2883 if (ScaleQuantumToShort(q->red) == transparent_color.red &&
2884 ScaleQuantumToShort(q->green) == transparent_color.green &&
2885 ScaleQuantumToShort(q->blue) == transparent_color.blue)
2887 q->opacity=(Quantum) TransparentOpacity;
2890 #if 0 /* I have not found a case where this is needed. */
2893 q->opacity=(Quantum) OpaqueOpacity;
2900 if (SyncAuthenticPixels(image,exception) == MagickFalse)
2906 image->storage_class=DirectClass;
2909 if ((ping_color_type == PNG_COLOR_TYPE_GRAY) ||
2910 (ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA))
2911 image->colorspace=GRAYColorspace;
2913 if (png_get_text(ping,ping_info,&text,&num_text) != 0)
2914 for (i=0; i < (ssize_t) num_text; i++)
2916 /* Check for a profile */
2918 if (logging != MagickFalse)
2919 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2920 " Reading PNG text chunk");
2922 if (memcmp(text[i].key, "Raw profile type ",17) == 0)
2923 (void) Magick_png_read_raw_profile(image,image_info,text,(int) i);
2930 length=text[i].text_length;
2931 value=(char *) AcquireQuantumMemory(length+MaxTextExtent,
2933 if (value == (char *) NULL)
2935 (void) ThrowMagickException(&image->exception,GetMagickModule(),
2936 ResourceLimitError,"MemoryAllocationFailed","`%s'",
2941 (void) ConcatenateMagickString(value,text[i].text,length+2);
2942 (void) SetImageProperty(image,text[i].key,value);
2944 if (logging != MagickFalse)
2945 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2946 " Keyword: %s",text[i].key);
2948 value=DestroyString(value);
2952 #ifdef MNG_OBJECT_BUFFERS
2954 Store the object if necessary.
2956 if (object_id && !mng_info->frozen[object_id])
2958 if (mng_info->ob[object_id] == (MngBuffer *) NULL)
2961 create a new object buffer.
2963 mng_info->ob[object_id]=(MngBuffer *)
2964 AcquireMagickMemory(sizeof(MngBuffer));
2966 if (mng_info->ob[object_id] != (MngBuffer *) NULL)
2968 mng_info->ob[object_id]->image=(Image *) NULL;
2969 mng_info->ob[object_id]->reference_count=1;
2973 if ((mng_info->ob[object_id] == (MngBuffer *) NULL) ||
2974 mng_info->ob[object_id]->frozen)
2976 if (mng_info->ob[object_id] == (MngBuffer *) NULL)
2977 (void) ThrowMagickException(&image->exception,GetMagickModule(),
2978 ResourceLimitError,"MemoryAllocationFailed","`%s'",
2981 if (mng_info->ob[object_id]->frozen)
2982 (void) ThrowMagickException(&image->exception,GetMagickModule(),
2983 ResourceLimitError,"Cannot overwrite frozen MNG object buffer",
2984 "`%s'",image->filename);
2990 if (mng_info->ob[object_id]->image != (Image *) NULL)
2991 mng_info->ob[object_id]->image=DestroyImage
2992 (mng_info->ob[object_id]->image);
2994 mng_info->ob[object_id]->image=CloneImage(image,0,0,MagickTrue,
2997 if (mng_info->ob[object_id]->image != (Image *) NULL)
2998 mng_info->ob[object_id]->image->file=(FILE *) NULL;
3001 (void) ThrowMagickException(&image->exception,GetMagickModule(),
3002 ResourceLimitError,"Cloning image for object buffer failed",
3003 "`%s'",image->filename);
3005 if (ping_width > 250000L || ping_height > 250000L)
3006 png_error(ping,"PNG Image dimensions are too large.");
3008 mng_info->ob[object_id]->width=ping_width;
3009 mng_info->ob[object_id]->height=ping_height;
3010 mng_info->ob[object_id]->color_type=ping_color_type;
3011 mng_info->ob[object_id]->sample_depth=ping_bit_depth;
3012 mng_info->ob[object_id]->interlace_method=ping_interlace_method;
3013 mng_info->ob[object_id]->compression_method=
3014 ping_compression_method;
3015 mng_info->ob[object_id]->filter_method=ping_filter_method;
3017 if (png_get_valid(ping,ping_info,PNG_INFO_PLTE))
3026 Copy the PLTE to the object buffer.
3028 png_get_PLTE(ping,ping_info,&plte,&number_colors);
3029 mng_info->ob[object_id]->plte_length=number_colors;
3031 for (i=0; i < number_colors; i++)
3033 mng_info->ob[object_id]->plte[i]=plte[i];
3038 mng_info->ob[object_id]->plte_length=0;
3043 Relinquish resources.
3045 png_destroy_read_struct(&ping,&ping_info,&end_info);
3047 ping_pixels=(unsigned char *) RelinquishMagickMemory(ping_pixels);
3048 #if defined(PNG_SETJMP_NOT_THREAD_SAFE)
3049 UnlockSemaphoreInfo(ping_semaphore);
3052 if (logging != MagickFalse)
3053 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3054 " exit ReadOnePNGImage()");
3058 /* end of reading one PNG image */
3061 static Image *ReadPNGImage(const ImageInfo *image_info,ExceptionInfo *exception)
3076 magic_number[MaxTextExtent];
3084 assert(image_info != (const ImageInfo *) NULL);
3085 assert(image_info->signature == MagickSignature);
3087 if (image_info->debug != MagickFalse)
3088 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
3089 image_info->filename);
3091 assert(exception != (ExceptionInfo *) NULL);
3092 assert(exception->signature == MagickSignature);
3093 logging=LogMagickEvent(CoderEvent,GetMagickModule(),"enter ReadPNGImage()");
3094 image=AcquireImage(image_info);
3095 mng_info=(MngInfo *) NULL;
3096 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
3098 if (status == MagickFalse)
3099 ThrowReaderException(FileOpenError,"UnableToOpenFile");
3102 Verify PNG signature.
3104 count=ReadBlob(image,8,(unsigned char *) magic_number);
3106 if (memcmp(magic_number,"\211PNG\r\n\032\n",8) != 0)
3107 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
3110 Allocate a MngInfo structure.
3112 have_mng_structure=MagickFalse;
3113 mng_info=(MngInfo *) AcquireMagickMemory(sizeof(MngInfo));
3115 if (mng_info == (MngInfo *) NULL)
3116 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
3119 Initialize members of the MngInfo structure.
3121 (void) ResetMagickMemory(mng_info,0,sizeof(MngInfo));
3122 mng_info->image=image;
3123 have_mng_structure=MagickTrue;
3126 image=ReadOnePNGImage(mng_info,image_info,exception);
3127 MngInfoFreeStruct(mng_info,&have_mng_structure);
3129 if (image == (Image *) NULL)
3131 if (previous != (Image *) NULL)
3133 if (previous->signature != MagickSignature)
3134 ThrowReaderException(CorruptImageError,"CorruptImage");
3136 (void) CloseBlob(previous);
3137 (void) DestroyImageList(previous);
3140 if (logging != MagickFalse)
3141 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3142 "exit ReadPNGImage() with error");
3144 return((Image *) NULL);
3147 (void) CloseBlob(image);
3149 if ((image->columns == 0) || (image->rows == 0))
3151 if (logging != MagickFalse)
3152 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3153 "exit ReadPNGImage() with error.");
3155 ThrowReaderException(CorruptImageError,"CorruptImage");
3158 if (LocaleCompare(image_info->magick,"PNG8") == 0)
3160 (void) SetImageType(image,PaletteType);
3162 if (image->matte != MagickFalse)
3164 /* To do: Reduce to binary transparency */
3168 if (LocaleCompare(image_info->magick,"PNG24") == 0)
3170 (void) SetImageType(image,TrueColorType);
3171 image->matte=MagickFalse;
3174 if (LocaleCompare(image_info->magick,"PNG32") == 0)
3175 (void) SetImageType(image,TrueColorMatteType);
3177 if (logging != MagickFalse)
3178 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"exit ReadPNGImage()");
3185 #if defined(JNG_SUPPORTED)
3187 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3191 % R e a d O n e J N G I m a g e %
3195 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3197 % ReadOneJNGImage() reads a JPEG Network Graphics (JNG) image file
3198 % (minus the 8-byte signature) and returns it. It allocates the memory
3199 % necessary for the new Image structure and returns a pointer to the new
3202 % JNG support written by Glenn Randers-Pehrson, glennrp@image...
3204 % The format of the ReadOneJNGImage method is:
3206 % Image *ReadOneJNGImage(MngInfo *mng_info, const ImageInfo *image_info,
3207 % ExceptionInfo *exception)
3209 % A description of each parameter follows:
3211 % o mng_info: Specifies a pointer to a MngInfo structure.
3213 % o image_info: the image info.
3215 % o exception: return any errors or warnings in this structure.
3218 static Image *ReadOneJNGImage(MngInfo *mng_info,
3219 const ImageInfo *image_info, ExceptionInfo *exception)
3246 jng_image_sample_depth,
3247 jng_image_compression_method,
3248 jng_image_interlace_method,
3249 jng_alpha_sample_depth,
3250 jng_alpha_compression_method,
3251 jng_alpha_filter_method,
3252 jng_alpha_interlace_method;
3254 register const PixelPacket
3261 register PixelPacket
3264 register unsigned char
3275 jng_alpha_compression_method=0;
3276 jng_alpha_sample_depth=8;
3280 alpha_image=(Image *) NULL;
3281 color_image=(Image *) NULL;
3282 alpha_image_info=(ImageInfo *) NULL;
3283 color_image_info=(ImageInfo *) NULL;
3285 logging=LogMagickEvent(CoderEvent,GetMagickModule(),
3286 " enter ReadOneJNGImage()");
3288 image=mng_info->image;
3290 if (GetAuthenticPixelQueue(image) != (PixelPacket *) NULL)
3293 Allocate next image structure.
3295 if (logging != MagickFalse)
3296 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3297 " AcquireNextImage()");
3299 AcquireNextImage(image_info,image);
3301 if (GetNextImageInList(image) == (Image *) NULL)
3302 return((Image *) NULL);
3304 image=SyncNextImageInList(image);
3306 mng_info->image=image;
3309 Signature bytes have already been read.
3312 read_JSEP=MagickFalse;
3313 reading_idat=MagickFalse;
3314 skip_to_iend=MagickFalse;
3318 type[MaxTextExtent];
3327 Read a new JNG chunk.
3329 status=SetImageProgress(image,LoadImagesTag,TellBlob(image),
3330 2*GetBlobSize(image));
3332 if (status == MagickFalse)
3336 (void) ConcatenateMagickString(type,"errr",MaxTextExtent);
3337 length=ReadBlobMSBLong(image);
3338 count=(unsigned int) ReadBlob(image,4,(unsigned char *) type);
3340 if (logging != MagickFalse)
3341 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3342 " Reading JNG chunk type %c%c%c%c, length: %.20g",
3343 type[0],type[1],type[2],type[3],(double) length);
3345 if (length > PNG_UINT_31_MAX || count == 0)
3346 ThrowReaderException(CorruptImageError,"CorruptImage");
3349 chunk=(unsigned char *) NULL;
3353 chunk=(unsigned char *) AcquireQuantumMemory(length,sizeof(*chunk));
3355 if (chunk == (unsigned char *) NULL)
3356 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
3358 for (i=0; i < (ssize_t) length; i++)
3359 chunk[i]=(unsigned char) ReadBlobByte(image);
3364 (void) ReadBlobMSBLong(image); /* read crc word */
3369 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
3374 if (memcmp(type,mng_JHDR,4) == 0)
3378 jng_width=(size_t) ((p[0] << 24) | (p[1] << 16) |
3379 (p[2] << 8) | p[3]);
3380 jng_height=(size_t) ((p[4] << 24) | (p[5] << 16) |
3381 (p[6] << 8) | p[7]);
3382 jng_color_type=p[8];
3383 jng_image_sample_depth=p[9];
3384 jng_image_compression_method=p[10];
3385 jng_image_interlace_method=p[11];
3387 image->interlace=jng_image_interlace_method != 0 ? PNGInterlace :
3390 jng_alpha_sample_depth=p[12];
3391 jng_alpha_compression_method=p[13];
3392 jng_alpha_filter_method=p[14];
3393 jng_alpha_interlace_method=p[15];
3395 if (logging != MagickFalse)
3397 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3398 " jng_width: %16lu",(unsigned long) jng_width);
3400 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3401 " jng_width: %16lu",(unsigned long) jng_height);
3403 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3404 " jng_color_type: %16d",jng_color_type);
3406 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3407 " jng_image_sample_depth: %3d",
3408 jng_image_sample_depth);
3410 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3411 " jng_image_compression_method:%3d",
3412 jng_image_compression_method);
3414 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3415 " jng_image_interlace_method: %3d",
3416 jng_image_interlace_method);
3418 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3419 " jng_alpha_sample_depth: %3d",
3420 jng_alpha_sample_depth);
3422 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3423 " jng_alpha_compression_method:%3d",
3424 jng_alpha_compression_method);
3426 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3427 " jng_alpha_filter_method: %3d",
3428 jng_alpha_filter_method);
3430 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3431 " jng_alpha_interlace_method: %3d",
3432 jng_alpha_interlace_method);
3437 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
3443 if ((reading_idat == MagickFalse) && (read_JSEP == MagickFalse) &&
3444 ((memcmp(type,mng_JDAT,4) == 0) || (memcmp(type,mng_JdAA,4) == 0) ||
3445 (memcmp(type,mng_IDAT,4) == 0) || (memcmp(type,mng_JDAA,4) == 0)))
3448 o create color_image
3449 o open color_blob, attached to color_image
3450 o if (color type has alpha)
3451 open alpha_blob, attached to alpha_image
3454 color_image_info=(ImageInfo *)AcquireMagickMemory(sizeof(ImageInfo));
3456 if (color_image_info == (ImageInfo *) NULL)
3457 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
3459 GetImageInfo(color_image_info);
3460 color_image=AcquireImage(color_image_info);
3462 if (color_image == (Image *) NULL)
3463 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
3465 if (logging != MagickFalse)
3466 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3467 " Creating color_blob.");
3469 (void) AcquireUniqueFilename(color_image->filename);
3470 status=OpenBlob(color_image_info,color_image,WriteBinaryBlobMode,
3473 if (status == MagickFalse)
3474 return((Image *) NULL);
3476 if ((image_info->ping == MagickFalse) && (jng_color_type >= 12))
3478 alpha_image_info=(ImageInfo *)
3479 AcquireMagickMemory(sizeof(ImageInfo));
3481 if (alpha_image_info == (ImageInfo *) NULL)
3482 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
3484 GetImageInfo(alpha_image_info);
3485 alpha_image=AcquireImage(alpha_image_info);
3487 if (alpha_image == (Image *) NULL)
3489 alpha_image=DestroyImage(alpha_image);
3490 ThrowReaderException(ResourceLimitError,
3491 "MemoryAllocationFailed");
3494 if (logging != MagickFalse)
3495 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3496 " Creating alpha_blob.");
3498 (void) AcquireUniqueFilename(alpha_image->filename);
3499 status=OpenBlob(alpha_image_info,alpha_image,WriteBinaryBlobMode,
3502 if (status == MagickFalse)
3503 return((Image *) NULL);
3505 if (jng_alpha_compression_method == 0)
3510 if (logging != MagickFalse)
3511 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3512 " Writing IHDR chunk to alpha_blob.");
3514 (void) WriteBlob(alpha_image,8,(const unsigned char *)
3515 "\211PNG\r\n\032\n");
3517 (void) WriteBlobMSBULong(alpha_image,13L);
3518 PNGType(data,mng_IHDR);
3519 LogPNGChunk(logging,mng_IHDR,13L);
3520 PNGLong(data+4,jng_width);
3521 PNGLong(data+8,jng_height);
3522 data[12]=jng_alpha_sample_depth;
3523 data[13]=0; /* color_type gray */
3524 data[14]=0; /* compression method 0 */
3525 data[15]=0; /* filter_method 0 */
3526 data[16]=0; /* interlace_method 0 */
3527 (void) WriteBlob(alpha_image,17,data);
3528 (void) WriteBlobMSBULong(alpha_image,crc32(0,data,17));
3531 reading_idat=MagickTrue;
3534 if (memcmp(type,mng_JDAT,4) == 0)
3536 /* Copy chunk to color_image->blob */
3538 if (logging != MagickFalse)
3539 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3540 " Copying JDAT chunk data to color_blob.");
3542 (void) WriteBlob(color_image,length,chunk);
3545 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
3550 if (memcmp(type,mng_IDAT,4) == 0)
3555 /* Copy IDAT header and chunk data to alpha_image->blob */
3557 if (image_info->ping == MagickFalse)
3559 if (logging != MagickFalse)
3560 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3561 " Copying IDAT chunk data to alpha_blob.");
3563 (void) WriteBlobMSBULong(alpha_image,(size_t) length);
3564 PNGType(data,mng_IDAT);
3565 LogPNGChunk(logging,mng_IDAT,length);
3566 (void) WriteBlob(alpha_image,4,data);
3567 (void) WriteBlob(alpha_image,length,chunk);
3568 (void) WriteBlobMSBULong(alpha_image,
3569 crc32(crc32(0,data,4),chunk,(uInt) length));
3573 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
3578 if ((memcmp(type,mng_JDAA,4) == 0) || (memcmp(type,mng_JdAA,4) == 0))
3580 /* Copy chunk data to alpha_image->blob */
3582 if (image_info->ping == MagickFalse)
3584 if (logging != MagickFalse)
3585 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3586 " Copying JDAA chunk data to alpha_blob.");
3588 (void) WriteBlob(alpha_image,length,chunk);
3592 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
3597 if (memcmp(type,mng_JSEP,4) == 0)
3599 read_JSEP=MagickTrue;
3602 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
3607 if (memcmp(type,mng_bKGD,4) == 0)
3611 image->background_color.red=ScaleCharToQuantum(p[1]);
3612 image->background_color.green=image->background_color.red;
3613 image->background_color.blue=image->background_color.red;
3618 image->background_color.red=ScaleCharToQuantum(p[1]);
3619 image->background_color.green=ScaleCharToQuantum(p[3]);
3620 image->background_color.blue=ScaleCharToQuantum(p[5]);
3623 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
3627 if (memcmp(type,mng_gAMA,4) == 0)
3630 image->gamma=((float) mng_get_long(p))*0.00001;
3632 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
3636 if (memcmp(type,mng_cHRM,4) == 0)
3640 image->chromaticity.white_point.x=0.00001*mng_get_long(p);
3641 image->chromaticity.white_point.y=0.00001*mng_get_long(&p[4]);
3642 image->chromaticity.red_primary.x=0.00001*mng_get_long(&p[8]);
3643 image->chromaticity.red_primary.y=0.00001*mng_get_long(&p[12]);
3644 image->chromaticity.green_primary.x=0.00001*mng_get_long(&p[16]);
3645 image->chromaticity.green_primary.y=0.00001*mng_get_long(&p[20]);
3646 image->chromaticity.blue_primary.x=0.00001*mng_get_long(&p[24]);
3647 image->chromaticity.blue_primary.y=0.00001*mng_get_long(&p[28]);
3650 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
3654 if (memcmp(type,mng_sRGB,4) == 0)
3658 image->rendering_intent=
3659 Magick_RenderingIntent_from_PNG_RenderingIntent(p[0]);
3660 image->gamma=0.45455f;
3661 image->chromaticity.red_primary.x=0.6400f;
3662 image->chromaticity.red_primary.y=0.3300f;
3663 image->chromaticity.green_primary.x=0.3000f;
3664 image->chromaticity.green_primary.y=0.6000f;
3665 image->chromaticity.blue_primary.x=0.1500f;
3666 image->chromaticity.blue_primary.y=0.0600f;
3667 image->chromaticity.white_point.x=0.3127f;
3668 image->chromaticity.white_point.y=0.3290f;
3671 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
3675 if (memcmp(type,mng_oFFs,4) == 0)
3679 image->page.x=mng_get_long(p);
3680 image->page.y=mng_get_long(&p[4]);
3682 if ((int) p[8] != 0)
3684 image->page.x/=10000;
3685 image->page.y/=10000;
3690 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
3695 if (memcmp(type,mng_pHYs,4) == 0)
3699 image->x_resolution=(double) mng_get_long(p);
3700 image->y_resolution=(double) mng_get_long(&p[4]);
3701 if ((int) p[8] == PNG_RESOLUTION_METER)
3703 image->units=PixelsPerCentimeterResolution;
3704 image->x_resolution=image->x_resolution/100.0f;
3705 image->y_resolution=image->y_resolution/100.0f;
3709 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
3714 if (memcmp(type,mng_iCCP,4) == 0)
3718 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
3725 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
3727 if (memcmp(type,mng_IEND,4))
3737 Finish up reading image data:
3739 o read main image from color_blob.
3743 o if (color_type has alpha)
3744 if alpha_encoding is PNG
3745 read secondary image from alpha_blob via ReadPNG
3746 if alpha_encoding is JPEG
3747 read secondary image from alpha_blob via ReadJPEG
3751 o copy intensity of secondary image into
3752 opacity samples of main image.
3754 o destroy the secondary image.
3757 (void) CloseBlob(color_image);
3759 if (logging != MagickFalse)
3760 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3761 " Reading jng_image from color_blob.");
3763 (void) FormatMagickString(color_image_info->filename,MaxTextExtent,"%s",
3764 color_image->filename);
3766 color_image_info->ping=MagickFalse; /* To do: avoid this */
3767 jng_image=ReadImage(color_image_info,exception);
3769 if (jng_image == (Image *) NULL)
3770 return((Image *) NULL);
3772 (void) RelinquishUniqueFileResource(color_image->filename);
3773 color_image=DestroyImage(color_image);
3774 color_image_info=DestroyImageInfo(color_image_info);
3776 if (jng_image == (Image *) NULL)
3777 return((Image *) NULL);
3779 if (logging != MagickFalse)
3780 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3781 " Copying jng_image pixels to main image.");
3783 image->rows=jng_height;
3784 image->columns=jng_width;
3785 length=image->columns*sizeof(PixelPacket);
3787 for (y=0; y < (ssize_t) image->rows; y++)
3789 s=GetVirtualPixels(jng_image,0,y,image->columns,1,&image->exception);
3790 q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
3791 (void) CopyMagickMemory(q,s,length);
3793 if (SyncAuthenticPixels(image,exception) == MagickFalse)
3797 jng_image=DestroyImage(jng_image);
3799 if (image_info->ping == MagickFalse)
3801 if (jng_color_type >= 12)
3803 if (jng_alpha_compression_method == 0)
3807 (void) WriteBlobMSBULong(alpha_image,0x00000000L);
3808 PNGType(data,mng_IEND);
3809 LogPNGChunk(logging,mng_IEND,0L);
3810 (void) WriteBlob(alpha_image,4,data);
3811 (void) WriteBlobMSBULong(alpha_image,crc32(0,data,4));
3814 (void) CloseBlob(alpha_image);
3816 if (logging != MagickFalse)
3817 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3818 " Reading opacity from alpha_blob.");
3820 (void) FormatMagickString(alpha_image_info->filename,MaxTextExtent,
3821 "%s",alpha_image->filename);
3823 jng_image=ReadImage(alpha_image_info,exception);
3825 if (jng_image != (Image *) NULL)
3826 for (y=0; y < (ssize_t) image->rows; y++)
3828 s=GetVirtualPixels(jng_image,0,y,image->columns,1,
3830 q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
3832 if (image->matte != MagickFalse)
3833 for (x=(ssize_t) image->columns; x != 0; x--,q++,s++)
3834 q->opacity=(Quantum) QuantumRange-s->red;
3837 for (x=(ssize_t) image->columns; x != 0; x--,q++,s++)
3839 q->opacity=(Quantum) QuantumRange-s->red;
3840 if (q->opacity != OpaqueOpacity)
3841 image->matte=MagickTrue;
3844 if (SyncAuthenticPixels(image,exception) == MagickFalse)
3847 (void) RelinquishUniqueFileResource(alpha_image->filename);
3848 alpha_image=DestroyImage(alpha_image);
3849 alpha_image_info=DestroyImageInfo(alpha_image_info);
3850 if (jng_image != (Image *) NULL)
3851 jng_image=DestroyImage(jng_image);
3855 /* Read the JNG image. */
3857 if (mng_info->mng_type == 0)
3859 mng_info->mng_width=jng_width;
3860 mng_info->mng_height=jng_height;
3863 if (image->page.width == 0 && image->page.height == 0)
3865 image->page.width=jng_width;
3866 image->page.height=jng_height;
3869 if (image->page.x == 0 && image->page.y == 0)
3871 image->page.x=mng_info->x_off[mng_info->object_id];
3872 image->page.y=mng_info->y_off[mng_info->object_id];
3877 image->page.y=mng_info->y_off[mng_info->object_id];
3880 mng_info->image_found++;
3881 status=SetImageProgress(image,LoadImagesTag,2*TellBlob(image),
3882 2*GetBlobSize(image));
3884 if (logging != MagickFalse)
3885 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3886 " exit ReadOneJNGImage()");
3892 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3896 % R e a d J N G I m a g e %
3900 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3902 % ReadJNGImage() reads a JPEG Network Graphics (JNG) image file
3903 % (including the 8-byte signature) and returns it. It allocates the memory
3904 % necessary for the new Image structure and returns a pointer to the new
3907 % JNG support written by Glenn Randers-Pehrson, glennrp@image...
3909 % The format of the ReadJNGImage method is:
3911 % Image *ReadJNGImage(const ImageInfo *image_info, ExceptionInfo
3914 % A description of each parameter follows:
3916 % o image_info: the image info.
3918 % o exception: return any errors or warnings in this structure.
3922 static Image *ReadJNGImage(const ImageInfo *image_info,ExceptionInfo *exception)
3937 magic_number[MaxTextExtent];
3945 assert(image_info != (const ImageInfo *) NULL);
3946 assert(image_info->signature == MagickSignature);
3947 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image_info->filename);
3948 assert(exception != (ExceptionInfo *) NULL);
3949 assert(exception->signature == MagickSignature);
3950 logging=LogMagickEvent(CoderEvent,GetMagickModule(),"enter ReadJNGImage()");
3951 image=AcquireImage(image_info);
3952 mng_info=(MngInfo *) NULL;
3953 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
3955 if (status == MagickFalse)
3956 return((Image *) NULL);
3958 if (LocaleCompare(image_info->magick,"JNG") != 0)
3959 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
3961 /* Verify JNG signature. */
3963 count=(size_t) ReadBlob(image,8,(unsigned char *) magic_number);
3965 if (memcmp(magic_number,"\213JNG\r\n\032\n",8) != 0)
3966 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
3968 /* Allocate a MngInfo structure. */
3970 have_mng_structure=MagickFalse;
3971 mng_info=(MngInfo *) AcquireMagickMemory(sizeof(*mng_info));
3973 if (mng_info == (MngInfo *) NULL)
3974 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
3976 /* Initialize members of the MngInfo structure. */
3978 (void) ResetMagickMemory(mng_info,0,sizeof(MngInfo));
3979 have_mng_structure=MagickTrue;
3981 mng_info->image=image;
3983 image=ReadOneJNGImage(mng_info,image_info,exception);
3984 MngInfoFreeStruct(mng_info,&have_mng_structure);
3986 if (image == (Image *) NULL)
3988 if (IsImageObject(previous) != MagickFalse)
3990 (void) CloseBlob(previous);
3991 (void) DestroyImageList(previous);
3994 if (logging != MagickFalse)
3995 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3996 "exit ReadJNGImage() with error");
3998 return((Image *) NULL);
4000 (void) CloseBlob(image);
4002 if (image->columns == 0 || image->rows == 0)
4004 if (logging != MagickFalse)
4005 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4006 "exit ReadJNGImage() with error");
4008 ThrowReaderException(CorruptImageError,"CorruptImage");
4011 if (logging != MagickFalse)
4012 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"exit ReadJNGImage()");
4018 static Image *ReadMNGImage(const ImageInfo *image_info,ExceptionInfo *exception)
4021 page_geometry[MaxTextExtent];
4054 #if defined(MNG_INSERT_LAYERS)
4056 mng_background_color;
4059 register unsigned char
4074 #if defined(MNG_INSERT_LAYERS)
4079 volatile unsigned int
4080 #ifdef MNG_OBJECT_BUFFERS
4081 mng_background_object=0,
4083 mng_type=0; /* 0: PNG or JNG; 1: MNG; 2: MNG-LC; 3: MNG-VLC */
4086 default_frame_timeout,
4088 #if defined(MNG_INSERT_LAYERS)
4094 /* These delays are all measured in image ticks_per_second,
4095 * not in MNG ticks_per_second
4098 default_frame_delay,
4102 #if defined(MNG_INSERT_LAYERS)
4111 previous_fb.bottom=0;
4113 previous_fb.right=0;
4115 default_fb.bottom=0;
4119 /* Open image file. */
4121 assert(image_info != (const ImageInfo *) NULL);
4122 assert(image_info->signature == MagickSignature);
4123 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image_info->filename);
4124 assert(exception != (ExceptionInfo *) NULL);
4125 assert(exception->signature == MagickSignature);
4126 logging=LogMagickEvent(CoderEvent,GetMagickModule(),"enter ReadMNGImage()");
4127 image=AcquireImage(image_info);
4128 mng_info=(MngInfo *) NULL;
4129 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
4131 if (status == MagickFalse)
4132 return((Image *) NULL);
4134 first_mng_object=MagickFalse;
4136 have_mng_structure=MagickFalse;
4138 /* Allocate a MngInfo structure. */
4140 mng_info=(MngInfo *) AcquireMagickMemory(sizeof(MngInfo));
4142 if (mng_info == (MngInfo *) NULL)
4143 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
4145 /* Initialize members of the MngInfo structure. */
4147 (void) ResetMagickMemory(mng_info,0,sizeof(MngInfo));
4148 mng_info->image=image;
4149 have_mng_structure=MagickTrue;
4151 if (LocaleCompare(image_info->magick,"MNG") == 0)
4154 magic_number[MaxTextExtent];
4156 /* Verify MNG signature. */
4157 count=(size_t) ReadBlob(image,8,(unsigned char *) magic_number);
4158 if (memcmp(magic_number,"\212MNG\r\n\032\n",8) != 0)
4159 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
4161 /* Initialize some nonzero members of the MngInfo structure. */
4162 for (i=0; i < MNG_MAX_OBJECTS; i++)
4164 mng_info->object_clip[i].right=(ssize_t) PNG_UINT_31_MAX;
4165 mng_info->object_clip[i].bottom=(ssize_t) PNG_UINT_31_MAX;
4167 mng_info->exists[0]=MagickTrue;
4170 first_mng_object=MagickTrue;
4172 #if defined(MNG_INSERT_LAYERS)
4173 insert_layers=MagickFalse; /* should be False when converting or mogrifying */
4175 default_frame_delay=0;
4176 default_frame_timeout=0;
4179 mng_info->ticks_per_second=1UL*image->ticks_per_second;
4181 skip_to_iend=MagickFalse;
4182 term_chunk_found=MagickFalse;
4183 mng_info->framing_mode=1;
4184 #if defined(MNG_INSERT_LAYERS)
4185 mandatory_back=MagickFalse;
4187 #if defined(MNG_INSERT_LAYERS)
4188 mng_background_color=image->background_color;
4190 default_fb=mng_info->frame;
4191 previous_fb=mng_info->frame;
4195 type[MaxTextExtent];
4197 if (LocaleCompare(image_info->magick,"MNG") == 0)
4206 (void) ConcatenateMagickString(type,"errr",MaxTextExtent);
4207 length=ReadBlobMSBLong(image);
4208 count=(size_t) ReadBlob(image,4,(unsigned char *) type);
4210 if (logging != MagickFalse)
4211 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4212 " Reading MNG chunk type %c%c%c%c, length: %.20g",
4213 type[0],type[1],type[2],type[3],(double) length);
4215 if (length > PNG_UINT_31_MAX)
4219 ThrowReaderException(CorruptImageError,"CorruptImage");
4222 chunk=(unsigned char *) NULL;
4226 chunk=(unsigned char *) AcquireQuantumMemory(length,sizeof(*chunk));
4228 if (chunk == (unsigned char *) NULL)
4229 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
4231 for (i=0; i < (ssize_t) length; i++)
4232 chunk[i]=(unsigned char) ReadBlobByte(image);
4237 (void) ReadBlobMSBLong(image); /* read crc word */
4239 #if !defined(JNG_SUPPORTED)
4240 if (memcmp(type,mng_JHDR,4) == 0)
4242 skip_to_iend=MagickTrue;
4244 if (mng_info->jhdr_warning == 0)
4245 (void) ThrowMagickException(&image->exception,GetMagickModule(),
4246 CoderError,"JNGCompressNotSupported","`%s'",image->filename);
4248 mng_info->jhdr_warning++;
4251 if (memcmp(type,mng_DHDR,4) == 0)
4253 skip_to_iend=MagickTrue;
4255 if (mng_info->dhdr_warning == 0)
4256 (void) ThrowMagickException(&image->exception,GetMagickModule(),
4257 CoderError,"DeltaPNGNotSupported","`%s'",image->filename);
4259 mng_info->dhdr_warning++;
4261 if (memcmp(type,mng_MEND,4) == 0)
4266 if (memcmp(type,mng_IEND,4) == 0)
4267 skip_to_iend=MagickFalse;
4270 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4272 if (logging != MagickFalse)
4273 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4279 if (memcmp(type,mng_MHDR,4) == 0)
4281 mng_info->mng_width=(size_t) ((p[0] << 24) | (p[1] << 16) |
4282 (p[2] << 8) | p[3]);
4284 mng_info->mng_height=(size_t) ((p[4] << 24) | (p[5] << 16) |
4285 (p[6] << 8) | p[7]);
4287 if (logging != MagickFalse)
4289 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4290 " MNG width: %.20g",(double) mng_info->mng_width);
4291 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4292 " MNG height: %.20g",(double) mng_info->mng_height);
4296 mng_info->ticks_per_second=(size_t) mng_get_long(p);
4298 if (mng_info->ticks_per_second == 0)
4299 default_frame_delay=0;
4302 default_frame_delay=1UL*image->ticks_per_second/
4303 mng_info->ticks_per_second;
4305 frame_delay=default_frame_delay;
4311 simplicity=(size_t) mng_get_long(p);
4314 mng_type=1; /* Full MNG */
4316 if ((simplicity != 0) && ((simplicity | 11) == 11))
4317 mng_type=2; /* LC */
4319 if ((simplicity != 0) && ((simplicity | 9) == 9))
4320 mng_type=3; /* VLC */
4322 #if defined(MNG_INSERT_LAYERS)
4324 insert_layers=MagickTrue;
4326 if (GetAuthenticPixelQueue(image) != (PixelPacket *) NULL)
4328 /* Allocate next image structure. */
4329 AcquireNextImage(image_info,image);
4331 if (GetNextImageInList(image) == (Image *) NULL)
4332 return((Image *) NULL);
4334 image=SyncNextImageInList(image);
4335 mng_info->image=image;
4338 if ((mng_info->mng_width > 65535L) ||
4339 (mng_info->mng_height > 65535L))
4340 ThrowReaderException(ImageError,"WidthOrHeightExceedsLimit");
4342 (void) FormatMagickString(page_geometry,MaxTextExtent,
4343 "%.20gx%.20g+0+0",(double) mng_info->mng_width,(double)
4344 mng_info->mng_height);
4346 mng_info->frame.left=0;
4347 mng_info->frame.right=(ssize_t) mng_info->mng_width;
4348 mng_info->frame.top=0;
4349 mng_info->frame.bottom=(ssize_t) mng_info->mng_height;
4350 mng_info->clip=default_fb=previous_fb=mng_info->frame;
4352 for (i=0; i < MNG_MAX_OBJECTS; i++)
4353 mng_info->object_clip[i]=mng_info->frame;
4355 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4359 if (memcmp(type,mng_TERM,4) == 0)
4370 final_delay=(png_uint_32) mng_get_long(&p[2]);
4371 mng_iterations=(png_uint_32) mng_get_long(&p[6]);
4373 if (mng_iterations == PNG_UINT_31_MAX)
4376 image->iterations=mng_iterations;
4377 term_chunk_found=MagickTrue;
4380 if (logging != MagickFalse)
4382 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4383 " repeat=%d",repeat);
4385 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4386 " final_delay=%.20g",(double) final_delay);
4388 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4389 " image->iterations=%.20g",(double) image->iterations);
4392 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4395 if (memcmp(type,mng_DEFI,4) == 0)
4398 (void) ThrowMagickException(&image->exception,GetMagickModule(),
4399 CoderError,"DEFI chunk found in MNG-VLC datastream","`%s'",
4402 object_id=(p[0] << 8) | p[1];
4404 if (mng_type == 2 && object_id != 0)
4405 (void) ThrowMagickException(&image->exception,GetMagickModule(),
4406 CoderError,"Nonzero object_id in MNG-LC datastream","`%s'",
4409 if (object_id > MNG_MAX_OBJECTS)
4412 Instead ofsuing a warning we should allocate a larger
4413 MngInfo structure and continue.
4415 (void) ThrowMagickException(&image->exception,GetMagickModule(),
4416 CoderError,"object id too large","`%s'",image->filename);
4417 object_id=MNG_MAX_OBJECTS;
4420 if (mng_info->exists[object_id])
4421 if (mng_info->frozen[object_id])
4423 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4424 (void) ThrowMagickException(&image->exception,
4425 GetMagickModule(),CoderError,
4426 "DEFI cannot redefine a frozen MNG object","`%s'",
4431 mng_info->exists[object_id]=MagickTrue;
4434 mng_info->invisible[object_id]=p[2];
4437 Extract object offset info.
4441 mng_info->x_off[object_id]=(ssize_t) ((p[4] << 24) |
4442 (p[5] << 16) | (p[6] << 8) | p[7]);
4444 mng_info->y_off[object_id]=(ssize_t) ((p[8] << 24) |
4445 (p[9] << 16) | (p[10] << 8) | p[11]);
4447 if (logging != MagickFalse)
4449 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4450 " x_off[%d]: %.20g",object_id,(double)
4451 mng_info->x_off[object_id]);
4453 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4454 " y_off[%d]: %.20g",object_id,(double)
4455 mng_info->y_off[object_id]);
4460 Extract object clipping info.
4463 mng_info->object_clip[object_id]=mng_read_box(mng_info->frame,0,
4466 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4469 if (memcmp(type,mng_bKGD,4) == 0)
4471 mng_info->have_global_bkgd=MagickFalse;
4475 mng_info->mng_global_bkgd.red=
4476 ScaleShortToQuantum((unsigned short) ((p[0] << 8) | p[1]));
4478 mng_info->mng_global_bkgd.green=
4479 ScaleShortToQuantum((unsigned short) ((p[2] << 8) | p[3]));
4481 mng_info->mng_global_bkgd.blue=
4482 ScaleShortToQuantum((unsigned short) ((p[4] << 8) | p[5]));
4484 mng_info->have_global_bkgd=MagickTrue;
4487 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4490 if (memcmp(type,mng_BACK,4) == 0)
4492 #if defined(MNG_INSERT_LAYERS)
4494 mandatory_back=p[6];
4499 if (mandatory_back && length > 5)
4501 mng_background_color.red=
4502 ScaleShortToQuantum((unsigned short) ((p[0] << 8) | p[1]));
4504 mng_background_color.green=
4505 ScaleShortToQuantum((unsigned short) ((p[2] << 8) | p[3]));
4507 mng_background_color.blue=
4508 ScaleShortToQuantum((unsigned short) ((p[4] << 8) | p[5]));
4510 mng_background_color.opacity=OpaqueOpacity;
4513 #ifdef MNG_OBJECT_BUFFERS
4515 mng_background_object=(p[7] << 8) | p[8];
4518 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4522 if (memcmp(type,mng_PLTE,4) == 0)
4524 /* Read global PLTE. */
4526 if (length && (length < 769))
4528 if (mng_info->global_plte == (png_colorp) NULL)
4529 mng_info->global_plte=(png_colorp) AcquireQuantumMemory(256,
4530 sizeof(*mng_info->global_plte));
4532 for (i=0; i < (ssize_t) (length/3); i++)
4534 mng_info->global_plte[i].red=p[3*i];
4535 mng_info->global_plte[i].green=p[3*i+1];
4536 mng_info->global_plte[i].blue=p[3*i+2];
4539 mng_info->global_plte_length=(unsigned int) (length/3);
4542 for ( ; i < 256; i++)
4544 mng_info->global_plte[i].red=i;
4545 mng_info->global_plte[i].green=i;
4546 mng_info->global_plte[i].blue=i;
4550 mng_info->global_plte_length=256;
4553 mng_info->global_plte_length=0;
4555 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4559 if (memcmp(type,mng_tRNS,4) == 0)
4561 /* read global tRNS */
4564 for (i=0; i < (ssize_t) length; i++)
4565 mng_info->global_trns[i]=p[i];
4568 for ( ; i < 256; i++)
4569 mng_info->global_trns[i]=255;
4571 mng_info->global_trns_length=(unsigned int) length;
4572 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4575 if (memcmp(type,mng_gAMA,4) == 0)
4582 igamma=mng_get_long(p);
4583 mng_info->global_gamma=((float) igamma)*0.00001;
4584 mng_info->have_global_gama=MagickTrue;
4588 mng_info->have_global_gama=MagickFalse;
4590 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4594 if (memcmp(type,mng_cHRM,4) == 0)
4596 /* Read global cHRM */
4600 mng_info->global_chrm.white_point.x=0.00001*mng_get_long(p);
4601 mng_info->global_chrm.white_point.y=0.00001*mng_get_long(&p[4]);
4602 mng_info->global_chrm.red_primary.x=0.00001*mng_get_long(&p[8]);
4603 mng_info->global_chrm.red_primary.y=0.00001*
4604 mng_get_long(&p[12]);
4605 mng_info->global_chrm.green_primary.x=0.00001*
4606 mng_get_long(&p[16]);
4607 mng_info->global_chrm.green_primary.y=0.00001*
4608 mng_get_long(&p[20]);
4609 mng_info->global_chrm.blue_primary.x=0.00001*
4610 mng_get_long(&p[24]);
4611 mng_info->global_chrm.blue_primary.y=0.00001*
4612 mng_get_long(&p[28]);
4613 mng_info->have_global_chrm=MagickTrue;
4616 mng_info->have_global_chrm=MagickFalse;
4618 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4622 if (memcmp(type,mng_sRGB,4) == 0)
4629 mng_info->global_srgb_intent=
4630 Magick_RenderingIntent_from_PNG_RenderingIntent(p[0]);
4631 mng_info->have_global_srgb=MagickTrue;
4634 mng_info->have_global_srgb=MagickFalse;
4636 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4640 if (memcmp(type,mng_iCCP,4) == 0)
4648 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4653 if (memcmp(type,mng_FRAM,4) == 0)
4656 (void) ThrowMagickException(&image->exception,GetMagickModule(),
4657 CoderError,"FRAM chunk found in MNG-VLC datastream","`%s'",
4660 if ((mng_info->framing_mode == 2) || (mng_info->framing_mode == 4))
4661 image->delay=frame_delay;
4663 frame_delay=default_frame_delay;
4664 frame_timeout=default_frame_timeout;
4669 mng_info->framing_mode=p[0];
4671 if (logging != MagickFalse)
4672 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4673 " Framing_mode=%d",mng_info->framing_mode);
4677 /* Note the delay and frame clipping boundaries. */
4679 p++; /* framing mode */
4681 while (*p && ((p-chunk) < (ssize_t) length))
4682 p++; /* frame name */
4684 p++; /* frame name terminator */
4686 if ((p-chunk) < (ssize_t) (length-4))
4693 change_delay=(*p++);
4694 change_timeout=(*p++);
4695 change_clipping=(*p++);
4696 p++; /* change_sync */
4700 frame_delay=1UL*image->ticks_per_second*
4703 if (mng_info->ticks_per_second != 0)
4704 frame_delay/=mng_info->ticks_per_second;
4707 frame_delay=PNG_UINT_31_MAX;
4709 if (change_delay == 2)
4710 default_frame_delay=frame_delay;
4714 if (logging != MagickFalse)
4715 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4716 " Framing_delay=%.20g",(double) frame_delay);
4721 frame_timeout=1UL*image->ticks_per_second*
4724 if (mng_info->ticks_per_second != 0)
4725 frame_timeout/=mng_info->ticks_per_second;
4728 frame_timeout=PNG_UINT_31_MAX;
4730 if (change_delay == 2)
4731 default_frame_timeout=frame_timeout;
4735 if (logging != MagickFalse)
4736 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4737 " Framing_timeout=%.20g",(double) frame_timeout);
4740 if (change_clipping)
4742 fb=mng_read_box(previous_fb,(char) p[0],&p[1]);
4746 if (logging != MagickFalse)
4747 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4748 " Frame_clip: L=%.20g R=%.20g T=%.20g B=%.20g",
4749 (double) fb.left,(double) fb.right,(double) fb.top,
4750 (double) fb.bottom);
4752 if (change_clipping == 2)
4758 mng_info->clip=mng_minimum_box(fb,mng_info->frame);
4760 subframe_width=(size_t) (mng_info->clip.right
4761 -mng_info->clip.left);
4763 subframe_height=(size_t) (mng_info->clip.bottom
4764 -mng_info->clip.top);
4766 Insert a background layer behind the frame if framing_mode is 4.
4768 #if defined(MNG_INSERT_LAYERS)
4769 if (logging != MagickFalse)
4770 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4771 " subframe_width=%.20g, subframe_height=%.20g",(double)
4772 subframe_width,(double) subframe_height);
4774 if (insert_layers && (mng_info->framing_mode == 4) &&
4775 (subframe_width) && (subframe_height))
4777 /* Allocate next image structure. */
4778 if (GetAuthenticPixelQueue(image) != (PixelPacket *) NULL)
4780 AcquireNextImage(image_info,image);
4782 if (GetNextImageInList(image) == (Image *) NULL)
4784 image=DestroyImageList(image);
4785 MngInfoFreeStruct(mng_info,&have_mng_structure);
4786 return((Image *) NULL);
4789 image=SyncNextImageInList(image);
4792 mng_info->image=image;
4794 if (term_chunk_found)
4796 image->start_loop=MagickTrue;
4797 image->iterations=mng_iterations;
4798 term_chunk_found=MagickFalse;
4802 image->start_loop=MagickFalse;
4804 image->columns=subframe_width;
4805 image->rows=subframe_height;
4806 image->page.width=subframe_width;
4807 image->page.height=subframe_height;
4808 image->page.x=mng_info->clip.left;
4809 image->page.y=mng_info->clip.top;
4810 image->background_color=mng_background_color;
4811 image->matte=MagickFalse;
4813 (void) SetImageBackgroundColor(image);
4815 if (logging != MagickFalse)
4816 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4817 " Insert backgd layer, L=%.20g, R=%.20g T=%.20g, B=%.20g",
4818 (double) mng_info->clip.left,(double) mng_info->clip.right,
4819 (double) mng_info->clip.top,(double) mng_info->clip.bottom);
4822 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4825 if (memcmp(type,mng_CLIP,4) == 0)
4834 first_object=(p[0] << 8) | p[1];
4835 last_object=(p[2] << 8) | p[3];
4837 for (i=(int) first_object; i <= (int) last_object; i++)
4839 if (mng_info->exists[i] && !mng_info->frozen[i])
4844 box=mng_info->object_clip[i];
4845 mng_info->object_clip[i]=mng_read_box(box,(char) p[4],&p[5]);
4849 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4852 if (memcmp(type,mng_SAVE,4) == 0)
4854 for (i=1; i < MNG_MAX_OBJECTS; i++)
4855 if (mng_info->exists[i])
4857 mng_info->frozen[i]=MagickTrue;
4858 #ifdef MNG_OBJECT_BUFFERS
4859 if (mng_info->ob[i] != (MngBuffer *) NULL)
4860 mng_info->ob[i]->frozen=MagickTrue;
4865 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4870 if ((memcmp(type,mng_DISC,4) == 0) || (memcmp(type,mng_SEEK,4) == 0))
4872 /* Read DISC or SEEK. */
4874 if ((length == 0) || !memcmp(type,mng_SEEK,4))
4876 for (i=1; i < MNG_MAX_OBJECTS; i++)
4877 MngInfoDiscardObject(mng_info,i);
4885 for (j=0; j < (ssize_t) length; j+=2)
4887 i=p[j] << 8 | p[j+1];
4888 MngInfoDiscardObject(mng_info,i);
4893 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4898 if (memcmp(type,mng_MOVE,4) == 0)
4906 first_object=(p[0] << 8) | p[1];
4907 last_object=(p[2] << 8) | p[3];
4908 for (i=(ssize_t) first_object; i <= (ssize_t) last_object; i++)
4910 if (mng_info->exists[i] && !mng_info->frozen[i])
4918 old_pair.a=mng_info->x_off[i];
4919 old_pair.b=mng_info->y_off[i];
4920 new_pair=mng_read_pair(old_pair,(int) p[4],&p[5]);
4921 mng_info->x_off[i]=new_pair.a;
4922 mng_info->y_off[i]=new_pair.b;
4926 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4930 if (memcmp(type,mng_LOOP,4) == 0)
4932 ssize_t loop_iters=1;
4933 loop_level=chunk[0];
4934 mng_info->loop_active[loop_level]=1; /* mark loop active */
4936 /* Record starting point. */
4937 loop_iters=mng_get_long(&chunk[1]);
4939 if (logging != MagickFalse)
4940 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4941 " LOOP level %.20g has %.20g iterations ",(double) loop_level,
4942 (double) loop_iters);
4944 if (loop_iters == 0)
4945 skipping_loop=loop_level;
4949 mng_info->loop_jump[loop_level]=TellBlob(image);
4950 mng_info->loop_count[loop_level]=loop_iters;
4953 mng_info->loop_iteration[loop_level]=0;
4954 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4958 if (memcmp(type,mng_ENDL,4) == 0)
4960 loop_level=chunk[0];
4962 if (skipping_loop > 0)
4964 if (skipping_loop == loop_level)
4967 Found end of zero-iteration loop.
4970 mng_info->loop_active[loop_level]=0;
4976 if (mng_info->loop_active[loop_level] == 1)
4978 mng_info->loop_count[loop_level]--;
4979 mng_info->loop_iteration[loop_level]++;
4981 if (logging != MagickFalse)
4982 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4983 " ENDL: LOOP level %.20g has %.20g remaining iters ",
4984 (double) loop_level,(double)
4985 mng_info->loop_count[loop_level]);
4987 if (mng_info->loop_count[loop_level] != 0)
4989 offset=SeekBlob(image,mng_info->loop_jump[loop_level],
4993 ThrowReaderException(CorruptImageError,
4994 "ImproperImageHeader");
5005 mng_info->loop_active[loop_level]=0;
5007 for (i=0; i < loop_level; i++)
5008 if (mng_info->loop_active[i] == 1)
5009 last_level=(short) i;
5010 loop_level=last_level;
5015 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5019 if (memcmp(type,mng_CLON,4) == 0)
5021 if (mng_info->clon_warning == 0)
5022 (void) ThrowMagickException(&image->exception,GetMagickModule(),
5023 CoderError,"CLON is not implemented yet","`%s'",
5026 mng_info->clon_warning++;
5029 if (memcmp(type,mng_MAGN,4) == 0)
5044 magn_first=(p[0] << 8) | p[1];
5050 magn_last=(p[2] << 8) | p[3];
5053 magn_last=magn_first;
5054 #ifndef MNG_OBJECT_BUFFERS
5055 if (magn_first || magn_last)
5056 if (mng_info->magn_warning == 0)
5058 (void) ThrowMagickException(&image->exception,
5059 GetMagickModule(),CoderError,
5060 "MAGN is not implemented yet for nonzero objects",
5061 "`%s'",image->filename);
5063 mng_info->magn_warning++;
5073 magn_mx=(p[5] << 8) | p[6];
5082 magn_my=(p[7] << 8) | p[8];
5091 magn_ml=(p[9] << 8) | p[10];
5100 magn_mr=(p[11] << 8) | p[12];
5109 magn_mt=(p[13] << 8) | p[14];
5118 magn_mb=(p[15] << 8) | p[16];
5130 magn_methy=magn_methx;
5133 if (magn_methx > 5 || magn_methy > 5)
5134 if (mng_info->magn_warning == 0)
5136 (void) ThrowMagickException(&image->exception,
5137 GetMagickModule(),CoderError,
5138 "Unknown MAGN method in MNG datastream","`%s'",
5141 mng_info->magn_warning++;
5143 #ifdef MNG_OBJECT_BUFFERS
5144 /* Magnify existing objects in the range magn_first to magn_last */
5146 if (magn_first == 0 || magn_last == 0)
5148 /* Save the magnification factors for object 0 */
5149 mng_info->magn_mb=magn_mb;
5150 mng_info->magn_ml=magn_ml;
5151 mng_info->magn_mr=magn_mr;
5152 mng_info->magn_mt=magn_mt;
5153 mng_info->magn_mx=magn_mx;
5154 mng_info->magn_my=magn_my;
5155 mng_info->magn_methx=magn_methx;
5156 mng_info->magn_methy=magn_methy;
5160 if (memcmp(type,mng_PAST,4) == 0)
5162 if (mng_info->past_warning == 0)
5163 (void) ThrowMagickException(&image->exception,GetMagickModule(),
5164 CoderError,"PAST is not implemented yet","`%s'",
5167 mng_info->past_warning++;
5170 if (memcmp(type,mng_SHOW,4) == 0)
5172 if (mng_info->show_warning == 0)
5173 (void) ThrowMagickException(&image->exception,GetMagickModule(),
5174 CoderError,"SHOW is not implemented yet","`%s'",
5177 mng_info->show_warning++;
5180 if (memcmp(type,mng_sBIT,4) == 0)
5183 mng_info->have_global_sbit=MagickFalse;
5187 mng_info->global_sbit.gray=p[0];
5188 mng_info->global_sbit.red=p[0];
5189 mng_info->global_sbit.green=p[1];
5190 mng_info->global_sbit.blue=p[2];
5191 mng_info->global_sbit.alpha=p[3];
5192 mng_info->have_global_sbit=MagickTrue;
5195 if (memcmp(type,mng_pHYs,4) == 0)
5199 mng_info->global_x_pixels_per_unit=
5200 (size_t) mng_get_long(p);
5201 mng_info->global_y_pixels_per_unit=
5202 (size_t) mng_get_long(&p[4]);
5203 mng_info->global_phys_unit_type=p[8];
5204 mng_info->have_global_phys=MagickTrue;
5208 mng_info->have_global_phys=MagickFalse;
5210 if (memcmp(type,mng_pHYg,4) == 0)
5212 if (mng_info->phyg_warning == 0)
5213 (void) ThrowMagickException(&image->exception,GetMagickModule(),
5214 CoderError,"pHYg is not implemented.","`%s'",image->filename);
5216 mng_info->phyg_warning++;
5218 if (memcmp(type,mng_BASI,4) == 0)
5220 skip_to_iend=MagickTrue;
5222 if (mng_info->basi_warning == 0)
5223 (void) ThrowMagickException(&image->exception,GetMagickModule(),
5224 CoderError,"BASI is not implemented yet","`%s'",
5227 mng_info->basi_warning++;
5228 #ifdef MNG_BASI_SUPPORTED
5229 basi_width=(size_t) ((p[0] << 24) | (p[1] << 16) |
5230 (p[2] << 8) | p[3]);
5231 basi_height=(size_t) ((p[4] << 24) | (p[5] << 16) |
5232 (p[6] << 8) | p[7]);
5233 basi_color_type=p[8];
5234 basi_compression_method=p[9];
5235 basi_filter_type=p[10];
5236 basi_interlace_method=p[11];
5238 basi_red=(p[12] << 8) & p[13];
5244 basi_green=(p[14] << 8) & p[15];
5250 basi_blue=(p[16] << 8) & p[17];
5256 basi_alpha=(p[18] << 8) & p[19];
5260 if (basi_sample_depth == 16)
5267 basi_viewable=p[20];
5273 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5277 if (memcmp(type,mng_IHDR,4)
5278 #if defined(JNG_SUPPORTED)
5279 && memcmp(type,mng_JHDR,4)
5283 /* Not an IHDR or JHDR chunk */
5285 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5290 if (logging != MagickFalse)
5291 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5292 " Processing %c%c%c%c chunk",type[0],type[1],type[2],type[3]);
5294 mng_info->exists[object_id]=MagickTrue;
5295 mng_info->viewable[object_id]=MagickTrue;
5297 if (mng_info->invisible[object_id])
5299 if (logging != MagickFalse)
5300 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5301 " Skipping invisible object");
5303 skip_to_iend=MagickTrue;
5304 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5307 #if defined(MNG_INSERT_LAYERS)
5309 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
5311 image_width=(size_t) mng_get_long(p);
5312 image_height=(size_t) mng_get_long(&p[4]);
5314 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5317 Insert a transparent background layer behind the entire animation
5318 if it is not full screen.
5320 #if defined(MNG_INSERT_LAYERS)
5321 if (insert_layers && mng_type && first_mng_object)
5323 if ((mng_info->clip.left > 0) || (mng_info->clip.top > 0) ||
5324 (image_width < mng_info->mng_width) ||
5325 (mng_info->clip.right < (ssize_t) mng_info->mng_width) ||
5326 (image_height < mng_info->mng_height) ||
5327 (mng_info->clip.bottom < (ssize_t) mng_info->mng_height))
5329 if (GetAuthenticPixelQueue(image) != (PixelPacket *) NULL)
5332 Allocate next image structure.
5334 AcquireNextImage(image_info,image);
5336 if (GetNextImageInList(image) == (Image *) NULL)
5338 image=DestroyImageList(image);
5339 MngInfoFreeStruct(mng_info,&have_mng_structure);
5340 return((Image *) NULL);
5343 image=SyncNextImageInList(image);
5345 mng_info->image=image;
5347 if (term_chunk_found)
5349 image->start_loop=MagickTrue;
5350 image->iterations=mng_iterations;
5351 term_chunk_found=MagickFalse;
5355 image->start_loop=MagickFalse;
5357 /* Make a background rectangle. */
5360 image->columns=mng_info->mng_width;
5361 image->rows=mng_info->mng_height;
5362 image->page.width=mng_info->mng_width;
5363 image->page.height=mng_info->mng_height;
5366 image->background_color=mng_background_color;
5367 (void) SetImageBackgroundColor(image);
5368 if (logging != MagickFalse)
5369 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5370 " Inserted transparent background layer, W=%.20g, H=%.20g",
5371 (double) mng_info->mng_width,(double) mng_info->mng_height);
5375 Insert a background layer behind the upcoming image if
5376 framing_mode is 3, and we haven't already inserted one.
5378 if (insert_layers && (mng_info->framing_mode == 3) &&
5379 (subframe_width) && (subframe_height) && (simplicity == 0 ||
5380 (simplicity & 0x08)))
5382 if (GetAuthenticPixelQueue(image) != (PixelPacket *) NULL)
5385 Allocate next image structure.
5387 AcquireNextImage(image_info,image);
5389 if (GetNextImageInList(image) == (Image *) NULL)
5391 image=DestroyImageList(image);
5392 MngInfoFreeStruct(mng_info,&have_mng_structure);
5393 return((Image *) NULL);
5396 image=SyncNextImageInList(image);
5399 mng_info->image=image;
5401 if (term_chunk_found)
5403 image->start_loop=MagickTrue;
5404 image->iterations=mng_iterations;
5405 term_chunk_found=MagickFalse;
5409 image->start_loop=MagickFalse;
5412 image->columns=subframe_width;
5413 image->rows=subframe_height;
5414 image->page.width=subframe_width;
5415 image->page.height=subframe_height;
5416 image->page.x=mng_info->clip.left;
5417 image->page.y=mng_info->clip.top;
5418 image->background_color=mng_background_color;
5419 image->matte=MagickFalse;
5420 (void) SetImageBackgroundColor(image);
5422 if (logging != MagickFalse)
5423 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5424 " Insert background layer, L=%.20g, R=%.20g T=%.20g, B=%.20g",
5425 (double) mng_info->clip.left,(double) mng_info->clip.right,
5426 (double) mng_info->clip.top,(double) mng_info->clip.bottom);
5428 #endif /* MNG_INSERT_LAYERS */
5429 first_mng_object=MagickFalse;
5431 if (GetAuthenticPixelQueue(image) != (PixelPacket *) NULL)
5434 Allocate next image structure.
5436 AcquireNextImage(image_info,image);
5438 if (GetNextImageInList(image) == (Image *) NULL)
5440 image=DestroyImageList(image);
5441 MngInfoFreeStruct(mng_info,&have_mng_structure);
5442 return((Image *) NULL);
5445 image=SyncNextImageInList(image);
5447 mng_info->image=image;
5448 status=SetImageProgress(image,LoadImagesTag,TellBlob(image),
5449 GetBlobSize(image));
5451 if (status == MagickFalse)
5454 if (term_chunk_found)
5456 image->start_loop=MagickTrue;
5457 term_chunk_found=MagickFalse;
5461 image->start_loop=MagickFalse;
5463 if (mng_info->framing_mode == 1 || mng_info->framing_mode == 3)
5465 image->delay=frame_delay;
5466 frame_delay=default_frame_delay;
5472 image->page.width=mng_info->mng_width;
5473 image->page.height=mng_info->mng_height;
5474 image->page.x=mng_info->x_off[object_id];
5475 image->page.y=mng_info->y_off[object_id];
5476 image->iterations=mng_iterations;
5479 Seek back to the beginning of the IHDR or JHDR chunk's length field.
5482 if (logging != MagickFalse)
5483 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5484 " Seeking back to beginning of %c%c%c%c chunk",type[0],type[1],
5487 offset=SeekBlob(image,-((ssize_t) length+12),SEEK_CUR);
5490 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
5494 mng_info->image=image;
5495 mng_info->mng_type=mng_type;
5496 mng_info->object_id=object_id;
5498 if (memcmp(type,mng_IHDR,4) == 0)
5499 image=ReadOnePNGImage(mng_info,image_info,exception);
5501 #if defined(JNG_SUPPORTED)
5503 image=ReadOneJNGImage(mng_info,image_info,exception);
5506 if (image == (Image *) NULL)
5508 if (IsImageObject(previous) != MagickFalse)
5510 (void) DestroyImageList(previous);
5511 (void) CloseBlob(previous);
5514 MngInfoFreeStruct(mng_info,&have_mng_structure);
5515 return((Image *) NULL);
5518 if (image->columns == 0 || image->rows == 0)
5520 (void) CloseBlob(image);
5521 image=DestroyImageList(image);
5522 MngInfoFreeStruct(mng_info,&have_mng_structure);
5523 return((Image *) NULL);
5526 mng_info->image=image;
5533 if (mng_info->magn_methx || mng_info->magn_methy)
5539 if (logging != MagickFalse)
5540 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5541 " Processing MNG MAGN chunk");
5543 if (mng_info->magn_methx == 1)
5545 magnified_width=mng_info->magn_ml;
5547 if (image->columns > 1)
5548 magnified_width += mng_info->magn_mr;
5550 if (image->columns > 2)
5551 magnified_width += (png_uint_32)
5552 ((image->columns-2)*(mng_info->magn_mx));
5557 magnified_width=(png_uint_32) image->columns;
5559 if (image->columns > 1)
5560 magnified_width += mng_info->magn_ml-1;
5562 if (image->columns > 2)
5563 magnified_width += mng_info->magn_mr-1;
5565 if (image->columns > 3)
5566 magnified_width += (png_uint_32)
5567 ((image->columns-3)*(mng_info->magn_mx-1));
5570 if (mng_info->magn_methy == 1)
5572 magnified_height=mng_info->magn_mt;
5574 if (image->rows > 1)
5575 magnified_height += mng_info->magn_mb;
5577 if (image->rows > 2)
5578 magnified_height += (png_uint_32)
5579 ((image->rows-2)*(mng_info->magn_my));
5584 magnified_height=(png_uint_32) image->rows;
5586 if (image->rows > 1)
5587 magnified_height += mng_info->magn_mt-1;
5589 if (image->rows > 2)
5590 magnified_height += mng_info->magn_mb-1;
5592 if (image->rows > 3)
5593 magnified_height += (png_uint_32)
5594 ((image->rows-3)*(mng_info->magn_my-1));
5597 if (magnified_height > image->rows ||
5598 magnified_width > image->columns)
5613 register PixelPacket
5625 /* Allocate next image structure. */
5627 if (logging != MagickFalse)
5628 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5629 " Allocate magnified image");
5631 AcquireNextImage(image_info,image);
5633 if (GetNextImageInList(image) == (Image *) NULL)
5635 image=DestroyImageList(image);
5636 MngInfoFreeStruct(mng_info,&have_mng_structure);
5637 return((Image *) NULL);
5640 large_image=SyncNextImageInList(image);
5642 large_image->columns=magnified_width;
5643 large_image->rows=magnified_height;
5645 magn_methx=mng_info->magn_methx;
5646 magn_methy=mng_info->magn_methy;
5648 #if (MAGICKCORE_QUANTUM_DEPTH == 32)
5649 #define QM unsigned short
5650 if (magn_methx != 1 || magn_methy != 1)
5653 Scale pixels to unsigned shorts to prevent
5654 overflow of intermediate values of interpolations
5656 for (y=0; y < (ssize_t) image->rows; y++)
5658 q=GetAuthenticPixels(image,0,y,image->columns,1,
5661 for (x=(ssize_t) image->columns-1; x >= 0; x--)
5663 q->red=ScaleQuantumToShort(q->red);
5664 q->green=ScaleQuantumToShort(q->green);
5665 q->blue=ScaleQuantumToShort(q->blue);
5666 q->opacity=ScaleQuantumToShort(q->opacity);
5670 if (SyncAuthenticPixels(image,exception) == MagickFalse)
5678 if (image->matte != MagickFalse)
5679 (void) SetImageBackgroundColor(large_image);
5683 large_image->background_color.opacity=OpaqueOpacity;
5684 (void) SetImageBackgroundColor(large_image);
5686 if (magn_methx == 4)
5689 if (magn_methx == 5)
5692 if (magn_methy == 4)
5695 if (magn_methy == 5)
5699 /* magnify the rows into the right side of the large image */
5701 if (logging != MagickFalse)
5702 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5703 " Magnify the rows to %.20g",(double) large_image->rows);
5704 m=(ssize_t) mng_info->magn_mt;
5706 length=(size_t) image->columns;
5707 next=(PixelPacket *) AcquireQuantumMemory(length,sizeof(*next));
5708 prev=(PixelPacket *) AcquireQuantumMemory(length,sizeof(*prev));
5710 if ((prev == (PixelPacket *) NULL) ||
5711 (next == (PixelPacket *) NULL))
5713 image=DestroyImageList(image);
5714 MngInfoFreeStruct(mng_info,&have_mng_structure);
5715 ThrowReaderException(ResourceLimitError,
5716 "MemoryAllocationFailed");
5719 n=GetAuthenticPixels(image,0,0,image->columns,1,exception);
5720 (void) CopyMagickMemory(next,n,length);
5722 for (y=0; y < (ssize_t) image->rows; y++)
5725 m=(ssize_t) mng_info->magn_mt;
5727 else if (magn_methy > 1 && y == (ssize_t) image->rows-2)
5728 m=(ssize_t) mng_info->magn_mb;
5730 else if (magn_methy <= 1 && y == (ssize_t) image->rows-1)
5731 m=(ssize_t) mng_info->magn_mb;
5733 else if (magn_methy > 1 && y == (ssize_t) image->rows-1)
5737 m=(ssize_t) mng_info->magn_my;
5743 if (y < (ssize_t) image->rows-1)
5745 n=GetAuthenticPixels(image,0,y+1,image->columns,1,
5747 (void) CopyMagickMemory(next,n,length);
5750 for (i=0; i < m; i++, yy++)
5752 register PixelPacket
5755 assert(yy < (ssize_t) large_image->rows);
5758 q=GetAuthenticPixels(large_image,0,yy,large_image->columns,
5760 q+=(large_image->columns-image->columns);
5762 for (x=(ssize_t) image->columns-1; x >= 0; x--)
5764 /* TO DO: get color as function of indexes[x] */
5766 if (image->storage_class == PseudoClass)
5771 if (magn_methy <= 1)
5773 *q=(*pixels); /* replicate previous */
5776 else if (magn_methy == 2 || magn_methy == 4)
5784 (*q).red=(QM) (((ssize_t) (2*i*((*n).red
5785 -(*pixels).red)+m))/((ssize_t) (m*2))
5787 (*q).green=(QM) (((ssize_t) (2*i*((*n).green
5788 -(*pixels).green)+m))/((ssize_t) (m*2))
5790 (*q).blue=(QM) (((ssize_t) (2*i*((*n).blue
5791 -(*pixels).blue)+m))/((ssize_t) (m*2))
5794 if (image->matte != MagickFalse)
5795 (*q).opacity=(QM) (((ssize_t)
5797 -(*pixels).opacity)+m))
5798 /((ssize_t) (m*2))+(*pixels).opacity);
5801 if (magn_methy == 4)
5803 /* Replicate nearest */
5804 if (i <= ((m+1) << 1))
5805 (*q).opacity=(*pixels).opacity+0;
5807 (*q).opacity=(*n).opacity+0;
5811 else /* if (magn_methy == 3 || magn_methy == 5) */
5813 /* Replicate nearest */
5814 if (i <= ((m+1) << 1))
5820 if (magn_methy == 5)
5822 (*q).opacity=(QM) (((ssize_t) (2*i*((*n).opacity
5823 -(*pixels).opacity)+m))/((ssize_t) (m*2))
5824 +(*pixels).opacity);
5832 if (SyncAuthenticPixels(large_image,exception) == 0)
5838 prev=(PixelPacket *) RelinquishMagickMemory(prev);
5839 next=(PixelPacket *) RelinquishMagickMemory(next);
5841 length=image->columns;
5843 if (logging != MagickFalse)
5844 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5845 " Delete original image");
5847 DeleteImageFromList(&image);
5851 mng_info->image=image;
5853 /* magnify the columns */
5854 if (logging != MagickFalse)
5855 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5856 " Magnify the columns to %.20g",(double) image->columns);
5858 for (y=0; y < (ssize_t) image->rows; y++)
5860 register PixelPacket
5863 q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
5864 pixels=q+(image->columns-length);
5867 for (x=(ssize_t) (image->columns-length);
5868 x < (ssize_t) image->columns; x++)
5870 if (x == (ssize_t) (image->columns-length))
5871 m=(ssize_t) mng_info->magn_ml;
5873 else if (magn_methx > 1 && x == (ssize_t) image->columns-2)
5874 m=(ssize_t) mng_info->magn_mr;
5876 else if (magn_methx <= 1 && x == (ssize_t) image->columns-1)
5877 m=(ssize_t) mng_info->magn_mr;
5879 else if (magn_methx > 1 && x == (ssize_t) image->columns-1)
5883 m=(ssize_t) mng_info->magn_mx;
5885 for (i=0; i < m; i++)
5887 if (magn_methx <= 1)
5889 /* replicate previous */
5893 else if (magn_methx == 2 || magn_methx == 4)
5901 (*q).red=(QM) ((2*i*((*n).red
5903 /((ssize_t) (m*2))+(*pixels).red);
5904 (*q).green=(QM) ((2*i*((*n).green
5906 +m)/((ssize_t) (m*2))+(*pixels).green);
5907 (*q).blue=(QM) ((2*i*((*n).blue
5909 /((ssize_t) (m*2))+(*pixels).blue);
5910 if (image->matte != MagickFalse)
5911 (*q).opacity=(QM) ((2*i*((*n).opacity
5912 -(*pixels).opacity)+m)/((ssize_t) (m*2))
5913 +(*pixels).opacity);
5916 if (magn_methx == 4)
5918 /* Replicate nearest */
5919 if (i <= ((m+1) << 1))
5920 (*q).opacity=(*pixels).opacity+0;
5922 (*q).opacity=(*n).opacity+0;
5926 else /* if (magn_methx == 3 || magn_methx == 5) */
5928 /* Replicate nearest */
5929 if (i <= ((m+1) << 1))
5935 if (magn_methx == 5)
5938 (*q).opacity=(QM) ((2*i*((*n).opacity
5939 -(*pixels).opacity)+m) /((ssize_t) (m*2))
5940 +(*pixels).opacity);
5949 if (SyncAuthenticPixels(image,exception) == MagickFalse)
5952 #if (MAGICKCORE_QUANTUM_DEPTH == 32)
5953 if (magn_methx != 1 || magn_methy != 1)
5956 Rescale pixels to Quantum
5958 for (y=0; y < (ssize_t) image->rows; y++)
5960 q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
5962 for (x=(ssize_t) image->columns-1; x >= 0; x--)
5964 q->red=ScaleShortToQuantum(q->red);
5965 q->green=ScaleShortToQuantum(q->green);
5966 q->blue=ScaleShortToQuantum(q->blue);
5967 q->opacity=ScaleShortToQuantum(q->opacity);
5971 if (SyncAuthenticPixels(image,exception) == MagickFalse)
5976 if (logging != MagickFalse)
5977 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5978 " Finished MAGN processing");
5983 Crop_box is with respect to the upper left corner of the MNG.
5985 crop_box.left=mng_info->image_box.left+mng_info->x_off[object_id];
5986 crop_box.right=mng_info->image_box.right+mng_info->x_off[object_id];
5987 crop_box.top=mng_info->image_box.top+mng_info->y_off[object_id];
5988 crop_box.bottom=mng_info->image_box.bottom+mng_info->y_off[object_id];
5989 crop_box=mng_minimum_box(crop_box,mng_info->clip);
5990 crop_box=mng_minimum_box(crop_box,mng_info->frame);
5991 crop_box=mng_minimum_box(crop_box,mng_info->object_clip[object_id]);
5992 if ((crop_box.left != (mng_info->image_box.left
5993 +mng_info->x_off[object_id])) ||
5994 (crop_box.right != (mng_info->image_box.right
5995 +mng_info->x_off[object_id])) ||
5996 (crop_box.top != (mng_info->image_box.top
5997 +mng_info->y_off[object_id])) ||
5998 (crop_box.bottom != (mng_info->image_box.bottom
5999 +mng_info->y_off[object_id])))
6001 if (logging != MagickFalse)
6002 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6003 " Crop the PNG image");
6005 if ((crop_box.left < crop_box.right) &&
6006 (crop_box.top < crop_box.bottom))
6015 Crop_info is with respect to the upper left corner of
6018 crop_info.x=(crop_box.left-mng_info->x_off[object_id]);
6019 crop_info.y=(crop_box.top-mng_info->y_off[object_id]);
6020 crop_info.width=(size_t) (crop_box.right-crop_box.left);
6021 crop_info.height=(size_t) (crop_box.bottom-crop_box.top);
6022 image->page.width=image->columns;
6023 image->page.height=image->rows;
6026 im=CropImage(image,&crop_info,exception);
6028 if (im != (Image *) NULL)
6030 image->columns=im->columns;
6031 image->rows=im->rows;
6032 im=DestroyImage(im);
6033 image->page.width=image->columns;
6034 image->page.height=image->rows;
6035 image->page.x=crop_box.left;
6036 image->page.y=crop_box.top;
6043 No pixels in crop area. The MNG spec still requires
6044 a layer, though, so make a single transparent pixel in
6045 the top left corner.
6050 (void) SetImageBackgroundColor(image);
6051 image->page.width=1;
6052 image->page.height=1;
6057 #ifndef PNG_READ_EMPTY_PLTE_SUPPORTED
6058 image=mng_info->image;
6062 #if (MAGICKCORE_QUANTUM_DEPTH > 16)
6063 /* PNG does not handle depths greater than 16 so reduce it even
6066 if (image->depth > 16)
6070 #if (MAGICKCORE_QUANTUM_DEPTH >= 16)
6071 if (LosslessReduceDepthOK(image) != MagickFalse)
6075 GetImageException(image,exception);
6077 if (image_info->number_scenes != 0)
6079 if (mng_info->scenes_found >
6080 (ssize_t) (image_info->first_scene+image_info->number_scenes))
6084 if (logging != MagickFalse)
6085 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6086 " Finished reading image datastream.");
6088 } while (LocaleCompare(image_info->magick,"MNG") == 0);
6090 (void) CloseBlob(image);
6092 if (logging != MagickFalse)
6093 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6094 " Finished reading all image datastreams.");
6096 #if defined(MNG_INSERT_LAYERS)
6097 if (insert_layers && !mng_info->image_found && (mng_info->mng_width) &&
6098 (mng_info->mng_height))
6101 Insert a background layer if nothing else was found.
6103 if (logging != MagickFalse)
6104 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6105 " No images found. Inserting a background layer.");
6107 if (GetAuthenticPixelQueue(image) != (PixelPacket *) NULL)
6110 Allocate next image structure.
6112 AcquireNextImage(image_info,image);
6113 if (GetNextImageInList(image) == (Image *) NULL)
6115 image=DestroyImageList(image);
6116 MngInfoFreeStruct(mng_info,&have_mng_structure);
6118 if (logging != MagickFalse)
6119 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6120 " Allocation failed, returning NULL.");
6122 return((Image *) NULL);
6124 image=SyncNextImageInList(image);
6126 image->columns=mng_info->mng_width;
6127 image->rows=mng_info->mng_height;
6128 image->page.width=mng_info->mng_width;
6129 image->page.height=mng_info->mng_height;
6132 image->background_color=mng_background_color;
6133 image->matte=MagickFalse;
6135 if (image_info->ping == MagickFalse)
6136 (void) SetImageBackgroundColor(image);
6138 mng_info->image_found++;
6141 image->iterations=mng_iterations;
6143 if (mng_iterations == 1)
6144 image->start_loop=MagickTrue;
6146 while (GetPreviousImageInList(image) != (Image *) NULL)
6149 if (image_count > 10*mng_info->image_found)
6151 if (logging != MagickFalse)
6152 (void) LogMagickEvent(CoderEvent,GetMagickModule()," No beginning");
6154 (void) ThrowMagickException(&image->exception,GetMagickModule(),
6155 CoderError,"Linked list is corrupted, beginning of list not found",
6156 "`%s'",image_info->filename);
6158 return((Image *) NULL);
6161 image=GetPreviousImageInList(image);
6163 if (GetNextImageInList(image) == (Image *) NULL)
6165 if (logging != MagickFalse)
6166 (void) LogMagickEvent(CoderEvent,GetMagickModule()," Corrupt list");
6168 (void) ThrowMagickException(&image->exception,GetMagickModule(),
6169 CoderError,"Linked list is corrupted; next_image is NULL","`%s'",
6170 image_info->filename);
6174 if (mng_info->ticks_per_second && mng_info->image_found > 1 &&
6175 GetNextImageInList(image) ==
6178 if (logging != MagickFalse)
6179 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6180 " First image null");
6182 (void) ThrowMagickException(&image->exception,GetMagickModule(),
6183 CoderError,"image->next for first image is NULL but shouldn't be.",
6184 "`%s'",image_info->filename);
6187 if (mng_info->image_found == 0)
6189 if (logging != MagickFalse)
6190 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6191 " No visible images found.");
6193 (void) ThrowMagickException(&image->exception,GetMagickModule(),
6194 CoderError,"No visible images in file","`%s'",image_info->filename);
6196 if (image != (Image *) NULL)
6197 image=DestroyImageList(image);
6199 MngInfoFreeStruct(mng_info,&have_mng_structure);
6200 return((Image *) NULL);
6203 if (mng_info->ticks_per_second)
6204 final_delay=1UL*MagickMax(image->ticks_per_second,1L)*
6205 final_delay/mng_info->ticks_per_second;
6208 image->start_loop=MagickTrue;
6210 /* Find final nonzero image delay */
6211 final_image_delay=0;
6213 while (GetNextImageInList(image) != (Image *) NULL)
6216 final_image_delay=image->delay;
6218 image=GetNextImageInList(image);
6221 if (final_delay < final_image_delay)
6222 final_delay=final_image_delay;
6224 image->delay=final_delay;
6226 if (logging != MagickFalse)
6227 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6228 " image->delay=%.20g, final_delay=%.20g",(double) image->delay,
6229 (double) final_delay);
6231 if (logging != MagickFalse)
6237 image=GetFirstImageInList(image);
6239 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6240 " Before coalesce:");
6242 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6243 " scene 0 delay=%.20g",(double) image->delay);
6245 while (GetNextImageInList(image) != (Image *) NULL)
6247 image=GetNextImageInList(image);
6248 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6249 " scene %.20g delay=%.20g",(double) scene++,(double) image->delay);
6253 image=GetFirstImageInList(image);
6254 #ifdef MNG_COALESCE_LAYERS
6264 if (logging != MagickFalse)
6265 (void) LogMagickEvent(CoderEvent,GetMagickModule()," Coalesce Images");
6268 next_image=CoalesceImages(image,&image->exception);
6270 if (next_image == (Image *) NULL)
6271 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
6273 image=DestroyImageList(image);
6276 for (next=image; next != (Image *) NULL; next=next_image)
6278 next->page.width=mng_info->mng_width;
6279 next->page.height=mng_info->mng_height;
6282 next->scene=scene++;
6283 next_image=GetNextImageInList(next);
6285 if (next_image == (Image *) NULL)
6288 if (next->delay == 0)
6291 next_image->previous=GetPreviousImageInList(next);
6292 if (GetPreviousImageInList(next) == (Image *) NULL)
6295 next->previous->next=next_image;
6296 next=DestroyImage(next);
6302 while (GetNextImageInList(image) != (Image *) NULL)
6303 image=GetNextImageInList(image);
6305 image->dispose=BackgroundDispose;
6307 if (logging != MagickFalse)
6313 image=GetFirstImageInList(image);
6315 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6316 " After coalesce:");
6318 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6319 " scene 0 delay=%.20g dispose=%.20g",(double) image->delay,
6320 (double) image->dispose);
6322 while (GetNextImageInList(image) != (Image *) NULL)
6324 image=GetNextImageInList(image);
6326 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6327 " scene %.20g delay=%.20g dispose=%.20g",(double) scene++,
6328 (double) image->delay,(double) image->dispose);
6332 image=GetFirstImageInList(image);
6333 MngInfoFreeStruct(mng_info,&have_mng_structure);
6334 have_mng_structure=MagickFalse;
6336 if (logging != MagickFalse)
6337 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"exit ReadMNGImage()");
6339 return(GetFirstImageInList(image));
6341 #else /* PNG_LIBPNG_VER > 10011 */
6342 static Image *ReadPNGImage(const ImageInfo *image_info,ExceptionInfo *exception)
6344 printf("Your PNG library is too old: You have libpng-%s\n",
6345 PNG_LIBPNG_VER_STRING);
6347 (void) ThrowMagickException(exception,GetMagickModule(),CoderError,
6348 "PNG library is too old","`%s'",image_info->filename);
6350 return(Image *) NULL;
6353 static Image *ReadMNGImage(const ImageInfo *image_info,ExceptionInfo *exception)
6355 return(ReadPNGImage(image_info,exception));
6357 #endif /* PNG_LIBPNG_VER > 10011 */
6361 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6365 % R e g i s t e r P N G I m a g e %
6369 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6371 % RegisterPNGImage() adds properties for the PNG image format to
6372 % the list of supported formats. The properties include the image format
6373 % tag, a method to read and/or write the format, whether the format
6374 % supports the saving of more than one frame to the same file or blob,
6375 % whether the format supports native in-memory I/O, and a brief
6376 % description of the format.
6378 % The format of the RegisterPNGImage method is:
6380 % size_t RegisterPNGImage(void)
6383 ModuleExport size_t RegisterPNGImage(void)
6386 version[MaxTextExtent];
6394 "See http://www.libpng.org/ for details about the PNG format."
6399 "See http://www.libpng.org/pub/mng/ for details about the JNG\n"
6405 "See http://www.libpng.org/pub/mng/ for details about the MNG\n"
6411 #if defined(PNG_LIBPNG_VER_STRING)
6412 (void) ConcatenateMagickString(version,"libpng ",MaxTextExtent);
6413 (void) ConcatenateMagickString(version,PNG_LIBPNG_VER_STRING,MaxTextExtent);
6415 if (LocaleCompare(PNG_LIBPNG_VER_STRING,png_get_header_ver(NULL)) != 0)
6417 (void) ConcatenateMagickString(version,",",MaxTextExtent);
6418 (void) ConcatenateMagickString(version,png_get_libpng_ver(NULL),
6423 entry=SetMagickInfo("MNG");
6424 entry->seekable_stream=MagickTrue; /* To do: eliminate this. */
6426 #if defined(MAGICKCORE_PNG_DELEGATE)
6427 entry->decoder=(DecodeImageHandler *) ReadMNGImage;
6428 entry->encoder=(EncodeImageHandler *) WriteMNGImage;
6431 entry->magick=(IsImageFormatHandler *) IsMNG;
6432 entry->description=ConstantString("Multiple-image Network Graphics");
6434 if (*version != '\0')
6435 entry->version=ConstantString(version);
6437 entry->module=ConstantString("PNG");
6438 entry->note=ConstantString(MNGNote);
6439 (void) RegisterMagickInfo(entry);
6441 entry=SetMagickInfo("PNG");
6443 #if defined(MAGICKCORE_PNG_DELEGATE)
6444 entry->decoder=(DecodeImageHandler *) ReadPNGImage;
6445 entry->encoder=(EncodeImageHandler *) WritePNGImage;
6448 entry->magick=(IsImageFormatHandler *) IsPNG;
6449 entry->adjoin=MagickFalse;
6450 entry->description=ConstantString("Portable Network Graphics");
6451 entry->module=ConstantString("PNG");
6453 if (*version != '\0')
6454 entry->version=ConstantString(version);
6456 entry->note=ConstantString(PNGNote);
6457 (void) RegisterMagickInfo(entry);
6459 entry=SetMagickInfo("PNG8");
6461 #if defined(MAGICKCORE_PNG_DELEGATE)
6462 entry->decoder=(DecodeImageHandler *) ReadPNGImage;
6463 entry->encoder=(EncodeImageHandler *) WritePNGImage;
6466 entry->magick=(IsImageFormatHandler *) IsPNG;
6467 entry->adjoin=MagickFalse;
6468 entry->description=ConstantString(
6469 "8-bit indexed with optional binary transparency");
6470 entry->module=ConstantString("PNG");
6471 (void) RegisterMagickInfo(entry);
6473 entry=SetMagickInfo("PNG24");
6476 #if defined(ZLIB_VERSION)
6477 (void) ConcatenateMagickString(version,"zlib ",MaxTextExtent);
6478 (void) ConcatenateMagickString(version,ZLIB_VERSION,MaxTextExtent);
6480 if (LocaleCompare(ZLIB_VERSION,zlib_version) != 0)
6482 (void) ConcatenateMagickString(version,",",MaxTextExtent);
6483 (void) ConcatenateMagickString(version,zlib_version,MaxTextExtent);
6487 if (*version != '\0')
6488 entry->version=ConstantString(version);
6490 #if defined(MAGICKCORE_PNG_DELEGATE)
6491 entry->decoder=(DecodeImageHandler *) ReadPNGImage;
6492 entry->encoder=(EncodeImageHandler *) WritePNGImage;
6495 entry->magick=(IsImageFormatHandler *) IsPNG;
6496 entry->adjoin=MagickFalse;
6497 entry->description=ConstantString("opaque 24-bit RGB");
6498 entry->module=ConstantString("PNG");
6499 (void) RegisterMagickInfo(entry);
6501 entry=SetMagickInfo("PNG32");
6503 #if defined(MAGICKCORE_PNG_DELEGATE)
6504 entry->decoder=(DecodeImageHandler *) ReadPNGImage;
6505 entry->encoder=(EncodeImageHandler *) WritePNGImage;
6508 entry->magick=(IsImageFormatHandler *) IsPNG;
6509 entry->adjoin=MagickFalse;
6510 entry->description=ConstantString("opaque or transparent 32-bit RGBA");
6511 entry->module=ConstantString("PNG");
6512 (void) RegisterMagickInfo(entry);
6514 entry=SetMagickInfo("JNG");
6516 #if defined(JNG_SUPPORTED)
6517 #if defined(MAGICKCORE_PNG_DELEGATE)
6518 entry->decoder=(DecodeImageHandler *) ReadJNGImage;
6519 entry->encoder=(EncodeImageHandler *) WriteJNGImage;
6523 entry->magick=(IsImageFormatHandler *) IsJNG;
6524 entry->adjoin=MagickFalse;
6525 entry->description=ConstantString("JPEG Network Graphics");
6526 entry->module=ConstantString("PNG");
6527 entry->note=ConstantString(JNGNote);
6528 (void) RegisterMagickInfo(entry);
6530 #if defined(PNG_SETJMP_NOT_THREAD_SAFE)
6531 ping_semaphore=AllocateSemaphoreInfo();
6534 return(MagickImageCoderSignature);
6538 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6542 % U n r e g i s t e r P N G I m a g e %
6546 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6548 % UnregisterPNGImage() removes format registrations made by the
6549 % PNG module from the list of supported formats.
6551 % The format of the UnregisterPNGImage method is:
6553 % UnregisterPNGImage(void)
6556 ModuleExport void UnregisterPNGImage(void)
6558 (void) UnregisterMagickInfo("MNG");
6559 (void) UnregisterMagickInfo("PNG");
6560 (void) UnregisterMagickInfo("PNG8");
6561 (void) UnregisterMagickInfo("PNG24");
6562 (void) UnregisterMagickInfo("PNG32");
6563 (void) UnregisterMagickInfo("JNG");
6565 #if defined(PNG_SETJMP_NOT_THREAD_SAFE)
6566 if (ping_semaphore != (SemaphoreInfo *) NULL)
6567 DestroySemaphoreInfo(&ping_semaphore);
6571 #if defined(MAGICKCORE_PNG_DELEGATE)
6572 #if PNG_LIBPNG_VER > 10011
6574 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6578 % W r i t e M N G I m a g e %
6582 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6584 % WriteMNGImage() writes an image in the Portable Network Graphics
6585 % Group's "Multiple-image Network Graphics" encoded image format.
6587 % MNG support written by Glenn Randers-Pehrson, glennrp@image...
6589 % The format of the WriteMNGImage method is:
6591 % MagickBooleanType WriteMNGImage(const ImageInfo *image_info,Image *image)
6593 % A description of each parameter follows.
6595 % o image_info: the image info.
6597 % o image: The image.
6600 % To do (as of version 5.5.2, November 26, 2002 -- glennrp -- see also
6601 % "To do" under ReadPNGImage):
6603 % Preserve all unknown and not-yet-handled known chunks found in input
6604 % PNG file and copy them into output PNG files according to the PNG
6607 % Write the iCCP chunk at MNG level when (icc profile length > 0)
6609 % Improve selection of color type (use indexed-colour or indexed-colour
6610 % with tRNS when 256 or fewer unique RGBA values are present).
6612 % Figure out what to do with "dispose=<restore-to-previous>" (dispose == 3)
6613 % This will be complicated if we limit ourselves to generating MNG-LC
6614 % files. For now we ignore disposal method 3 and simply overlay the next
6617 % Check for identical PLTE's or PLTE/tRNS combinations and use a
6618 % global MNG PLTE or PLTE/tRNS combination when appropriate.
6619 % [mostly done 15 June 1999 but still need to take care of tRNS]
6621 % Check for identical sRGB and replace with a global sRGB (and remove
6622 % gAMA/cHRM if sRGB is found; check for identical gAMA/cHRM and
6623 % replace with global gAMA/cHRM (or with sRGB if appropriate; replace
6624 % local gAMA/cHRM with local sRGB if appropriate).
6626 % Check for identical sBIT chunks and write global ones.
6628 % Provide option to skip writing the signature tEXt chunks.
6630 % Use signatures to detect identical objects and reuse the first
6631 % instance of such objects instead of writing duplicate objects.
6633 % Use a smaller-than-32k value of compression window size when
6636 % Encode JNG datastreams. Mostly done as of 5.5.2; need to write
6637 % ancillary text chunks and save profiles.
6639 % Provide an option to force LC files (to ensure exact framing rate)
6642 % Provide an option to force VLC files instead of LC, even when offsets
6643 % are present. This will involve expanding the embedded images with a
6644 % transparent region at the top and/or left.
6648 Magick_png_write_raw_profile(const ImageInfo *image_info,png_struct *ping,
6649 png_info *ping_info, unsigned char *profile_type, unsigned char
6650 *profile_description, unsigned char *profile_data, png_uint_32 length)
6669 hex[16]={'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
6671 if (LocaleNCompare((char *) profile_type+1, "ng-chunk-",9) == 0)
6674 if (image_info->verbose)
6676 (void) printf("writing raw profile: type=%s, length=%.20g\n",
6677 (char *) profile_type, (double) length);
6680 text=(png_textp) png_malloc(ping,(png_uint_32) sizeof(png_text));
6681 description_length=(png_uint_32) strlen((const char *) profile_description);
6682 allocated_length=(png_uint_32) (length*2 + (length >> 5) + 20
6683 + description_length);
6684 text[0].text=(png_charp) png_malloc(ping,allocated_length);
6685 text[0].key=(png_charp) png_malloc(ping, (png_uint_32) 80);
6686 text[0].key[0]='\0';
6687 (void) ConcatenateMagickString(text[0].key,
6688 "Raw profile type ",MaxTextExtent);
6689 (void) ConcatenateMagickString(text[0].key,(const char *) profile_type,62);
6693 (void) CopyMagickString(dp,(const char *) profile_description,
6695 dp+=description_length;
6697 (void) FormatMagickString(dp,allocated_length-
6698 (png_size_t) (dp-text[0].text),"%8lu ",(unsigned long) length);
6701 for (i=0; i < (ssize_t) length; i++)
6705 *(dp++)=(char) hex[((*sp >> 4) & 0x0f)];
6706 *(dp++)=(char) hex[((*sp++ ) & 0x0f)];
6711 text[0].text_length=(png_size_t) (dp-text[0].text);
6712 text[0].compression=image_info->compression == NoCompression ||
6713 (image_info->compression == UndefinedCompression &&
6714 text[0].text_length < 128) ? -1 : 0;
6716 if (text[0].text_length <= allocated_length)
6717 png_set_text(ping,ping_info,text,1);
6719 png_free(ping,text[0].text);
6720 png_free(ping,text[0].key);
6721 png_free(ping,text);
6724 static MagickBooleanType Magick_png_write_chunk_from_profile(Image *image,
6725 const char *string, MagickBooleanType logging)
6738 ResetImageProfileIterator(image);
6740 for (name=GetNextImageProfile(image); name != (const char *) NULL; )
6742 profile=GetImageProfile(image,name);
6744 if (profile != (const StringInfo *) NULL)
6749 if (LocaleNCompare(name,string,11) == 0)
6751 if (logging != MagickFalse)
6752 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6753 " Found %s profile",name);
6755 ping_profile=CloneStringInfo(profile);
6756 data=GetStringInfoDatum(ping_profile),
6757 length=(png_uint_32) GetStringInfoLength(ping_profile);
6762 (void) WriteBlobMSBULong(image,length-5); /* data length */
6763 (void) WriteBlob(image,length-1,data+1);
6764 (void) WriteBlobMSBULong(image,crc32(0,data+1,(uInt) length-1));
6765 ping_profile=DestroyStringInfo(ping_profile);
6769 name=GetNextImageProfile(image);
6776 /* Write one PNG image */
6777 static MagickBooleanType WriteOnePNGImage(MngInfo *mng_info,
6778 const ImageInfo *IMimage_info,Image *IMimage)
6802 ping_trans_alpha[256];
6840 /* ping_exclude_iTXt, */
6847 ping_exclude_zCCP, /* hex-encoded iCCP */
6850 ping_need_colortype_warning,
6868 ping_interlace_method,
6869 ping_compression_method,
6885 number_semitransparent,
6887 ping_pHYs_unit_type;
6890 ping_pHYs_x_resolution,
6891 ping_pHYs_y_resolution;
6893 logging=LogMagickEvent(CoderEvent,GetMagickModule(),
6894 " enter WriteOnePNGImage()");
6896 image = CloneImage(IMimage,0,0,MagickFalse,&IMimage->exception);
6897 image_info=(ImageInfo *) CloneImageInfo(IMimage_info);
6899 if (mng_info->need_blob != MagickFalse)
6901 if (OpenBlob(image_info,image,WriteBinaryBlobMode,&image->exception) ==
6904 image_info=DestroyImageInfo(image_info);
6905 image=DestroyImage(image);
6906 return(MagickFalse);
6910 #if defined(PNG_SETJMP_NOT_THREAD_SAFE)
6911 LockSemaphoreInfo(ping_semaphore);
6914 /* Initialize some stuff */
6917 ping_interlace_method=0,
6918 ping_compression_method=0,
6919 ping_filter_method=0,
6922 ping_background.red = 0;
6923 ping_background.green = 0;
6924 ping_background.blue = 0;
6925 ping_background.gray = 0;
6926 ping_background.index = 0;
6928 ping_trans_color.red=0;
6929 ping_trans_color.green=0;
6930 ping_trans_color.blue=0;
6931 ping_trans_color.gray=0;
6933 ping_pHYs_unit_type = 0;
6934 ping_pHYs_x_resolution = 0;
6935 ping_pHYs_y_resolution = 0;
6937 ping_have_color=MagickTrue;
6938 ping_have_PLTE=MagickFalse;
6939 ping_have_bKGD=MagickFalse;
6940 ping_have_pHYs=MagickFalse;
6941 ping_have_tRNS=MagickFalse;
6943 ping_exclude_bKGD=mng_info->ping_exclude_bKGD;
6944 ping_exclude_cHRM=mng_info->ping_exclude_cHRM;
6945 ping_exclude_EXIF=mng_info->ping_exclude_EXIF; /* hex-encoded EXIF in zTXt */
6946 ping_exclude_gAMA=mng_info->ping_exclude_gAMA;
6947 ping_exclude_cHRM=mng_info->ping_exclude_cHRM;
6948 ping_exclude_iCCP=mng_info->ping_exclude_iCCP;
6949 /* ping_exclude_iTXt=mng_info->ping_exclude_iTXt; */
6950 ping_exclude_oFFs=mng_info->ping_exclude_oFFs;
6951 ping_exclude_pHYs=mng_info->ping_exclude_pHYs;
6952 ping_exclude_sRGB=mng_info->ping_exclude_sRGB;
6953 ping_exclude_tEXt=mng_info->ping_exclude_tEXt;
6954 ping_exclude_tRNS=mng_info->ping_exclude_tRNS;
6955 ping_exclude_vpAg=mng_info->ping_exclude_vpAg;
6956 ping_exclude_zCCP=mng_info->ping_exclude_zCCP; /* hex-encoded iCCP in zTXt */
6957 ping_exclude_zTXt=mng_info->ping_exclude_zTXt;
6959 ping_need_colortype_warning = MagickFalse;
6962 number_semitransparent = 0;
6963 number_transparent = 0;
6965 if (image->colorspace != RGBColorspace)
6966 (void) TransformImageColorspace(image,RGBColorspace);
6969 Sometimes we get PseudoClass images whose RGB values don't match
6970 the colors in the colormap. This code syncs the RGB values.
6972 if (image->depth <= 8 && image->taint && image->storage_class == PseudoClass)
6973 (void) SyncImage(image);
6975 #if (MAGICKCORE_QUANTUM_DEPTH == 8)
6976 if (image->depth > 8)
6978 if (logging != MagickFalse)
6979 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6980 " Reducing PNG bit depth to 8 since this is a Q8 build.");
6987 #if (MAGICKCORE_QUANTUM_DEPTH > 16)
6988 /* PNG does not handle depths greater than 16 so reduce it even
6991 if (image->depth > 16)
6995 #if (MAGICKCORE_QUANTUM_DEPTH >= 16)
6996 if (image->depth == 16 && mng_info->write_png_colortype != 16)
6997 if (mng_info->write_png8 || LosslessReduceDepthOK(image) != MagickFalse)
7001 #ifdef BUILD_PNG_PALETTE
7002 if (mng_info->write_png_colortype < 8 /* all */)
7005 * Sometimes we get DirectClass images that have 256 colors or fewer.
7006 * This code will build a colormap.
7008 * Also, sometimes we get PseudoClass images with an out-of-date
7009 * colormap. This code will replace the colormap with a new one.
7010 * Sometimes we get PseudoClass images that have more than 256 colors.
7011 * This code will delete the colormap and change the image to
7014 * Also we gather some information (number of opaque, transparent,
7015 * and semitransparent pixels, and whether the image has any non-gray
7016 * pixels) that we might need later. If the user wants to force
7017 * GrayAlpha or RGBA (colortype 4 or 6) we probably don't need any
7029 semitransparent[260],
7032 register IndexPacket
7035 register const PixelPacket
7038 if (logging != MagickFalse)
7039 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7040 " Enter BUILD_PALETTE:");
7042 if (logging != MagickFalse)
7044 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7045 " image->columns=%.20g",(double) image->columns);
7046 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7047 " image->rows=%.20g",(double) image->rows);
7048 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7049 " image->matte=%.20g",(double) image->matte);
7050 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7051 " image->depth=%.20g",(double) image->depth);
7053 if (image->colormap != NULL)
7055 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7056 " Original colormap:");
7057 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7058 " i (red,green,blue,opacity)");
7060 for (i=0; i < 256; i++)
7062 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7063 " %d (%d,%d,%d,%d)",
7065 (int) image->colormap[i].red,
7066 (int) image->colormap[i].green,
7067 (int) image->colormap[i].blue,
7068 (int) image->colormap[i].opacity);
7071 for (i=image->colors - 10; i < (ssize_t) image->colors; i++)
7075 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7076 " %d (%d,%d,%d,%d)",
7078 (int) image->colormap[i].red,
7079 (int) image->colormap[i].green,
7080 (int) image->colormap[i].blue,
7081 (int) image->colormap[i].opacity);
7086 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7087 " image->colors=%d",(int) image->colors);
7089 if (image->colors == 0)
7090 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7091 " (zero means unknown)");
7093 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7094 " Regenerate the colormap");
7097 exception=(&image->exception);
7099 ping_have_color=MagickFalse;
7102 for (y=0; y < (ssize_t) image->rows; y++)
7104 q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
7106 if (q == (PixelPacket *) NULL)
7109 for (x=0; x < (ssize_t) image->columns; x++)
7111 if (q->red != q->green || q->red != q->blue)
7112 ping_have_color=MagickTrue;
7114 if (q->opacity == OpaqueOpacity)
7116 if (number_opaque < 259)
7118 if (number_opaque == 0)
7121 opaque[0].opacity=OpaqueOpacity;
7125 for (i=0; i< (ssize_t) number_opaque; i++)
7127 if (IsColorEqual(opaque+i, (PixelPacket *) q))
7131 if (i == (ssize_t) number_opaque &&
7132 number_opaque < 259)
7136 opaque[i].opacity = OpaqueOpacity;
7140 else if (q->opacity == TransparentOpacity)
7142 if (number_transparent < 259)
7144 if (number_transparent == 0)
7147 ping_trans_color.red=(unsigned short)(q->red);
7148 ping_trans_color.green=(unsigned short) (q->green);
7149 ping_trans_color.blue=(unsigned short) (q->blue);
7150 ping_trans_color.gray=(unsigned short) (q->blue);
7151 number_transparent = 1;
7154 for (i=0; i< (ssize_t) number_transparent; i++)
7156 if (IsColorEqual(transparent+i, (PixelPacket *) q))
7160 if (i == (ssize_t) number_transparent &&
7161 number_transparent < 259)
7163 number_transparent++;
7164 transparent[i] = *q;
7170 if (number_semitransparent < 259)
7172 if (number_semitransparent == 0)
7174 semitransparent[0]=*q;
7175 number_semitransparent = 1;
7178 for (i=0; i< (ssize_t) number_semitransparent; i++)
7180 if (IsColorEqual(semitransparent+i,
7181 (PixelPacket *) q) &&
7182 q->opacity == semitransparent[i].opacity)
7186 if (i == (ssize_t) number_semitransparent &&
7187 number_semitransparent < 259)
7189 number_semitransparent++;
7190 semitransparent[i] = *q;
7198 image_colors=number_opaque+number_transparent+number_semitransparent;
7200 if (logging != MagickFalse)
7202 if (image_colors >= 256)
7203 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7204 " image has more than 256 colors");
7207 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7208 " image has %d colors",image_colors);
7211 if (image_colors < 257)
7217 Initialize image colormap.
7220 if (logging != MagickFalse)
7221 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7222 " Sort the new colormap");
7224 /* Sort palette, transparent first */;
7228 for (i=0; i<number_transparent; i++)
7229 colormap[n++] = transparent[i];
7231 for (i=0; i<number_semitransparent; i++)
7232 colormap[n++] = semitransparent[i];
7234 for (i=0; i<number_opaque; i++)
7235 colormap[n++] = opaque[i];
7237 if (ping_exclude_bKGD == MagickFalse)
7239 /* Add the background color to the palette, if it
7240 * isn't already there.
7242 for (i=0; i<number_opaque; i++)
7244 if (IsColorEqual(opaque+i,
7245 &image->background_color))
7249 if (number_opaque < 257 && i == number_opaque)
7251 opaque[i]=image->background_color;
7252 opaque[i].opacity = OpaqueOpacity;
7257 if ((mng_info->ping_exclude_tRNS == MagickFalse ||
7258 (number_transparent == 0 && number_semitransparent == 0)) &&
7259 (((mng_info->write_png_colortype-1) ==
7260 PNG_COLOR_TYPE_PALETTE) ||
7261 (mng_info->write_png_colortype == 0)))
7263 if (logging != MagickFalse)
7265 if (n != (ssize_t) image_colors)
7266 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7267 " image_colors (%d) and n (%d) don't match",
7270 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7271 " AcquireImageColormap");
7274 image->colors = image_colors;
7276 if (AcquireImageColormap(image,image_colors) ==
7278 ThrowWriterException(ResourceLimitError,
7279 "MemoryAllocationFailed");
7281 for (i=0; i< (ssize_t) image_colors; i++)
7282 image->colormap[i] = colormap[i];
7284 if (logging != MagickFalse)
7286 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7287 " image->colors=%d (%d)",
7288 (int) image->colors, image_colors);
7290 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7291 " Update the pixel indexes");
7294 for (y=0; y < (ssize_t) image->rows; y++)
7296 q=GetAuthenticPixels(image,0,y,image->columns,1,
7299 if (q == (PixelPacket *) NULL)
7302 indexes=GetAuthenticIndexQueue(image);
7304 for (x=0; x < (ssize_t) image->columns; x++)
7306 for (i=0; i< (ssize_t) image_colors; i++)
7308 if ((image->matte == MagickFalse ||
7309 image->colormap[i].opacity == q->opacity) &&
7310 (IsColorEqual(&image->colormap[i],(PixelPacket *) q)))
7312 indexes[x]=(IndexPacket) i;
7319 if (SyncAuthenticPixels(image,exception) == MagickFalse)
7325 if (logging != MagickFalse)
7327 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7328 " image->colors=%d", (int) image->colors);
7330 if (image->colormap != NULL)
7332 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7333 " i (red,green,blue,opacity)");
7335 for (i=0; i < (ssize_t) image->colors; i++)
7337 if (i < 300 || i >= image->colors - 10)
7339 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7340 " %d (%d,%d,%d,%d)",
7342 (int) image->colormap[i].red,
7343 (int) image->colormap[i].green,
7344 (int) image->colormap[i].blue,
7345 (int) image->colormap[i].opacity);
7350 if (logging != MagickFalse)
7352 if (number_transparent < 257)
7353 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7354 " number_transparent = %d",
7355 number_transparent);
7358 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7359 " number_transparent > 256");
7361 if (number_opaque < 257)
7362 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7363 " number_opaque = %d",
7366 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7367 " number_opaque > 256");
7369 if (number_semitransparent < 257)
7370 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7371 " number_semitransparent = %d",
7372 number_semitransparent);
7375 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7376 " number_semitransparent > 256");
7379 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7380 " Exit BUILD_PALETTE:");
7383 #endif /* BUILD_PNG_PALETTE */
7385 if (mng_info->ping_exclude_tRNS != MagickFalse &&
7386 (number_transparent != 0 || number_semitransparent != 0))
7388 int colortype=mng_info->write_png_colortype;
7390 if (ping_have_color == MagickFalse)
7391 mng_info->write_png_colortype = 5;
7394 mng_info->write_png_colortype = 7;
7396 if (colortype != 0 && mng_info->write_png_colortype != (ssize_t) colortype)
7397 ping_need_colortype_warning=MagickTrue;
7401 image_depth=image->depth;
7403 quantum_info = (QuantumInfo *) NULL;
7405 image_colors=(int) image->colors;
7406 image_matte=image->matte;
7408 mng_info->IsPalette=image->storage_class == PseudoClass &&
7409 image_colors <= 256;
7412 Allocate the PNG structures
7414 #ifdef PNG_USER_MEM_SUPPORTED
7415 ping=png_create_write_struct_2(PNG_LIBPNG_VER_STRING,image,
7416 MagickPNGErrorHandler,MagickPNGWarningHandler,(void *) NULL,
7417 (png_malloc_ptr) Magick_png_malloc,(png_free_ptr) Magick_png_free);
7420 ping=png_create_write_struct(PNG_LIBPNG_VER_STRING,image,
7421 MagickPNGErrorHandler,MagickPNGWarningHandler);
7424 if (ping == (png_struct *) NULL)
7425 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
7427 ping_info=png_create_info_struct(ping);
7429 if (ping_info == (png_info *) NULL)
7431 png_destroy_write_struct(&ping,(png_info **) NULL);
7432 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
7435 png_set_write_fn(ping,image,png_put_data,png_flush_data);
7436 ping_pixels=(unsigned char *) NULL;
7438 if (setjmp(png_jmpbuf(ping)))
7444 if (image_info->verbose)
7445 (void) printf("PNG write has failed.\n");
7447 png_destroy_write_struct(&ping,&ping_info);
7448 #if defined(PNG_SETJMP_NOT_THREAD_SAFE)
7449 UnlockSemaphoreInfo(ping_semaphore);
7451 if (mng_info->need_blob != MagickFalse)
7452 (void) CloseBlob(image);
7453 image_info=DestroyImageInfo(image_info);
7454 image=DestroyImage(image);
7455 return(MagickFalse);
7458 Prepare PNG for writing.
7460 #if defined(PNG_MNG_FEATURES_SUPPORTED)
7461 if (mng_info->write_mng)
7462 (void) png_permit_mng_features(ping,PNG_ALL_MNG_FEATURES);
7465 # ifdef PNG_WRITE_EMPTY_PLTE_SUPPORTED
7466 if (mng_info->write_mng)
7467 png_permit_empty_plte(ping,MagickTrue);
7474 ping_width=(png_uint_32) image->columns;
7475 ping_height=(png_uint_32) image->rows;
7477 if (mng_info->write_png8 || mng_info->write_png24 || mng_info->write_png32)
7480 if (mng_info->write_png_depth != 0)
7481 image_depth=mng_info->write_png_depth;
7483 /* Adjust requested depth to next higher valid depth if necessary */
7484 if (image_depth > 8)
7487 if ((image_depth > 4) && (image_depth < 8))
7490 if (image_depth == 3)
7493 if (logging != MagickFalse)
7495 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7496 " width=%.20g",(double) ping_width);
7497 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7498 " height=%.20g",(double) ping_height);
7499 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7500 " image_matte=%.20g",(double) image->matte);
7501 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7502 " image->depth=%.20g",(double) image->depth);
7503 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7504 " Tentative ping_bit_depth=%.20g",(double) image_depth);
7507 save_image_depth=image_depth;
7508 ping_bit_depth=(png_byte) save_image_depth;
7511 #if defined(PNG_pHYs_SUPPORTED)
7512 if (ping_exclude_pHYs == MagickFalse)
7514 if ((image->x_resolution != 0) && (image->y_resolution != 0) &&
7515 (!mng_info->write_mng || !mng_info->equal_physs))
7517 if (logging != MagickFalse)
7518 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7519 " Setting up pHYs chunk");
7521 if (image->units == PixelsPerInchResolution)
7523 ping_pHYs_unit_type=PNG_RESOLUTION_METER;
7524 ping_pHYs_x_resolution=(png_uint_32) (100.0*image->x_resolution/2.54);
7525 ping_pHYs_y_resolution=(png_uint_32) (100.0*image->y_resolution/2.54);
7528 else if (image->units == PixelsPerCentimeterResolution)
7530 ping_pHYs_unit_type=PNG_RESOLUTION_METER;
7531 ping_pHYs_x_resolution=(png_uint_32) (100.0*image->x_resolution);
7532 ping_pHYs_y_resolution=(png_uint_32) (100.0*image->y_resolution);
7537 ping_pHYs_unit_type=PNG_RESOLUTION_UNKNOWN;
7538 ping_pHYs_x_resolution=(png_uint_32) image->x_resolution;
7539 ping_pHYs_y_resolution=(png_uint_32) image->y_resolution;
7542 ping_have_pHYs = MagickTrue;
7547 if (ping_exclude_bKGD == MagickFalse)
7549 if ((!mng_info->adjoin || !mng_info->equal_backgrounds))
7555 if (ping_bit_depth == 8)
7558 if (ping_bit_depth == 4)
7561 if (ping_bit_depth == 2)
7564 if (ping_bit_depth == 1)
7567 ping_background.red=(png_uint_16)
7568 (ScaleQuantumToShort(image->background_color.red) & mask);
7570 ping_background.green=(png_uint_16)
7571 (ScaleQuantumToShort(image->background_color.green) & mask);
7573 ping_background.blue=(png_uint_16)
7574 (ScaleQuantumToShort(image->background_color.blue) & mask);
7577 if (logging != MagickFalse)
7579 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7580 " Setting up bKGD chunk (1)");
7582 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7583 " ping_bit_depth=%d",ping_bit_depth);
7586 ping_have_bKGD = MagickTrue;
7590 Select the color type.
7595 if (mng_info->write_png8)
7598 /* TO DO: make this a function cause it's used twice, except
7599 for reducing the sample depth from 8. */
7601 number_colors=image_colors;
7603 ping_have_tRNS=MagickFalse;
7608 ping_color_type=(png_byte) PNG_COLOR_TYPE_PALETTE;
7610 if (logging != MagickFalse)
7611 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7612 " Setting up PLTE chunk with %d colors (%d)",
7613 number_colors, image_colors);
7615 for (i=0; i < (ssize_t) number_colors; i++)
7617 palette[i].red=ScaleQuantumToChar(image->colormap[i].red);
7618 palette[i].green=ScaleQuantumToChar(image->colormap[i].green);
7619 palette[i].blue=ScaleQuantumToChar(image->colormap[i].blue);
7620 if (logging != MagickFalse)
7621 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7622 #if MAGICKCORE_QUANTUM_DEPTH == 8
7623 " %3ld (%3d,%3d,%3d)",
7625 " %5ld (%5d,%5d,%5d)",
7627 (long) i,palette[i].red,palette[i].green,palette[i].blue);
7631 ping_have_PLTE=MagickTrue;
7632 image_depth=ping_bit_depth;
7635 if (matte != MagickFalse)
7638 Identify which colormap entry is transparent.
7640 assert(number_colors <= 256);
7641 assert(image->colormap != NULL);
7643 for (i=0; i < (ssize_t) number_transparent; i++)
7644 ping_trans_alpha[i]=0;
7646 /* PNG8 can't have semitransparent colors so we threshold them
7649 for (; i < (ssize_t) number_semitransparent; i++)
7650 ping_trans_alpha[i]=image->colormap[i].opacity >
7651 OpaqueOpacity/2 ? 0 : 255;
7653 ping_num_trans=(unsigned short) (number_transparent +
7654 number_semitransparent);
7656 if (ping_num_trans == 0)
7657 ping_have_tRNS=MagickFalse;
7660 ping_have_tRNS=MagickTrue;
7663 if (ping_exclude_bKGD == MagickFalse)
7666 * Identify which colormap entry is the background color.
7668 for (i=0; i < (ssize_t) MagickMax(1L*number_colors-1L,1L); i++)
7669 if (IsPNGColorEqual(ping_background,image->colormap[i]))
7672 ping_background.index=(png_byte) i;
7674 } /* end of write_png8 */
7676 else if (mng_info->write_png24)
7678 image_matte=MagickFalse;
7679 ping_color_type=(png_byte) PNG_COLOR_TYPE_RGB;
7682 else if (mng_info->write_png32)
7684 image_matte=MagickTrue;
7685 ping_color_type=(png_byte) PNG_COLOR_TYPE_RGB_ALPHA;
7688 else /* mng_info->write_pngNN not specified */
7690 image_depth=ping_bit_depth;
7692 if (mng_info->write_png_colortype != 0)
7694 ping_color_type=(png_byte) mng_info->write_png_colortype-1;
7696 if (ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA ||
7697 ping_color_type == PNG_COLOR_TYPE_RGB_ALPHA)
7698 image_matte=MagickTrue;
7701 image_matte=MagickFalse;
7704 else /* write_ping_colortype not specified */
7706 if (logging != MagickFalse)
7707 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7708 " Selecting PNG colortype:");
7710 ping_color_type=(png_byte) ((matte != MagickFalse)?
7711 PNG_COLOR_TYPE_RGB_ALPHA:PNG_COLOR_TYPE_RGB);
7713 if (image_info->type == TrueColorType)
7715 ping_color_type=(png_byte) PNG_COLOR_TYPE_RGB;
7716 image_matte=MagickFalse;
7719 if (image_info->type == TrueColorMatteType)
7721 ping_color_type=(png_byte) PNG_COLOR_TYPE_RGB_ALPHA;
7722 image_matte=MagickTrue;
7725 if (image_info->type == PaletteType ||
7726 image_info->type == PaletteMatteType)
7727 ping_color_type=(png_byte) PNG_COLOR_TYPE_PALETTE;
7729 if (image_info->type == UndefinedType ||
7730 image_info->type == OptimizeType)
7732 if (ping_have_color == MagickFalse)
7734 if (image_matte == MagickFalse)
7736 ping_color_type=(png_byte) PNG_COLOR_TYPE_GRAY;
7737 image_matte=MagickFalse;
7742 ping_color_type=(png_byte) PNG_COLOR_TYPE_GRAY_ALPHA;
7743 image_matte=MagickTrue;
7748 if (image_matte == MagickFalse)
7750 ping_color_type=(png_byte) PNG_COLOR_TYPE_RGB;
7751 image_matte=MagickFalse;
7756 ping_color_type=(png_byte) PNG_COLOR_TYPE_RGBA;
7757 image_matte=MagickTrue;
7764 if (logging != MagickFalse)
7765 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7766 " Selected PNG colortype=%d",ping_color_type);
7768 if (ping_bit_depth < 8)
7770 if (ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA ||
7771 ping_color_type == PNG_COLOR_TYPE_RGB ||
7772 ping_color_type == PNG_COLOR_TYPE_RGB_ALPHA)
7776 old_bit_depth=ping_bit_depth;
7778 if (ping_color_type == PNG_COLOR_TYPE_GRAY)
7780 if (image->matte == MagickFalse && image->colors < 256)
7782 if (ImageIsMonochrome(image))
7789 if (ping_color_type == PNG_COLOR_TYPE_PALETTE)
7794 if (image->colors == 0)
7797 (void) ThrowMagickException(&image->exception,
7798 GetMagickModule(),CoderError,
7799 "image has 0 colors", "`%s'","");
7802 while ((int) (one << ping_bit_depth) < (ssize_t) image_colors)
7803 ping_bit_depth <<= 1;
7806 if (logging != MagickFalse)
7808 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7809 " Number of colors: %.20g",(double) image_colors);
7811 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7812 " Tentative PNG bit depth: %d",ping_bit_depth);
7815 if (ping_bit_depth < (int) mng_info->write_png_depth)
7816 ping_bit_depth = mng_info->write_png_depth;
7819 image_depth=ping_bit_depth;
7821 if (logging != MagickFalse)
7823 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7824 " Tentative PNG color type: %.20g",(double) ping_color_type);
7826 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7827 " image_info->type: %.20g",(double) image_info->type);
7829 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7830 " image_depth: %.20g",(double) image_depth);
7832 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7834 " image->depth: %.20g",(double) image->depth);
7836 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7837 " ping_bit_depth: %.20g",(double) ping_bit_depth);
7840 if (matte != MagickFalse)
7842 if (mng_info->IsPalette)
7845 ping_color_type=PNG_COLOR_TYPE_GRAY_ALPHA;
7847 if (ping_have_color != MagickFalse)
7848 ping_color_type=PNG_COLOR_TYPE_RGBA;
7851 * Determine if there is any transparent color.
7853 if (number_transparent + number_semitransparent == 0)
7856 No transparent pixels are present. Change 4 or 6 to 0 or 2.
7859 image_matte=MagickFalse;
7860 ping_color_type&=0x03;
7870 if (ping_bit_depth == 8)
7873 if (ping_bit_depth == 4)
7876 if (ping_bit_depth == 2)
7879 if (ping_bit_depth == 1)
7882 ping_trans_color.red=(png_uint_16)
7883 (ScaleQuantumToShort(image->colormap[0].red) & mask);
7885 ping_trans_color.green=(png_uint_16)
7886 (ScaleQuantumToShort(image->colormap[0].green) & mask);
7888 ping_trans_color.blue=(png_uint_16)
7889 (ScaleQuantumToShort(image->colormap[0].blue) & mask);
7891 ping_trans_color.gray=(png_uint_16)
7892 (ScaleQuantumToShort(PixelIntensityToQuantum(
7893 image->colormap)) & mask);
7895 ping_trans_color.index=(png_byte) 0;
7897 ping_have_tRNS=MagickTrue;
7900 if (ping_have_tRNS != MagickFalse)
7903 Determine if there is one and only one transparent color
7904 and if so if it is fully transparent.
7906 if (logging != MagickFalse)
7907 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7908 " Is there a single fully transparent color?");
7910 if (number_transparent > 1 || number_semitransparent > 0)
7912 ping_have_tRNS = MagickFalse;
7913 if (logging != MagickFalse)
7914 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7919 if (logging != MagickFalse)
7920 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7921 " ... Yes: (%d,%d,%d), (gray: %d)",
7922 (int) ping_trans_color.red,
7923 (int) ping_trans_color.green,
7924 (int) ping_trans_color.blue,
7925 (int) ping_trans_color.gray);
7929 if (ping_have_tRNS != MagickFalse)
7931 ping_color_type &= 0x03; /* changes 4 or 6 to 0 or 2 */
7933 if (image_depth == 8)
7935 ping_trans_color.red&=0xff;
7936 ping_trans_color.green&=0xff;
7937 ping_trans_color.blue&=0xff;
7938 ping_trans_color.gray&=0xff;
7944 if (image_depth == 8)
7946 ping_trans_color.red&=0xff;
7947 ping_trans_color.green&=0xff;
7948 ping_trans_color.blue&=0xff;
7949 ping_trans_color.gray&=0xff;
7956 if (ping_have_tRNS != MagickFalse)
7957 image_matte=MagickFalse;
7959 if ((mng_info->IsPalette) &&
7960 mng_info->write_png_colortype-1 != PNG_COLOR_TYPE_PALETTE &&
7961 ImageIsGray(image) && (image_matte == MagickFalse || image_depth >= 8))
7965 if (image_matte != MagickFalse)
7966 ping_color_type=PNG_COLOR_TYPE_GRAY_ALPHA;
7970 ping_color_type=PNG_COLOR_TYPE_GRAY;
7972 if (save_image_depth == 16 && image_depth == 8)
7974 if (logging != MagickFalse)
7976 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7977 " Scaling ping_trans_color (0)");
7979 ping_trans_color.gray*=0x0101;
7983 if (image_depth > MAGICKCORE_QUANTUM_DEPTH)
7984 image_depth=MAGICKCORE_QUANTUM_DEPTH;
7986 if (image_colors == 0 || image_colors-1 > MaxColormapSize)
7987 image_colors=(int) (one << image_depth);
7989 if (image_depth > 8)
7995 if ((int) ping_color_type == PNG_COLOR_TYPE_PALETTE)
7997 if(!mng_info->write_png_depth)
8001 while ((int) (one << ping_bit_depth)
8002 < (ssize_t) image_colors)
8003 ping_bit_depth <<= 1;
8007 else if (ping_color_type ==
8008 PNG_COLOR_TYPE_GRAY && image_colors < 17 &&
8009 mng_info->IsPalette)
8012 /* Check if grayscale is reducible */
8014 depth_4_ok=MagickTrue,
8015 depth_2_ok=MagickTrue,
8016 depth_1_ok=MagickTrue;
8018 for (i=0; i < (ssize_t) image_colors; i++)
8023 intensity=ScaleQuantumToChar(image->colormap[i].red);
8025 if ((intensity & 0x0f) != ((intensity & 0xf0) >> 4))
8026 depth_4_ok=depth_2_ok=depth_1_ok=MagickFalse;
8028 else if ((intensity & 0x03) != ((intensity & 0x0c) >> 2))
8029 depth_2_ok=depth_1_ok=MagickFalse;
8031 else if ((intensity & 0x01) != ((intensity & 0x02) >> 1))
8032 depth_1_ok=MagickFalse;
8035 if (depth_1_ok && mng_info->write_png_depth <= 1)
8038 else if (depth_2_ok && mng_info->write_png_depth <= 2)
8041 else if (depth_4_ok && mng_info->write_png_depth <= 4)
8046 image_depth=ping_bit_depth;
8051 if (mng_info->IsPalette)
8053 number_colors=image_colors;
8055 if (image_depth <= 8)
8060 ping_color_type=(png_byte) PNG_COLOR_TYPE_PALETTE;
8062 if (mng_info->have_write_global_plte && matte == MagickFalse)
8064 png_set_PLTE(ping,ping_info,NULL,0);
8066 if (logging != MagickFalse)
8067 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8068 " Setting up empty PLTE chunk");
8073 for (i=0; i < (ssize_t) number_colors; i++)
8075 palette[i].red=ScaleQuantumToChar(image->colormap[i].red);
8076 palette[i].green=ScaleQuantumToChar(image->colormap[i].green);
8077 palette[i].blue=ScaleQuantumToChar(image->colormap[i].blue);
8080 if (logging != MagickFalse)
8081 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8082 " Setting up PLTE chunk with %d colors",
8085 ping_have_PLTE=MagickTrue;
8088 /* color_type is PNG_COLOR_TYPE_PALETTE */
8089 if (mng_info->write_png_depth == 0)
8097 while ((one << ping_bit_depth) < number_colors)
8098 ping_bit_depth <<= 1;
8103 if (matte != MagickFalse)
8106 * Set up trans_colors array.
8108 assert(number_colors <= 256);
8110 ping_num_trans=(unsigned short) (number_transparent +
8111 number_semitransparent);
8113 if (ping_num_trans == 0)
8114 ping_have_tRNS=MagickFalse;
8118 if (logging != MagickFalse)
8120 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8121 " Scaling ping_trans_color (1)");
8123 ping_have_tRNS=MagickTrue;
8125 for (i=0; i < ping_num_trans; i++)
8127 ping_trans_alpha[i]= (png_byte) (255-
8128 ScaleQuantumToChar(image->colormap[i].opacity));
8138 if (image_depth < 8)
8141 if ((save_image_depth == 16) && (image_depth == 8))
8143 if (logging != MagickFalse)
8145 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8146 " Scaling ping_trans_color from (%d,%d,%d)",
8147 (int) ping_trans_color.red,
8148 (int) ping_trans_color.green,
8149 (int) ping_trans_color.blue);
8152 ping_trans_color.red*=0x0101;
8153 ping_trans_color.green*=0x0101;
8154 ping_trans_color.blue*=0x0101;
8155 ping_trans_color.gray*=0x0101;
8157 if (logging != MagickFalse)
8159 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8161 (int) ping_trans_color.red,
8162 (int) ping_trans_color.green,
8163 (int) ping_trans_color.blue);
8168 if (ping_bit_depth < (ssize_t) mng_info->write_png_depth)
8169 ping_bit_depth = (ssize_t) mng_info->write_png_depth;
8172 Adjust background and transparency samples in sub-8-bit grayscale files.
8174 if (ping_bit_depth < 8 && ping_color_type ==
8175 PNG_COLOR_TYPE_GRAY)
8183 maxval=(png_uint_16) ((one << ping_bit_depth)-1);
8185 if (ping_exclude_bKGD == MagickFalse)
8188 ping_background.gray=(png_uint_16)
8189 (QuantumScale*(maxval*(PixelIntensity(&image->background_color))));
8191 if (logging != MagickFalse)
8192 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8193 " Setting up bKGD chunk (2)");
8195 ping_have_bKGD = MagickTrue;
8198 ping_trans_color.gray=(png_uint_16) (QuantumScale*(maxval*
8199 ping_trans_color.gray));
8202 if (ping_exclude_bKGD == MagickFalse)
8204 if ((int) ping_color_type == PNG_COLOR_TYPE_PALETTE)
8207 Identify which colormap entry is the background color.
8210 number_colors=image_colors;
8212 for (i=0; i < (ssize_t) MagickMax(1L*number_colors,1L); i++)
8213 if (IsPNGColorEqual(image->background_color,image->colormap[i]))
8216 ping_background.index=(png_byte) i;
8218 if (logging != MagickFalse)
8220 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8221 " Setting up bKGD chunk with index=%d",(int) i);
8224 if (i < (ssize_t) number_colors)
8226 ping_have_bKGD = MagickTrue;
8228 if (logging != MagickFalse)
8230 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8231 " background =(%d,%d,%d)",
8232 (int) ping_background.red,
8233 (int) ping_background.green,
8234 (int) ping_background.blue);
8238 else /* Can't happen */
8240 if (logging != MagickFalse)
8241 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8242 " No room in PLTE to add bKGD color");
8243 ping_have_bKGD = MagickFalse;
8248 if (logging != MagickFalse)
8249 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8250 " PNG color type: %d",ping_color_type);
8252 Initialize compression level and filtering.
8254 if (logging != MagickFalse)
8256 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8257 " Setting up deflate compression");
8259 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8260 " Compression buffer size: 32768");
8263 png_set_compression_buffer_size(ping,32768L);
8265 if (logging != MagickFalse)
8266 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8267 " Compression mem level: 9");
8269 png_set_compression_mem_level(ping, 9);
8271 quality=image->quality == UndefinedCompressionQuality ? 75UL :
8279 level=(int) MagickMin((ssize_t) quality/10,9);
8281 if (logging != MagickFalse)
8282 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8283 " Compression level: %d",level);
8285 png_set_compression_level(ping,level);
8290 if (logging != MagickFalse)
8291 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8292 " Compression strategy: Z_HUFFMAN_ONLY");
8294 png_set_compression_strategy(ping, Z_HUFFMAN_ONLY);
8297 if (logging != MagickFalse)
8298 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8299 " Setting up filtering");
8301 #if defined(PNG_MNG_FEATURES_SUPPORTED) && defined(PNG_INTRAPIXEL_DIFFERENCING)
8302 /* This became available in libpng-1.0.9. Output must be a MNG. */
8303 if (mng_info->write_mng && ((quality % 10) == 7))
8305 if (logging != MagickFalse)
8306 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8307 " Filter_type: PNG_INTRAPIXEL_DIFFERENCING");
8309 ping_filter_method=PNG_INTRAPIXEL_DIFFERENCING;
8313 if (logging != MagickFalse)
8314 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8322 if ((quality % 10) > 5)
8323 base_filter=PNG_ALL_FILTERS;
8326 if ((quality % 10) != 5)
8327 base_filter=(int) quality % 10;
8330 if (((int) ping_color_type == PNG_COLOR_TYPE_GRAY) ||
8331 ((int) ping_color_type == PNG_COLOR_TYPE_PALETTE) ||
8333 base_filter=PNG_NO_FILTERS;
8336 base_filter=PNG_ALL_FILTERS;
8338 if (logging != MagickFalse)
8340 if (base_filter == PNG_ALL_FILTERS)
8341 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8342 " Base filter method: ADAPTIVE");
8344 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8345 " Base filter method: NONE");
8348 png_set_filter(ping,PNG_FILTER_TYPE_BASE,base_filter);
8351 if (ping_exclude_iCCP == MagickFalse || ping_exclude_zCCP == MagickFalse)
8353 ResetImageProfileIterator(image);
8354 for (name=GetNextImageProfile(image); name != (const char *) NULL; )
8356 profile=GetImageProfile(image,name);
8358 if (profile != (StringInfo *) NULL)
8360 #ifdef PNG_WRITE_iCCP_SUPPORTED
8361 if ((LocaleCompare(name,"ICC") == 0) ||
8362 (LocaleCompare(name,"ICM") == 0))
8365 if (ping_exclude_iCCP == MagickFalse)
8367 png_set_iCCP(ping,ping_info,(const png_charp) name,0,
8368 #if (PNG_LIBPNG_VER < 10500)
8369 (png_charp) GetStringInfoDatum(profile),
8371 (png_const_bytep) GetStringInfoDatum(profile),
8373 (png_uint_32) GetStringInfoLength(profile));
8379 if (ping_exclude_zCCP == MagickFalse)
8381 Magick_png_write_raw_profile(image_info,ping,ping_info,
8382 (unsigned char *) name,(unsigned char *) name,
8383 GetStringInfoDatum(profile),
8384 (png_uint_32) GetStringInfoLength(profile));
8388 if (logging != MagickFalse)
8389 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8390 " Setting up text chunk with %s profile",name);
8392 name=GetNextImageProfile(image);
8396 #if defined(PNG_WRITE_sRGB_SUPPORTED)
8397 if ((mng_info->have_write_global_srgb == 0) &&
8398 ((image->rendering_intent != UndefinedIntent) ||
8399 (image->colorspace == sRGBColorspace)))
8401 if (ping_exclude_sRGB == MagickFalse)
8404 Note image rendering intent.
8406 if (logging != MagickFalse)
8407 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8408 " Setting up sRGB chunk");
8410 (void) png_set_sRGB(ping,ping_info,(
8411 Magick_RenderingIntent_to_PNG_RenderingIntent(
8412 image->rendering_intent)));
8414 if (ping_exclude_gAMA == MagickFalse)
8415 png_set_gAMA(ping,ping_info,0.45455);
8419 if ((!mng_info->write_mng) || (!png_get_valid(ping,ping_info,PNG_INFO_sRGB)))
8422 if (ping_exclude_gAMA == MagickFalse &&
8423 (ping_exclude_sRGB == MagickFalse ||
8424 (image->gamma < .45 || image->gamma > .46)))
8426 if ((mng_info->have_write_global_gama == 0) && (image->gamma != 0.0))
8430 To do: check for cHRM+gAMA == sRGB, and write sRGB instead.
8432 if (logging != MagickFalse)
8433 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8434 " Setting up gAMA chunk");
8436 png_set_gAMA(ping,ping_info,image->gamma);
8440 if (ping_exclude_cHRM == MagickFalse)
8442 if ((mng_info->have_write_global_chrm == 0) &&
8443 (image->chromaticity.red_primary.x != 0.0))
8446 Note image chromaticity.
8447 To do: check for cHRM+gAMA == sRGB, and write sRGB instead.
8455 wp=image->chromaticity.white_point;
8456 rp=image->chromaticity.red_primary;
8457 gp=image->chromaticity.green_primary;
8458 bp=image->chromaticity.blue_primary;
8460 if (logging != MagickFalse)
8461 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8462 " Setting up cHRM chunk");
8464 png_set_cHRM(ping,ping_info,wp.x,wp.y,rp.x,rp.y,gp.x,gp.y,
8470 ping_interlace_method=image_info->interlace != NoInterlace;
8472 if (mng_info->write_mng)
8473 png_set_sig_bytes(ping,8);
8475 /* Bail out if cannot meet defined PNG:bit-depth or PNG:color-type */
8477 if (mng_info->write_png_colortype != 0)
8479 if (mng_info->write_png_colortype-1 == PNG_COLOR_TYPE_GRAY)
8480 if (ImageIsGray(image) == MagickFalse)
8482 ping_color_type = PNG_COLOR_TYPE_RGB;
8484 if (ping_bit_depth < 8)
8488 if (mng_info->write_png_colortype-1 == PNG_COLOR_TYPE_GRAY_ALPHA)
8489 if (ImageIsGray(image) == MagickFalse)
8490 ping_color_type = PNG_COLOR_TYPE_RGB_ALPHA;
8493 if (ping_need_colortype_warning != MagickFalse ||
8494 ((mng_info->write_png_depth &&
8495 (int) mng_info->write_png_depth != ping_bit_depth) ||
8496 (mng_info->write_png_colortype &&
8497 ((int) mng_info->write_png_colortype-1 != ping_color_type &&
8498 mng_info->write_png_colortype != 7 &&
8499 !(mng_info->write_png_colortype == 5 && ping_color_type == 0)))))
8501 if (logging != MagickFalse)
8503 if (ping_need_colortype_warning != MagickFalse)
8505 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8506 " Image has transparency but tRNS chunk was excluded");
8509 if (mng_info->write_png_depth)
8511 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8512 " Defined PNG:bit-depth=%u, Computed depth=%u",
8513 mng_info->write_png_depth,
8517 if (mng_info->write_png_colortype)
8519 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8520 " Defined PNG:color-type=%u, Computed color type=%u",
8521 mng_info->write_png_colortype-1,
8527 "Cannot write image with defined PNG:bit-depth or PNG:color-type.");
8530 if (image_matte != MagickFalse && image->matte == MagickFalse)
8532 /* Add an opaque matte channel */
8533 image->matte = MagickTrue;
8534 (void) SetImageOpacity(image,0);
8536 if (logging != MagickFalse)
8537 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8538 " Added an opaque matte channel");
8541 if (number_transparent != 0 || number_semitransparent != 0)
8543 if (ping_color_type < 4)
8545 ping_have_tRNS=MagickTrue;
8546 if (logging != MagickFalse)
8547 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8548 " Setting ping_have_tRNS=MagickTrue.");
8552 if (logging != MagickFalse)
8553 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8554 " Writing PNG header chunks");
8556 png_set_IHDR(ping,ping_info,ping_width,ping_height,
8557 ping_bit_depth,ping_color_type,
8558 ping_interlace_method,ping_compression_method,
8559 ping_filter_method);
8561 if (ping_color_type == 3 && ping_have_PLTE != MagickFalse)
8563 png_set_PLTE(ping,ping_info,palette,number_colors);
8565 if (logging != MagickFalse)
8567 for (i=0; i< (ssize_t) number_colors; i++)
8569 if (i < ping_num_trans)
8570 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8571 " PLTE[%d] = (%d,%d,%d), tRNS[%d] = (%d)",
8573 (int) palette[i].red,
8574 (int) palette[i].green,
8575 (int) palette[i].blue,
8577 (int) ping_trans_alpha[i]);
8579 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8580 " PLTE[%d] = (%d,%d,%d)",
8582 (int) palette[i].red,
8583 (int) palette[i].green,
8584 (int) palette[i].blue);
8589 if (ping_exclude_bKGD == MagickFalse)
8591 if (ping_have_bKGD != MagickFalse)
8592 png_set_bKGD(ping,ping_info,&ping_background);
8595 if (ping_exclude_pHYs == MagickFalse)
8597 if (ping_have_pHYs != MagickFalse)
8599 png_set_pHYs(ping,ping_info,
8600 ping_pHYs_x_resolution,
8601 ping_pHYs_y_resolution,
8602 ping_pHYs_unit_type);
8606 #if defined(PNG_oFFs_SUPPORTED)
8607 if (ping_exclude_oFFs == MagickFalse)
8609 if (image->page.x || image->page.y)
8611 png_set_oFFs(ping,ping_info,(png_int_32) image->page.x,
8612 (png_int_32) image->page.y, 0);
8614 if (logging != MagickFalse)
8615 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8616 " Setting up oFFs chunk with x=%d, y=%d, units=0",
8617 (int) image->page.x, (int) image->page.y);
8622 png_write_info_before_PLTE(ping, ping_info);
8624 if (ping_have_tRNS != MagickFalse && ping_color_type < 4)
8626 if (logging != MagickFalse)
8628 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8629 " Calling png_set_tRNS with num_trans=%d",ping_num_trans);
8632 if (ping_color_type == 3)
8633 (void) png_set_tRNS(ping, ping_info,
8640 (void) png_set_tRNS(ping, ping_info,
8645 if (logging != MagickFalse)
8647 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8648 " tRNS color =(%d,%d,%d)",
8649 (int) ping_trans_color.red,
8650 (int) ping_trans_color.green,
8651 (int) ping_trans_color.blue);
8656 /* write any png-chunk-b profiles */
8657 (void) Magick_png_write_chunk_from_profile(image,"PNG-chunk-b",logging);
8658 png_write_info(ping,ping_info);
8660 /* write any PNG-chunk-m profiles */
8661 (void) Magick_png_write_chunk_from_profile(image,"PNG-chunk-m",logging);
8663 if (ping_exclude_vpAg == MagickFalse)
8665 if ((image->page.width != 0 && image->page.width != image->columns) ||
8666 (image->page.height != 0 && image->page.height != image->rows))
8671 (void) WriteBlobMSBULong(image,9L); /* data length=8 */
8672 PNGType(chunk,mng_vpAg);
8673 LogPNGChunk(logging,mng_vpAg,9L);
8674 PNGLong(chunk+4,(png_uint_32) image->page.width);
8675 PNGLong(chunk+8,(png_uint_32) image->page.height);
8676 chunk[12]=0; /* unit = pixels */
8677 (void) WriteBlob(image,13,chunk);
8678 (void) WriteBlobMSBULong(image,crc32(0,chunk,13));
8682 #if (PNG_LIBPNG_VER == 10206)
8683 /* avoid libpng-1.2.6 bug by setting PNG_HAVE_IDAT flag */
8684 #define PNG_HAVE_IDAT 0x04
8685 ping->mode |= PNG_HAVE_IDAT;
8686 #undef PNG_HAVE_IDAT
8689 png_set_packing(ping);
8693 rowbytes=image->columns;
8694 if (image_depth > 8)
8696 switch (ping_color_type)
8698 case PNG_COLOR_TYPE_RGB:
8702 case PNG_COLOR_TYPE_GRAY_ALPHA:
8706 case PNG_COLOR_TYPE_RGBA:
8714 if (logging != MagickFalse)
8716 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8717 " Writing PNG image data");
8719 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8720 " Allocating %.20g bytes of memory for pixels",(double) rowbytes);
8722 ping_pixels=(unsigned char *) AcquireQuantumMemory(rowbytes,
8723 sizeof(*ping_pixels));
8725 if (ping_pixels == (unsigned char *) NULL)
8726 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
8729 Initialize image scanlines.
8731 if (setjmp(png_jmpbuf(ping)))
8737 if (image_info->verbose)
8738 (void) printf("PNG write has failed.\n");
8740 png_destroy_write_struct(&ping,&ping_info);
8741 if (quantum_info != (QuantumInfo *) NULL)
8742 quantum_info=DestroyQuantumInfo(quantum_info);
8743 if (ping_pixels != (unsigned char *) NULL)
8744 ping_pixels=(unsigned char *) RelinquishMagickMemory(ping_pixels);
8745 #if defined(PNG_SETJMP_NOT_THREAD_SAFE)
8746 UnlockSemaphoreInfo(ping_semaphore);
8748 if (mng_info->need_blob != MagickFalse)
8749 (void) CloseBlob(image);
8750 image_info=DestroyImageInfo(image_info);
8751 image=DestroyImage(image);
8752 return(MagickFalse);
8754 quantum_info=AcquireQuantumInfo(image_info,image);
8755 if (quantum_info == (QuantumInfo *) NULL)
8756 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
8757 quantum_info->format=UndefinedQuantumFormat;
8758 quantum_info->depth=image_depth;
8759 num_passes=png_set_interlace_handling(ping);
8761 if ((!mng_info->write_png8 && !mng_info->write_png24 &&
8762 !mng_info->write_png32) &&
8763 (mng_info->IsPalette ||
8764 (image_info->type == BilevelType)) &&
8765 image_matte == MagickFalse && ImageIsMonochrome(image))
8767 /* Palette, Bilevel, or Opaque Monochrome */
8768 register const PixelPacket
8771 quantum_info->depth=8;
8772 for (pass=0; pass < num_passes; pass++)
8775 Convert PseudoClass image to a PNG monochrome image.
8777 for (y=0; y < (ssize_t) image->rows; y++)
8780 if (logging != MagickFalse)
8781 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8782 " Writing row of pixels (0)");
8784 p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception);
8786 if (p == (const PixelPacket *) NULL)
8789 if (mng_info->IsPalette)
8791 (void) ExportQuantumPixels(image,(const CacheView *) NULL,
8792 quantum_info,GrayQuantum,ping_pixels,&image->exception);
8793 if (mng_info->write_png_colortype-1 == PNG_COLOR_TYPE_PALETTE &&
8794 mng_info->write_png_depth &&
8795 mng_info->write_png_depth != old_bit_depth)
8797 /* Undo pixel scaling */
8798 for (i=0; i < (ssize_t) image->columns; i++)
8799 *(ping_pixels+i)=(unsigned char) (*(ping_pixels+i)
8800 >> (8-old_bit_depth));
8806 (void) ExportQuantumPixels(image,(const CacheView *) NULL,
8807 quantum_info,RedQuantum,ping_pixels,&image->exception);
8810 if (mng_info->write_png_colortype-1 != PNG_COLOR_TYPE_PALETTE)
8811 for (i=0; i < (ssize_t) image->columns; i++)
8812 *(ping_pixels+i)=(unsigned char) ((*(ping_pixels+i) > 127) ?
8815 if (logging != MagickFalse && y == 0)
8816 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8817 " Writing row of pixels (1)");
8819 png_write_row(ping,ping_pixels);
8821 if (image->previous == (Image *) NULL)
8823 status=SetImageProgress(image,LoadImageTag,pass,num_passes);
8824 if (status == MagickFalse)
8830 else /* Not Palette, Bilevel, or Opaque Monochrome */
8832 if ((!mng_info->write_png8 && !mng_info->write_png24 &&
8833 !mng_info->write_png32) &&
8834 (image_matte != MagickFalse ||
8835 (ping_bit_depth >= MAGICKCORE_QUANTUM_DEPTH)) &&
8836 (mng_info->IsPalette) && ImageIsGray(image))
8838 register const PixelPacket
8841 for (pass=0; pass < num_passes; pass++)
8844 for (y=0; y < (ssize_t) image->rows; y++)
8846 p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception);
8848 if (p == (const PixelPacket *) NULL)
8851 if (ping_color_type == PNG_COLOR_TYPE_GRAY)
8853 if (mng_info->IsPalette)
8854 (void) ExportQuantumPixels(image,(const CacheView *) NULL,
8855 quantum_info,GrayQuantum,ping_pixels,&image->exception);
8858 (void) ExportQuantumPixels(image,(const CacheView *) NULL,
8859 quantum_info,RedQuantum,ping_pixels,&image->exception);
8861 if (logging != MagickFalse && y == 0)
8862 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8863 " Writing GRAY PNG pixels (2)");
8866 else /* PNG_COLOR_TYPE_GRAY_ALPHA */
8868 if (logging != MagickFalse && y == 0)
8869 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8870 " Writing GRAY_ALPHA PNG pixels (2)");
8872 (void) ExportQuantumPixels(image,(const CacheView *) NULL,
8873 quantum_info,GrayAlphaQuantum,ping_pixels,&image->exception);
8876 if (logging != MagickFalse && y == 0)
8877 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8878 " Writing row of pixels (2)");
8880 png_write_row(ping,ping_pixels);
8883 if (image->previous == (Image *) NULL)
8885 status=SetImageProgress(image,LoadImageTag,pass,num_passes);
8886 if (status == MagickFalse)
8894 register const PixelPacket
8897 for (pass=0; pass < num_passes; pass++)
8899 if ((image_depth > 8) || (mng_info->write_png24 ||
8900 mng_info->write_png32 ||
8901 (!mng_info->write_png8 && !mng_info->IsPalette)))
8903 for (y=0; y < (ssize_t) image->rows; y++)
8905 p=GetVirtualPixels(image,0,y,image->columns,1,
8908 if (p == (const PixelPacket *) NULL)
8911 if (ping_color_type == PNG_COLOR_TYPE_GRAY)
8913 if (image->storage_class == DirectClass)
8914 (void) ExportQuantumPixels(image,(const CacheView *) NULL,
8915 quantum_info,RedQuantum,ping_pixels,&image->exception);
8918 (void) ExportQuantumPixels(image,(const CacheView *) NULL,
8919 quantum_info,GrayQuantum,ping_pixels,&image->exception);
8922 else if (ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
8924 (void) ExportQuantumPixels(image,(const CacheView *) NULL,
8925 quantum_info,GrayAlphaQuantum,ping_pixels,
8928 if (logging != MagickFalse && y == 0)
8929 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8930 " Writing GRAY_ALPHA PNG pixels (3)");
8933 else if (image_matte != MagickFalse)
8934 (void) ExportQuantumPixels(image,(const CacheView *) NULL,
8935 quantum_info,RGBAQuantum,ping_pixels,&image->exception);
8938 (void) ExportQuantumPixels(image,(const CacheView *) NULL,
8939 quantum_info,RGBQuantum,ping_pixels,&image->exception);
8941 if (logging != MagickFalse && y == 0)
8942 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8943 " Writing row of pixels (3)");
8945 png_write_row(ping,ping_pixels);
8950 /* not ((image_depth > 8) || (mng_info->write_png24 ||
8951 mng_info->write_png32 ||
8952 (!mng_info->write_png8 && !mng_info->IsPalette))) */
8954 if ((ping_color_type != PNG_COLOR_TYPE_GRAY) &&
8955 (ping_color_type != PNG_COLOR_TYPE_GRAY_ALPHA))
8957 if (logging != MagickFalse)
8958 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8959 " pass %d, Image Is not GRAY or GRAY_ALPHA",pass);
8961 quantum_info->depth=8;
8965 for (y=0; y < (ssize_t) image->rows; y++)
8967 if (logging != MagickFalse && y == 0)
8968 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8969 " pass %d, Image Is RGB, 16-bit GRAY, or GRAY_ALPHA",pass);
8971 p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception);
8973 if (p == (const PixelPacket *) NULL)
8976 if (ping_color_type == PNG_COLOR_TYPE_GRAY)
8977 (void) ExportQuantumPixels(image,(const CacheView *) NULL,
8978 quantum_info,GrayQuantum,ping_pixels,&image->exception);
8980 else if (ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
8982 if (logging != MagickFalse && y == 0)
8983 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8984 " Writing GRAY_ALPHA PNG pixels (4)");
8986 (void) ExportQuantumPixels(image,(const CacheView *) NULL,
8987 quantum_info,GrayAlphaQuantum,ping_pixels,
8992 (void) ExportQuantumPixels(image,(const CacheView *) NULL,
8993 quantum_info,IndexQuantum,ping_pixels,&image->exception);
8995 if (logging != MagickFalse && y <= 2)
8997 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8998 " Writing row of pixels (4)");
9000 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9001 " ping_pixels[0]=%d,ping_pixels[1]=%d",
9002 (int)ping_pixels[0],(int)ping_pixels[1]);
9004 png_write_row(ping,ping_pixels);
9008 if (image->previous == (Image *) NULL)
9010 status=SetImageProgress(image,LoadImageTag,pass,num_passes);
9011 if (status == MagickFalse)
9018 if (quantum_info != (QuantumInfo *) NULL)
9019 quantum_info=DestroyQuantumInfo(quantum_info);
9021 if (logging != MagickFalse)
9023 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9024 " Wrote PNG image data");
9026 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9027 " Width: %.20g",(double) ping_width);
9029 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9030 " Height: %.20g",(double) ping_height);
9032 if (mng_info->write_png_depth)
9034 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9035 " Defined PNG:bit-depth: %d",mng_info->write_png_depth);
9038 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9039 " PNG bit-depth written: %d",ping_bit_depth);
9041 if (mng_info->write_png_colortype)
9043 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9044 " Defined PNG:color-type: %d",mng_info->write_png_colortype-1);
9047 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9048 " PNG color-type written: %d",ping_color_type);
9050 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9051 " PNG Interlace method: %d",ping_interlace_method);
9054 Generate text chunks.
9056 if (ping_exclude_tEXt == MagickFalse && ping_exclude_zTXt == MagickFalse)
9058 ResetImagePropertyIterator(image);
9059 property=GetNextImageProperty(image);
9060 while (property != (const char *) NULL)
9065 value=GetImageProperty(image,property);
9066 if (value != (const char *) NULL)
9068 text=(png_textp) png_malloc(ping,(png_uint_32) sizeof(png_text));
9069 text[0].key=(char *) property;
9070 text[0].text=(char *) value;
9071 text[0].text_length=strlen(value);
9073 if (ping_exclude_tEXt != MagickFalse)
9074 text[0].compression=PNG_TEXT_COMPRESSION_zTXt;
9076 else if (ping_exclude_zTXt != MagickFalse)
9077 text[0].compression=PNG_TEXT_COMPRESSION_NONE;
9081 text[0].compression=image_info->compression == NoCompression ||
9082 (image_info->compression == UndefinedCompression &&
9083 text[0].text_length < 128) ? PNG_TEXT_COMPRESSION_NONE :
9084 PNG_TEXT_COMPRESSION_zTXt ;
9087 if (logging != MagickFalse)
9089 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9090 " Setting up text chunk");
9092 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9093 " keyword: %s",text[0].key);
9096 png_set_text(ping,ping_info,text,1);
9097 png_free(ping,text);
9099 property=GetNextImageProperty(image);
9103 /* write any PNG-chunk-e profiles */
9104 (void) Magick_png_write_chunk_from_profile(image,"PNG-chunk-e",logging);
9106 if (logging != MagickFalse)
9107 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9108 " Writing PNG end info");
9110 png_write_end(ping,ping_info);
9112 if (mng_info->need_fram && (int) image->dispose == BackgroundDispose)
9114 if (mng_info->page.x || mng_info->page.y ||
9115 (ping_width != mng_info->page.width) ||
9116 (ping_height != mng_info->page.height))
9122 Write FRAM 4 with clipping boundaries followed by FRAM 1.
9124 (void) WriteBlobMSBULong(image,27L); /* data length=27 */
9125 PNGType(chunk,mng_FRAM);
9126 LogPNGChunk(logging,mng_FRAM,27L);
9128 chunk[5]=0; /* frame name separator (no name) */
9129 chunk[6]=1; /* flag for changing delay, for next frame only */
9130 chunk[7]=0; /* flag for changing frame timeout */
9131 chunk[8]=1; /* flag for changing frame clipping for next frame */
9132 chunk[9]=0; /* flag for changing frame sync_id */
9133 PNGLong(chunk+10,(png_uint_32) (0L)); /* temporary 0 delay */
9134 chunk[14]=0; /* clipping boundaries delta type */
9135 PNGLong(chunk+15,(png_uint_32) (mng_info->page.x)); /* left cb */
9137 (png_uint_32) (mng_info->page.x + ping_width));
9138 PNGLong(chunk+23,(png_uint_32) (mng_info->page.y)); /* top cb */
9140 (png_uint_32) (mng_info->page.y + ping_height));
9141 (void) WriteBlob(image,31,chunk);
9142 (void) WriteBlobMSBULong(image,crc32(0,chunk,31));
9143 mng_info->old_framing_mode=4;
9144 mng_info->framing_mode=1;
9148 mng_info->framing_mode=3;
9150 if (mng_info->write_mng && !mng_info->need_fram &&
9151 ((int) image->dispose == 3))
9152 (void) ThrowMagickException(&image->exception,GetMagickModule(),
9153 CoderError,"Cannot convert GIF with disposal method 3 to MNG-LC",
9154 "`%s'",image->filename);
9160 png_destroy_write_struct(&ping,&ping_info);
9162 ping_pixels=(unsigned char *) RelinquishMagickMemory(ping_pixels);
9164 #if defined(PNG_SETJMP_NOT_THREAD_SAFE)
9165 UnlockSemaphoreInfo(ping_semaphore);
9168 if (mng_info->need_blob != MagickFalse)
9169 (void) CloseBlob(image);
9171 image_info=DestroyImageInfo(image_info);
9172 image=DestroyImage(image);
9174 /* Store bit depth actually written */
9175 s[0]=(char) ping_bit_depth;
9178 (void) SetImageProperty(IMimage,"png:bit-depth-written",s);
9180 if (logging != MagickFalse)
9181 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9182 " exit WriteOnePNGImage()");
9185 /* End write one PNG image */
9189 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
9193 % W r i t e P N G I m a g e %
9197 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
9199 % WritePNGImage() writes a Portable Network Graphics (PNG) or
9200 % Multiple-image Network Graphics (MNG) image file.
9202 % MNG support written by Glenn Randers-Pehrson, glennrp@image...
9204 % The format of the WritePNGImage method is:
9206 % MagickBooleanType WritePNGImage(const ImageInfo *image_info,Image *image)
9208 % A description of each parameter follows:
9210 % o image_info: the image info.
9212 % o image: The image.
9214 % Returns MagickTrue on success, MagickFalse on failure.
9216 % Communicating with the PNG encoder:
9218 % While the datastream written is always in PNG format and normally would
9219 % be given the "png" file extension, this method also writes the following
9220 % pseudo-formats which are subsets of PNG:
9222 % o PNG8: An 8-bit indexed PNG datastream is written. If transparency
9223 % is present, the tRNS chunk must only have values 0 and 255
9224 % (i.e., transparency is binary: fully opaque or fully
9225 % transparent). The pixels contain 8-bit indices even if
9226 % they could be represented with 1, 2, or 4 bits. Note: grayscale
9227 % images will be written as indexed PNG files even though the
9228 % PNG grayscale type might be slightly more efficient.
9230 % o PNG24: An 8-bit per sample RGB PNG datastream is written. The tRNS
9231 % chunk can be present to convey binary transparency by naming
9232 % one of the colors as transparent.
9234 % o PNG32: An 8-bit per sample RGBA PNG is written. Partial
9235 % transparency is permitted, i.e., the alpha sample for
9236 % each pixel can have any value from 0 to 255. The alpha
9237 % channel is present even if the image is fully opaque.
9239 % o -define: For more precise control of the PNG output, you can use the
9240 % Image options "png:bit-depth" and "png:color-type". These
9241 % can be set from the commandline with "-define" and also
9242 % from the application programming interfaces. The options
9243 % are case-independent and are converted to lowercase before
9244 % being passed to this encoder.
9246 % png:color-type can be 0, 2, 3, 4, or 6.
9248 % When png:color-type is 0 (Grayscale), png:bit-depth can
9249 % be 1, 2, 4, 8, or 16.
9251 % When png:color-type is 2 (RGB), png:bit-depth can
9254 % When png:color-type is 3 (Indexed), png:bit-depth can
9255 % be 1, 2, 4, or 8. This refers to the number of bits
9256 % used to store the index. The color samples always have
9257 % bit-depth 8 in indexed PNG files.
9259 % When png:color-type is 4 (Gray-Matte) or 6 (RGB-Matte),
9260 % png:bit-depth can be 8 or 16.
9262 % If the image cannot be written without loss in the requested PNG8, PNG24,
9263 % or PNG32 format or with the requested bit-depth and color-type without loss,
9264 % a PNG file will not be written, and the encoder will return MagickFalse.
9265 % Since image encoders should not be responsible for the "heavy lifting",
9266 % the user should make sure that ImageMagick has already reduced the
9267 % image depth and number of colors and limit transparency to binary
9268 % transparency prior to attempting to write the image in a format that
9269 % is subject to depth, color, or transparency limitations.
9271 % TODO: Enforce the previous paragraph.
9273 % Note that another definition, "png:bit-depth-written" exists, but it
9274 % is not intended for external use. It is only used internally by the
9275 % PNG encoder to inform the JNG encoder of the depth of the alpha channel.
9277 % It is possible to request that the PNG encoder write previously-formatted
9278 % ancillary chunks in the output PNG file, using the "-profile" commandline
9279 % option as shown below or by setting the profile via a programming
9282 % -profile PNG-chunk-x:<file>
9284 % where x is a location flag and <file> is a file containing the chunk
9285 % name in the first 4 bytes, then a colon (":"), followed by the chunk data.
9286 % This encoder will compute the chunk length and CRC, so those must not
9287 % be included in the file.
9289 % "x" can be "b" (before PLTE), "m" (middle, i.e., between PLTE and IDAT),
9290 % or "e" (end, i.e., after IDAT). If you want to write multiple chunks
9291 % of the same type, then add a short unique string after the "x" to prevent
9292 % subsequent profiles from overwriting the preceding ones, e.g.,
9294 % -profile PNG-chunk-b01:file01 -profile PNG-chunk-b02:file02
9296 % As of version 6.6.6 the following optimizations are always done:
9298 % o 32-bit depth is reduced to 16.
9299 % o 16-bit depth is reduced to 8 if all pixels contain samples whose
9300 % high byte and low byte are identical.
9301 % o Palette is sorted to remove unused entries and to put a
9302 % transparent color first, if BUILD_PNG_PALETTE is defined.
9303 % o Opaque matte channel is removed when writing an indexed PNG.
9304 % o Grayscale images are reduced to 1, 2, or 4 bit depth if
9305 % this can be done without loss and a larger bit depth N was not
9306 % requested via the "-define PNG:bit-depth=N" option.
9307 % o If matte channel is present but only one transparent color is
9308 % present, RGB+tRNS is written instead of RGBA
9309 % o Opaque matte channel is removed (or added, if color-type 4 or 6
9310 % was requested when converting an opaque image).
9312 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
9314 static MagickBooleanType WritePNGImage(const ImageInfo *image_info,
9336 assert(image_info != (const ImageInfo *) NULL);
9337 assert(image_info->signature == MagickSignature);
9338 assert(image != (Image *) NULL);
9339 assert(image->signature == MagickSignature);
9340 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
9341 logging=LogMagickEvent(CoderEvent,GetMagickModule(),"enter WritePNGImage()");
9343 Allocate a MngInfo structure.
9345 have_mng_structure=MagickFalse;
9346 mng_info=(MngInfo *) AcquireMagickMemory(sizeof(MngInfo));
9348 if (mng_info == (MngInfo *) NULL)
9349 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
9352 Initialize members of the MngInfo structure.
9354 (void) ResetMagickMemory(mng_info,0,sizeof(MngInfo));
9355 mng_info->image=image;
9356 mng_info->equal_backgrounds=MagickTrue;
9357 have_mng_structure=MagickTrue;
9359 /* See if user has requested a specific PNG subformat */
9361 mng_info->write_png8=LocaleCompare(image_info->magick,"PNG8") == 0;
9362 mng_info->write_png24=LocaleCompare(image_info->magick,"PNG24") == 0;
9363 mng_info->write_png32=LocaleCompare(image_info->magick,"PNG32") == 0;
9365 if (mng_info->write_png8)
9367 mng_info->write_png_colortype = /* 3 */ 4;
9368 mng_info->write_png_depth = 8;
9372 if (mng_info->write_png24)
9374 mng_info->write_png_colortype = /* 2 */ 3;
9375 mng_info->write_png_depth = 8;
9378 if (image->matte == MagickTrue)
9379 (void) SetImageType(image,TrueColorMatteType);
9382 (void) SetImageType(image,TrueColorType);
9384 (void) SyncImage(image);
9387 if (mng_info->write_png32)
9389 mng_info->write_png_colortype = /* 6 */ 7;
9390 mng_info->write_png_depth = 8;
9393 if (image->matte == MagickTrue)
9394 (void) SetImageType(image,TrueColorMatteType);
9397 (void) SetImageType(image,TrueColorType);
9399 (void) SyncImage(image);
9402 value=GetImageOption(image_info,"png:bit-depth");
9404 if (value != (char *) NULL)
9406 if (LocaleCompare(value,"1") == 0)
9407 mng_info->write_png_depth = 1;
9409 else if (LocaleCompare(value,"2") == 0)
9410 mng_info->write_png_depth = 2;
9412 else if (LocaleCompare(value,"4") == 0)
9413 mng_info->write_png_depth = 4;
9415 else if (LocaleCompare(value,"8") == 0)
9416 mng_info->write_png_depth = 8;
9418 else if (LocaleCompare(value,"16") == 0)
9419 mng_info->write_png_depth = 16;
9422 (void) ThrowMagickException(&image->exception,
9423 GetMagickModule(),CoderWarning,
9424 "ignoring invalid defined png:bit-depth",
9427 if (logging != MagickFalse)
9428 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9429 " png:bit-depth=%d was defined.\n",mng_info->write_png_depth);
9432 value=GetImageOption(image_info,"png:color-type");
9434 if (value != (char *) NULL)
9436 /* We must store colortype+1 because 0 is a valid colortype */
9437 if (LocaleCompare(value,"0") == 0)
9438 mng_info->write_png_colortype = 1;
9440 else if (LocaleCompare(value,"2") == 0)
9441 mng_info->write_png_colortype = 3;
9443 else if (LocaleCompare(value,"3") == 0)
9444 mng_info->write_png_colortype = 4;
9446 else if (LocaleCompare(value,"4") == 0)
9447 mng_info->write_png_colortype = 5;
9449 else if (LocaleCompare(value,"6") == 0)
9450 mng_info->write_png_colortype = 7;
9453 (void) ThrowMagickException(&image->exception,
9454 GetMagickModule(),CoderWarning,
9455 "ignoring invalid defined png:color-type",
9458 if (logging != MagickFalse)
9459 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9460 " png:color-type=%d was defined.\n",mng_info->write_png_colortype-1);
9463 /* Check for chunks to be excluded:
9465 * The default is to not exclude any known chunks except for any
9466 * listed in the "unused_chunks" array, above.
9468 * Chunks can be listed for exclusion via a "PNG:exclude-chunk"
9469 * define (in the image properties or in the image artifacts)
9470 * or via a mng_info member. For convenience, in addition
9471 * to or instead of a comma-separated list of chunks, the
9472 * "exclude-chunk" string can be simply "all" or "none".
9474 * The exclude-chunk define takes priority over the mng_info.
9476 * A "PNG:include-chunk" define takes priority over both the
9477 * mng_info and the "PNG:exclude-chunk" define. Like the
9478 * "exclude-chunk" string, it can define "all" or "none" as
9479 * well as a comma-separated list. Chunks that are unknown to
9480 * ImageMagick are always excluded, regardless of their "copy-safe"
9481 * status according to the PNG specification, and even if they
9482 * appear in the "include-chunk" list.
9484 * Finally, all chunks listed in the "unused_chunks" array are
9485 * automatically excluded, regardless of the other instructions
9488 * if you exclude sRGB but not gAMA (recommended), then sRGB chunk
9489 * will not be written and the gAMA chunk will only be written if it
9490 * is not between .45 and .46, or approximately (1.0/2.2).
9492 * If you exclude tRNS and the image has transparency, the colortype
9493 * is forced to be 4 or 6 (GRAY_ALPHA or RGB_ALPHA).
9495 * The -strip option causes StripImage() to set the png:include-chunk
9496 * artifact to "none,gama".
9499 mng_info->ping_exclude_bKGD=MagickFalse;
9500 mng_info->ping_exclude_cHRM=MagickFalse;
9501 mng_info->ping_exclude_EXIF=MagickFalse; /* hex-encoded EXIF in zTXt */
9502 mng_info->ping_exclude_gAMA=MagickFalse;
9503 mng_info->ping_exclude_cHRM=MagickFalse;
9504 mng_info->ping_exclude_iCCP=MagickFalse;
9505 /* mng_info->ping_exclude_iTXt=MagickFalse; */
9506 mng_info->ping_exclude_oFFs=MagickFalse;
9507 mng_info->ping_exclude_pHYs=MagickFalse;
9508 mng_info->ping_exclude_sRGB=MagickFalse;
9509 mng_info->ping_exclude_tEXt=MagickFalse;
9510 mng_info->ping_exclude_tRNS=MagickFalse;
9511 mng_info->ping_exclude_vpAg=MagickFalse;
9512 mng_info->ping_exclude_zCCP=MagickFalse; /* hex-encoded iCCP in zTXt */
9513 mng_info->ping_exclude_zTXt=MagickFalse;
9515 excluding=MagickFalse;
9517 for (source=0; source<1; source++)
9521 value=GetImageArtifact(image,"png:exclude-chunk");
9524 value=GetImageArtifact(image,"png:exclude-chunks");
9528 value=GetImageOption(image_info,"png:exclude-chunk");
9531 value=GetImageOption(image_info,"png:exclude-chunks");
9540 excluding=MagickTrue;
9542 if (logging != MagickFalse)
9545 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9546 " png:exclude-chunk=%s found in image artifacts.\n", value);
9548 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9549 " png:exclude-chunk=%s found in image properties.\n", value);
9554 for (i=0; i<(int) last; i+=5)
9557 if (LocaleNCompare(value+i,"all",3) == 0)
9559 mng_info->ping_exclude_bKGD=MagickTrue;
9560 mng_info->ping_exclude_cHRM=MagickTrue;
9561 mng_info->ping_exclude_EXIF=MagickTrue;
9562 mng_info->ping_exclude_gAMA=MagickTrue;
9563 mng_info->ping_exclude_iCCP=MagickTrue;
9564 /* mng_info->ping_exclude_iTXt=MagickTrue; */
9565 mng_info->ping_exclude_oFFs=MagickTrue;
9566 mng_info->ping_exclude_pHYs=MagickTrue;
9567 mng_info->ping_exclude_sRGB=MagickTrue;
9568 mng_info->ping_exclude_tEXt=MagickTrue;
9569 mng_info->ping_exclude_tRNS=MagickTrue;
9570 mng_info->ping_exclude_vpAg=MagickTrue;
9571 mng_info->ping_exclude_zCCP=MagickTrue;
9572 mng_info->ping_exclude_zTXt=MagickTrue;
9576 if (LocaleNCompare(value+i,"none",4) == 0)
9578 mng_info->ping_exclude_bKGD=MagickFalse;
9579 mng_info->ping_exclude_cHRM=MagickFalse;
9580 mng_info->ping_exclude_EXIF=MagickFalse;
9581 mng_info->ping_exclude_gAMA=MagickFalse;
9582 mng_info->ping_exclude_iCCP=MagickFalse;
9583 /* mng_info->ping_exclude_iTXt=MagickFalse; */
9584 mng_info->ping_exclude_oFFs=MagickFalse;
9585 mng_info->ping_exclude_pHYs=MagickFalse;
9586 mng_info->ping_exclude_sRGB=MagickFalse;
9587 mng_info->ping_exclude_tEXt=MagickFalse;
9588 mng_info->ping_exclude_tRNS=MagickFalse;
9589 mng_info->ping_exclude_vpAg=MagickFalse;
9590 mng_info->ping_exclude_zCCP=MagickFalse;
9591 mng_info->ping_exclude_zTXt=MagickFalse;
9594 if (LocaleNCompare(value+i,"bkgd",4) == 0)
9595 mng_info->ping_exclude_bKGD=MagickTrue;
9597 if (LocaleNCompare(value+i,"chrm",4) == 0)
9598 mng_info->ping_exclude_cHRM=MagickTrue;
9600 if (LocaleNCompare(value+i,"exif",4) == 0)
9601 mng_info->ping_exclude_EXIF=MagickTrue;
9603 if (LocaleNCompare(value+i,"gama",4) == 0)
9604 mng_info->ping_exclude_gAMA=MagickTrue;
9606 if (LocaleNCompare(value+i,"iccp",4) == 0)
9607 mng_info->ping_exclude_iCCP=MagickTrue;
9610 if (LocaleNCompare(value+i,"itxt",4) == 0)
9611 mng_info->ping_exclude_iTXt=MagickTrue;
9614 if (LocaleNCompare(value+i,"gama",4) == 0)
9615 mng_info->ping_exclude_gAMA=MagickTrue;
9617 if (LocaleNCompare(value+i,"offs",4) == 0)
9618 mng_info->ping_exclude_oFFs=MagickTrue;
9620 if (LocaleNCompare(value+i,"phys",4) == 0)
9621 mng_info->ping_exclude_pHYs=MagickTrue;
9623 if (LocaleNCompare(value+i,"srgb",4) == 0)
9624 mng_info->ping_exclude_sRGB=MagickTrue;
9626 if (LocaleNCompare(value+i,"text",4) == 0)
9627 mng_info->ping_exclude_tEXt=MagickTrue;
9629 if (LocaleNCompare(value+i,"trns",4) == 0)
9630 mng_info->ping_exclude_tRNS=MagickTrue;
9632 if (LocaleNCompare(value+i,"vpag",4) == 0)
9633 mng_info->ping_exclude_vpAg=MagickTrue;
9635 if (LocaleNCompare(value+i,"zccp",4) == 0)
9636 mng_info->ping_exclude_zCCP=MagickTrue;
9638 if (LocaleNCompare(value+i,"ztxt",4) == 0)
9639 mng_info->ping_exclude_zTXt=MagickTrue;
9645 for (source=0; source<1; source++)
9649 value=GetImageArtifact(image,"png:include-chunk");
9652 value=GetImageArtifact(image,"png:include-chunks");
9656 value=GetImageOption(image_info,"png:include-chunk");
9659 value=GetImageOption(image_info,"png:include-chunks");
9667 excluding=MagickTrue;
9669 if (logging != MagickFalse)
9672 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9673 " png:include-chunk=%s found in image artifacts.\n", value);
9675 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9676 " png:include-chunk=%s found in image properties.\n", value);
9681 for (i=0; i<(int) last; i+=5)
9683 if (LocaleNCompare(value+i,"all",3) == 0)
9685 mng_info->ping_exclude_bKGD=MagickFalse;
9686 mng_info->ping_exclude_cHRM=MagickFalse;
9687 mng_info->ping_exclude_EXIF=MagickFalse;
9688 mng_info->ping_exclude_gAMA=MagickFalse;
9689 mng_info->ping_exclude_iCCP=MagickFalse;
9690 /* mng_info->ping_exclude_iTXt=MagickFalse; */
9691 mng_info->ping_exclude_oFFs=MagickFalse;
9692 mng_info->ping_exclude_pHYs=MagickFalse;
9693 mng_info->ping_exclude_sRGB=MagickFalse;
9694 mng_info->ping_exclude_tEXt=MagickFalse;
9695 mng_info->ping_exclude_tRNS=MagickFalse;
9696 mng_info->ping_exclude_vpAg=MagickFalse;
9697 mng_info->ping_exclude_zCCP=MagickFalse;
9698 mng_info->ping_exclude_zTXt=MagickFalse;
9702 if (LocaleNCompare(value+i,"none",4) == 0)
9704 mng_info->ping_exclude_bKGD=MagickTrue;
9705 mng_info->ping_exclude_cHRM=MagickTrue;
9706 mng_info->ping_exclude_EXIF=MagickTrue;
9707 mng_info->ping_exclude_gAMA=MagickTrue;
9708 mng_info->ping_exclude_iCCP=MagickTrue;
9709 /* mng_info->ping_exclude_iTXt=MagickTrue; */
9710 mng_info->ping_exclude_oFFs=MagickTrue;
9711 mng_info->ping_exclude_pHYs=MagickTrue;
9712 mng_info->ping_exclude_sRGB=MagickTrue;
9713 mng_info->ping_exclude_tEXt=MagickTrue;
9714 mng_info->ping_exclude_tRNS=MagickTrue;
9715 mng_info->ping_exclude_vpAg=MagickTrue;
9716 mng_info->ping_exclude_zCCP=MagickTrue;
9717 mng_info->ping_exclude_zTXt=MagickTrue;
9720 if (LocaleNCompare(value+i,"bkgd",4) == 0)
9721 mng_info->ping_exclude_bKGD=MagickFalse;
9723 if (LocaleNCompare(value+i,"chrm",4) == 0)
9724 mng_info->ping_exclude_cHRM=MagickFalse;
9726 if (LocaleNCompare(value+i,"exif",4) == 0)
9727 mng_info->ping_exclude_EXIF=MagickFalse;
9729 if (LocaleNCompare(value+i,"gama",4) == 0)
9730 mng_info->ping_exclude_gAMA=MagickFalse;
9732 if (LocaleNCompare(value+i,"iccp",4) == 0)
9733 mng_info->ping_exclude_iCCP=MagickFalse;
9736 if (LocaleNCompare(value+i,"itxt",4) == 0)
9737 mng_info->ping_exclude_iTXt=MagickFalse;
9740 if (LocaleNCompare(value+i,"gama",4) == 0)
9741 mng_info->ping_exclude_gAMA=MagickFalse;
9743 if (LocaleNCompare(value+i,"offs",4) == 0)
9744 mng_info->ping_exclude_oFFs=MagickFalse;
9746 if (LocaleNCompare(value+i,"phys",4) == 0)
9747 mng_info->ping_exclude_pHYs=MagickFalse;
9749 if (LocaleNCompare(value+i,"srgb",4) == 0)
9750 mng_info->ping_exclude_sRGB=MagickFalse;
9752 if (LocaleNCompare(value+i,"text",4) == 0)
9753 mng_info->ping_exclude_tEXt=MagickFalse;
9755 if (LocaleNCompare(value+i,"trns",4) == 0)
9756 mng_info->ping_exclude_tRNS=MagickFalse;
9758 if (LocaleNCompare(value+i,"vpag",4) == 0)
9759 mng_info->ping_exclude_vpAg=MagickFalse;
9761 if (LocaleNCompare(value+i,"zccp",4) == 0)
9762 mng_info->ping_exclude_zCCP=MagickFalse;
9764 if (LocaleNCompare(value+i,"ztxt",4) == 0)
9765 mng_info->ping_exclude_zTXt=MagickFalse;
9771 if (excluding != MagickFalse && logging != MagickFalse)
9773 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9774 " Chunks to be excluded from the output PNG:");
9775 if (mng_info->ping_exclude_bKGD != MagickFalse)
9776 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9778 if (mng_info->ping_exclude_cHRM != MagickFalse)
9779 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9781 if (mng_info->ping_exclude_EXIF != MagickFalse)
9782 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9784 if (mng_info->ping_exclude_gAMA != MagickFalse)
9785 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9787 if (mng_info->ping_exclude_iCCP != MagickFalse)
9788 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9791 if (mng_info->ping_exclude_iTXt != MagickFalse)
9792 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9795 if (mng_info->ping_exclude_oFFs != MagickFalse)
9796 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9798 if (mng_info->ping_exclude_pHYs != MagickFalse)
9799 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9801 if (mng_info->ping_exclude_sRGB != MagickFalse)
9802 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9804 if (mng_info->ping_exclude_tEXt != MagickFalse)
9805 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9807 if (mng_info->ping_exclude_tRNS != MagickFalse)
9808 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9810 if (mng_info->ping_exclude_vpAg != MagickFalse)
9811 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9813 if (mng_info->ping_exclude_zCCP != MagickFalse)
9814 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9816 if (mng_info->ping_exclude_zTXt != MagickFalse)
9817 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9821 mng_info->need_blob = MagickTrue;
9823 status=WriteOnePNGImage(mng_info,image_info,image);
9825 MngInfoFreeStruct(mng_info,&have_mng_structure);
9827 if (logging != MagickFalse)
9828 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"exit WritePNGImage()");
9833 #if defined(JNG_SUPPORTED)
9835 /* Write one JNG image */
9836 static MagickBooleanType WriteOneJNGImage(MngInfo *mng_info,
9837 const ImageInfo *image_info,Image *image)
9858 jng_alpha_compression_method,
9859 jng_alpha_sample_depth,
9866 logging=LogMagickEvent(CoderEvent,GetMagickModule(),
9867 " enter WriteOneJNGImage()");
9869 blob=(unsigned char *) NULL;
9870 jpeg_image=(Image *) NULL;
9871 jpeg_image_info=(ImageInfo *) NULL;
9874 transparent=image_info->type==GrayscaleMatteType ||
9875 image_info->type==TrueColorMatteType;
9877 jng_alpha_sample_depth=0;
9878 jng_quality=image_info->quality == 0UL ? 75UL : image_info->quality;
9879 jng_alpha_compression_method=0;
9881 if (image->matte != MagickFalse)
9883 /* if any pixels are transparent */
9884 transparent=MagickTrue;
9885 if (image_info->compression==JPEGCompression)
9886 jng_alpha_compression_method=8;
9893 /* Create JPEG blob, image, and image_info */
9894 if (logging != MagickFalse)
9895 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9896 " Creating jpeg_image_info for opacity.");
9898 jpeg_image_info=(ImageInfo *) CloneImageInfo(image_info);
9900 if (jpeg_image_info == (ImageInfo *) NULL)
9901 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
9903 if (logging != MagickFalse)
9904 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9905 " Creating jpeg_image.");
9907 jpeg_image=CloneImage(image,0,0,MagickTrue,&image->exception);
9909 if (jpeg_image == (Image *) NULL)
9910 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
9912 (void) CopyMagickString(jpeg_image->magick,"JPEG",MaxTextExtent);
9913 status=SeparateImageChannel(jpeg_image,OpacityChannel);
9914 status=NegateImage(jpeg_image,MagickFalse);
9915 jpeg_image->matte=MagickFalse;
9917 if (jng_quality >= 1000)
9918 jpeg_image_info->quality=jng_quality/1000;
9921 jpeg_image_info->quality=jng_quality;
9923 jpeg_image_info->type=GrayscaleType;
9924 (void) SetImageType(jpeg_image,GrayscaleType);
9925 (void) AcquireUniqueFilename(jpeg_image->filename);
9926 (void) FormatMagickString(jpeg_image_info->filename,MaxTextExtent,
9927 "%s",jpeg_image->filename);
9930 /* To do: check bit depth of PNG alpha channel */
9932 /* Check if image is grayscale. */
9933 if (image_info->type != TrueColorMatteType && image_info->type !=
9934 TrueColorType && ImageIsGray(image))
9939 if (jng_alpha_compression_method==0)
9944 /* Encode opacity as a grayscale PNG blob */
9945 status=OpenBlob(jpeg_image_info,jpeg_image,WriteBinaryBlobMode,
9947 if (logging != MagickFalse)
9948 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9949 " Creating PNG blob.");
9952 (void) CopyMagickString(jpeg_image_info->magick,"PNG",MaxTextExtent);
9953 (void) CopyMagickString(jpeg_image->magick,"PNG",MaxTextExtent);
9954 jpeg_image_info->interlace=NoInterlace;
9956 blob=ImageToBlob(jpeg_image_info,jpeg_image,&length,
9959 /* Retrieve sample depth used */
9960 value=GetImageProperty(jpeg_image,"png:bit-depth-written");
9961 if (value != (char *) NULL)
9962 jng_alpha_sample_depth= (unsigned int) value[0];
9966 /* Encode opacity as a grayscale JPEG blob */
9968 status=OpenBlob(jpeg_image_info,jpeg_image,WriteBinaryBlobMode,
9971 (void) CopyMagickString(jpeg_image_info->magick,"JPEG",MaxTextExtent);
9972 (void) CopyMagickString(jpeg_image->magick,"JPEG",MaxTextExtent);
9973 jpeg_image_info->interlace=NoInterlace;
9974 if (logging != MagickFalse)
9975 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9977 blob=ImageToBlob(jpeg_image_info,jpeg_image,&length,
9979 jng_alpha_sample_depth=8;
9981 if (logging != MagickFalse)
9982 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9983 " Successfully read jpeg_image into a blob, length=%.20g.",
9987 /* Destroy JPEG image and image_info */
9988 jpeg_image=DestroyImage(jpeg_image);
9989 (void) RelinquishUniqueFileResource(jpeg_image_info->filename);
9990 jpeg_image_info=DestroyImageInfo(jpeg_image_info);
9993 /* Write JHDR chunk */
9994 (void) WriteBlobMSBULong(image,16L); /* chunk data length=16 */
9995 PNGType(chunk,mng_JHDR);
9996 LogPNGChunk(logging,mng_JHDR,16L);
9997 PNGLong(chunk+4,(png_uint_32) image->columns);
9998 PNGLong(chunk+8,(png_uint_32) image->rows);
9999 chunk[12]=jng_color_type;
10000 chunk[13]=8; /* sample depth */
10001 chunk[14]=8; /*jng_image_compression_method */
10002 chunk[15]=(unsigned char) (image_info->interlace == NoInterlace ? 0 : 8);
10003 chunk[16]=jng_alpha_sample_depth;
10004 chunk[17]=jng_alpha_compression_method;
10005 chunk[18]=0; /*jng_alpha_filter_method */
10006 chunk[19]=0; /*jng_alpha_interlace_method */
10007 (void) WriteBlob(image,20,chunk);
10008 (void) WriteBlobMSBULong(image,crc32(0,chunk,20));
10009 if (logging != MagickFalse)
10011 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10012 " JNG width:%15lu",(unsigned long) image->columns);
10014 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10015 " JNG height:%14lu",(unsigned long) image->rows);
10017 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10018 " JNG color type:%10d",jng_color_type);
10020 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10021 " JNG sample depth:%8d",8);
10023 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10024 " JNG compression:%9d",8);
10026 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10027 " JNG interlace:%11d",0);
10029 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10030 " JNG alpha depth:%9d",jng_alpha_sample_depth);
10032 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10033 " JNG alpha compression:%3d",jng_alpha_compression_method);
10035 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10036 " JNG alpha filter:%8d",0);
10038 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10039 " JNG alpha interlace:%5d",0);
10042 /* Write any JNG-chunk-b profiles */
10043 (void) Magick_png_write_chunk_from_profile(image,"JNG-chunk-b",logging);
10046 Write leading ancillary chunks
10052 Write JNG bKGD chunk
10063 if (jng_color_type == 8 || jng_color_type == 12)
10067 (void) WriteBlobMSBULong(image,(size_t) (num_bytes-4L));
10068 PNGType(chunk,mng_bKGD);
10069 LogPNGChunk(logging,mng_bKGD,(size_t) (num_bytes-4L));
10070 red=ScaleQuantumToChar(image->background_color.red);
10071 green=ScaleQuantumToChar(image->background_color.green);
10072 blue=ScaleQuantumToChar(image->background_color.blue);
10079 (void) WriteBlob(image,(size_t) num_bytes,chunk);
10080 (void) WriteBlobMSBULong(image,crc32(0,chunk,(uInt) num_bytes));
10083 if ((image->colorspace == sRGBColorspace || image->rendering_intent))
10086 Write JNG sRGB chunk
10088 (void) WriteBlobMSBULong(image,1L);
10089 PNGType(chunk,mng_sRGB);
10090 LogPNGChunk(logging,mng_sRGB,1L);
10092 if (image->rendering_intent != UndefinedIntent)
10093 chunk[4]=(unsigned char)
10094 Magick_RenderingIntent_to_PNG_RenderingIntent(
10095 (image->rendering_intent));
10098 chunk[4]=(unsigned char)
10099 Magick_RenderingIntent_to_PNG_RenderingIntent(
10100 (PerceptualIntent));
10102 (void) WriteBlob(image,5,chunk);
10103 (void) WriteBlobMSBULong(image,crc32(0,chunk,5));
10107 if (image->gamma != 0.0)
10110 Write JNG gAMA chunk
10112 (void) WriteBlobMSBULong(image,4L);
10113 PNGType(chunk,mng_gAMA);
10114 LogPNGChunk(logging,mng_gAMA,4L);
10115 PNGLong(chunk+4,(png_uint_32) (100000*image->gamma+0.5));
10116 (void) WriteBlob(image,8,chunk);
10117 (void) WriteBlobMSBULong(image,crc32(0,chunk,8));
10120 if ((mng_info->equal_chrms == MagickFalse) &&
10121 (image->chromaticity.red_primary.x != 0.0))
10127 Write JNG cHRM chunk
10129 (void) WriteBlobMSBULong(image,32L);
10130 PNGType(chunk,mng_cHRM);
10131 LogPNGChunk(logging,mng_cHRM,32L);
10132 primary=image->chromaticity.white_point;
10133 PNGLong(chunk+4,(png_uint_32) (100000*primary.x+0.5));
10134 PNGLong(chunk+8,(png_uint_32) (100000*primary.y+0.5));
10135 primary=image->chromaticity.red_primary;
10136 PNGLong(chunk+12,(png_uint_32) (100000*primary.x+0.5));
10137 PNGLong(chunk+16,(png_uint_32) (100000*primary.y+0.5));
10138 primary=image->chromaticity.green_primary;
10139 PNGLong(chunk+20,(png_uint_32) (100000*primary.x+0.5));
10140 PNGLong(chunk+24,(png_uint_32) (100000*primary.y+0.5));
10141 primary=image->chromaticity.blue_primary;
10142 PNGLong(chunk+28,(png_uint_32) (100000*primary.x+0.5));
10143 PNGLong(chunk+32,(png_uint_32) (100000*primary.y+0.5));
10144 (void) WriteBlob(image,36,chunk);
10145 (void) WriteBlobMSBULong(image,crc32(0,chunk,36));
10149 if (image->x_resolution && image->y_resolution && !mng_info->equal_physs)
10152 Write JNG pHYs chunk
10154 (void) WriteBlobMSBULong(image,9L);
10155 PNGType(chunk,mng_pHYs);
10156 LogPNGChunk(logging,mng_pHYs,9L);
10157 if (image->units == PixelsPerInchResolution)
10159 PNGLong(chunk+4,(png_uint_32)
10160 (image->x_resolution*100.0/2.54+0.5));
10162 PNGLong(chunk+8,(png_uint_32)
10163 (image->y_resolution*100.0/2.54+0.5));
10170 if (image->units == PixelsPerCentimeterResolution)
10172 PNGLong(chunk+4,(png_uint_32)
10173 (image->x_resolution*100.0+0.5));
10175 PNGLong(chunk+8,(png_uint_32)
10176 (image->y_resolution*100.0+0.5));
10183 PNGLong(chunk+4,(png_uint_32) (image->x_resolution+0.5));
10184 PNGLong(chunk+8,(png_uint_32) (image->y_resolution+0.5));
10188 (void) WriteBlob(image,13,chunk);
10189 (void) WriteBlobMSBULong(image,crc32(0,chunk,13));
10192 if (mng_info->write_mng == 0 && (image->page.x || image->page.y))
10195 Write JNG oFFs chunk
10197 (void) WriteBlobMSBULong(image,9L);
10198 PNGType(chunk,mng_oFFs);
10199 LogPNGChunk(logging,mng_oFFs,9L);
10200 PNGsLong(chunk+4,(ssize_t) (image->page.x));
10201 PNGsLong(chunk+8,(ssize_t) (image->page.y));
10203 (void) WriteBlob(image,13,chunk);
10204 (void) WriteBlobMSBULong(image,crc32(0,chunk,13));
10206 if (mng_info->write_mng == 0 && (image->page.width || image->page.height))
10208 (void) WriteBlobMSBULong(image,9L); /* data length=8 */
10209 PNGType(chunk,mng_vpAg);
10210 LogPNGChunk(logging,mng_vpAg,9L);
10211 PNGLong(chunk+4,(png_uint_32) image->page.width);
10212 PNGLong(chunk+8,(png_uint_32) image->page.height);
10213 chunk[12]=0; /* unit = pixels */
10214 (void) WriteBlob(image,13,chunk);
10215 (void) WriteBlobMSBULong(image,crc32(0,chunk,13));
10221 if (jng_alpha_compression_method==0)
10229 /* Write IDAT chunk header */
10230 if (logging != MagickFalse)
10231 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10232 " Write IDAT chunks from blob, length=%.20g.",(double)
10235 /* Copy IDAT chunks */
10238 for (i=8; i<(ssize_t) length; i+=len+12)
10240 len=(*p<<24)|((*(p+1))<<16)|((*(p+2))<<8)|(*(p+3));
10243 if (*(p)==73 && *(p+1)==68 && *(p+2)==65 && *(p+3)==84) /* IDAT */
10245 /* Found an IDAT chunk. */
10246 (void) WriteBlobMSBULong(image,(size_t) len);
10247 LogPNGChunk(logging,mng_IDAT,(size_t) len);
10248 (void) WriteBlob(image,(size_t) len+4,p);
10249 (void) WriteBlobMSBULong(image,
10250 crc32(0,p,(uInt) len+4));
10255 if (logging != MagickFalse)
10256 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10257 " Skipping %c%c%c%c chunk, length=%.20g.",
10258 *(p),*(p+1),*(p+2),*(p+3),(double) len);
10265 /* Write JDAA chunk header */
10266 if (logging != MagickFalse)
10267 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10268 " Write JDAA chunk, length=%.20g.",(double) length);
10269 (void) WriteBlobMSBULong(image,(size_t) length);
10270 PNGType(chunk,mng_JDAA);
10271 LogPNGChunk(logging,mng_JDAA,length);
10272 /* Write JDAT chunk(s) data */
10273 (void) WriteBlob(image,4,chunk);
10274 (void) WriteBlob(image,length,blob);
10275 (void) WriteBlobMSBULong(image,crc32(crc32(0,chunk,4),blob,
10278 blob=(unsigned char *) RelinquishMagickMemory(blob);
10281 /* Encode image as a JPEG blob */
10282 if (logging != MagickFalse)
10283 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10284 " Creating jpeg_image_info.");
10285 jpeg_image_info=(ImageInfo *) CloneImageInfo(image_info);
10286 if (jpeg_image_info == (ImageInfo *) NULL)
10287 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
10289 if (logging != MagickFalse)
10290 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10291 " Creating jpeg_image.");
10293 jpeg_image=CloneImage(image,0,0,MagickTrue,&image->exception);
10294 if (jpeg_image == (Image *) NULL)
10295 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
10296 (void) CopyMagickString(jpeg_image->magick,"JPEG",MaxTextExtent);
10298 (void) AcquireUniqueFilename(jpeg_image->filename);
10299 (void) FormatMagickString(jpeg_image_info->filename,MaxTextExtent,"%s",
10300 jpeg_image->filename);
10302 status=OpenBlob(jpeg_image_info,jpeg_image,WriteBinaryBlobMode,
10303 &image->exception);
10305 if (logging != MagickFalse)
10306 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10307 " Created jpeg_image, %.20g x %.20g.",(double) jpeg_image->columns,
10308 (double) jpeg_image->rows);
10310 if (jng_color_type == 8 || jng_color_type == 12)
10311 jpeg_image_info->type=GrayscaleType;
10313 jpeg_image_info->quality=jng_quality % 1000;
10314 (void) CopyMagickString(jpeg_image_info->magick,"JPEG",MaxTextExtent);
10315 (void) CopyMagickString(jpeg_image->magick,"JPEG",MaxTextExtent);
10317 if (logging != MagickFalse)
10318 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10319 " Creating blob.");
10321 blob=ImageToBlob(jpeg_image_info,jpeg_image,&length,&image->exception);
10323 if (logging != MagickFalse)
10325 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10326 " Successfully read jpeg_image into a blob, length=%.20g.",
10329 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10330 " Write JDAT chunk, length=%.20g.",(double) length);
10333 /* Write JDAT chunk(s) */
10334 (void) WriteBlobMSBULong(image,(size_t) length);
10335 PNGType(chunk,mng_JDAT);
10336 LogPNGChunk(logging,mng_JDAT,length);
10337 (void) WriteBlob(image,4,chunk);
10338 (void) WriteBlob(image,length,blob);
10339 (void) WriteBlobMSBULong(image,crc32(crc32(0,chunk,4),blob,(uInt) length));
10341 jpeg_image=DestroyImage(jpeg_image);
10342 (void) RelinquishUniqueFileResource(jpeg_image_info->filename);
10343 jpeg_image_info=DestroyImageInfo(jpeg_image_info);
10344 blob=(unsigned char *) RelinquishMagickMemory(blob);
10346 /* Write any JNG-chunk-e profiles */
10347 (void) Magick_png_write_chunk_from_profile(image,"JNG-chunk-e",logging);
10349 /* Write IEND chunk */
10350 (void) WriteBlobMSBULong(image,0L);
10351 PNGType(chunk,mng_IEND);
10352 LogPNGChunk(logging,mng_IEND,0);
10353 (void) WriteBlob(image,4,chunk);
10354 (void) WriteBlobMSBULong(image,crc32(0,chunk,4));
10356 if (logging != MagickFalse)
10357 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10358 " exit WriteOneJNGImage()");
10365 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
10369 % W r i t e J N G I m a g e %
10373 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
10375 % WriteJNGImage() writes a JPEG Network Graphics (JNG) image file.
10377 % JNG support written by Glenn Randers-Pehrson, glennrp@image...
10379 % The format of the WriteJNGImage method is:
10381 % MagickBooleanType WriteJNGImage(const ImageInfo *image_info,Image *image)
10383 % A description of each parameter follows:
10385 % o image_info: the image info.
10387 % o image: The image.
10389 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
10391 static MagickBooleanType WriteJNGImage(const ImageInfo *image_info,Image *image)
10394 have_mng_structure,
10404 assert(image_info != (const ImageInfo *) NULL);
10405 assert(image_info->signature == MagickSignature);
10406 assert(image != (Image *) NULL);
10407 assert(image->signature == MagickSignature);
10408 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
10409 logging=LogMagickEvent(CoderEvent,GetMagickModule(),"enter WriteJNGImage()");
10410 status=OpenBlob(image_info,image,WriteBinaryBlobMode,&image->exception);
10411 if (status == MagickFalse)
10415 Allocate a MngInfo structure.
10417 have_mng_structure=MagickFalse;
10418 mng_info=(MngInfo *) AcquireMagickMemory(sizeof(MngInfo));
10419 if (mng_info == (MngInfo *) NULL)
10420 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
10422 Initialize members of the MngInfo structure.
10424 (void) ResetMagickMemory(mng_info,0,sizeof(MngInfo));
10425 mng_info->image=image;
10426 have_mng_structure=MagickTrue;
10428 (void) WriteBlob(image,8,(const unsigned char *) "\213JNG\r\n\032\n");
10430 status=WriteOneJNGImage(mng_info,image_info,image);
10431 (void) CloseBlob(image);
10433 (void) CatchImageException(image);
10434 MngInfoFreeStruct(mng_info,&have_mng_structure);
10435 if (logging != MagickFalse)
10436 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"exit WriteJNGImage()");
10443 static MagickBooleanType WriteMNGImage(const ImageInfo *image_info,Image *image)
10452 have_mng_structure,
10455 volatile MagickBooleanType
10467 #if defined(PNG_WRITE_EMPTY_PLTE_SUPPORTED) || \
10468 defined(PNG_MNG_FEATURES_SUPPORTED)
10471 all_images_are_gray,
10481 volatile unsigned int
10492 #if (PNG_LIBPNG_VER < 10200)
10493 if (image_info->verbose)
10494 printf("Your PNG library (libpng-%s) is rather old.\n",
10495 PNG_LIBPNG_VER_STRING);
10501 assert(image_info != (const ImageInfo *) NULL);
10502 assert(image_info->signature == MagickSignature);
10503 assert(image != (Image *) NULL);
10504 assert(image->signature == MagickSignature);
10505 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
10506 logging=LogMagickEvent(CoderEvent,GetMagickModule(),"enter WriteMNGImage()");
10507 status=OpenBlob(image_info,image,WriteBinaryBlobMode,&image->exception);
10508 if (status == MagickFalse)
10512 Allocate a MngInfo structure.
10514 have_mng_structure=MagickFalse;
10515 mng_info=(MngInfo *) AcquireMagickMemory(sizeof(MngInfo));
10516 if (mng_info == (MngInfo *) NULL)
10517 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
10519 Initialize members of the MngInfo structure.
10521 (void) ResetMagickMemory(mng_info,0,sizeof(MngInfo));
10522 mng_info->image=image;
10523 have_mng_structure=MagickTrue;
10524 write_mng=LocaleCompare(image_info->magick,"MNG") == 0;
10527 * See if user has requested a specific PNG subformat to be used
10528 * for all of the PNGs in the MNG being written, e.g.,
10530 * convert *.png png8:animation.mng
10532 * To do: check -define png:bit_depth and png:color_type as well,
10533 * or perhaps use mng:bit_depth and mng:color_type instead for
10537 mng_info->write_png8=LocaleCompare(image_info->magick,"PNG8") == 0;
10538 mng_info->write_png24=LocaleCompare(image_info->magick,"PNG24") == 0;
10539 mng_info->write_png32=LocaleCompare(image_info->magick,"PNG32") == 0;
10541 write_jng=MagickFalse;
10542 if (image_info->compression == JPEGCompression)
10543 write_jng=MagickTrue;
10545 mng_info->adjoin=image_info->adjoin &&
10546 (GetNextImageInList(image) != (Image *) NULL) && write_mng;
10548 if (logging != MagickFalse)
10550 /* Log some info about the input */
10554 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10555 " Checking input image(s)");
10557 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10558 " Image_info depth: %.20g",(double) image_info->depth);
10560 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10561 " Type: %d",image_info->type);
10564 for (p=image; p != (Image *) NULL; p=GetNextImageInList(p))
10566 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10567 " Scene: %.20g",(double) scene++);
10569 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10570 " Image depth: %.20g",(double) p->depth);
10573 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10577 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10580 if (p->storage_class == PseudoClass)
10581 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10582 " Storage class: PseudoClass");
10585 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10586 " Storage class: DirectClass");
10589 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10590 " Number of colors: %.20g",(double) p->colors);
10593 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10594 " Number of colors: unspecified");
10596 if (mng_info->adjoin == MagickFalse)
10601 use_global_plte=MagickFalse;
10602 all_images_are_gray=MagickFalse;
10603 #ifdef PNG_WRITE_EMPTY_PLTE_SUPPORTED
10604 need_local_plte=MagickTrue;
10606 need_defi=MagickFalse;
10607 need_matte=MagickFalse;
10608 mng_info->framing_mode=1;
10609 mng_info->old_framing_mode=1;
10612 if (image_info->page != (char *) NULL)
10615 Determine image bounding box.
10617 SetGeometry(image,&mng_info->page);
10618 (void) ParseMetaGeometry(image_info->page,&mng_info->page.x,
10619 &mng_info->page.y,&mng_info->page.width,&mng_info->page.height);
10631 mng_info->page=image->page;
10632 need_geom=MagickTrue;
10633 if (mng_info->page.width || mng_info->page.height)
10634 need_geom=MagickFalse;
10636 Check all the scenes.
10638 initial_delay=image->delay;
10639 need_iterations=MagickFalse;
10640 mng_info->equal_chrms=image->chromaticity.red_primary.x != 0.0;
10641 mng_info->equal_physs=MagickTrue,
10642 mng_info->equal_gammas=MagickTrue;
10643 mng_info->equal_srgbs=MagickTrue;
10644 mng_info->equal_backgrounds=MagickTrue;
10646 #if defined(PNG_WRITE_EMPTY_PLTE_SUPPORTED) || \
10647 defined(PNG_MNG_FEATURES_SUPPORTED)
10648 all_images_are_gray=MagickTrue;
10649 mng_info->equal_palettes=MagickFalse;
10650 need_local_plte=MagickFalse;
10652 for (next_image=image; next_image != (Image *) NULL; )
10656 if ((next_image->columns+next_image->page.x) > mng_info->page.width)
10657 mng_info->page.width=next_image->columns+next_image->page.x;
10659 if ((next_image->rows+next_image->page.y) > mng_info->page.height)
10660 mng_info->page.height=next_image->rows+next_image->page.y;
10663 if (next_image->page.x || next_image->page.y)
10664 need_defi=MagickTrue;
10666 if (next_image->matte)
10667 need_matte=MagickTrue;
10669 if ((int) next_image->dispose >= BackgroundDispose)
10670 if (next_image->matte || next_image->page.x || next_image->page.y ||
10671 ((next_image->columns < mng_info->page.width) &&
10672 (next_image->rows < mng_info->page.height)))
10673 mng_info->need_fram=MagickTrue;
10675 if (next_image->iterations)
10676 need_iterations=MagickTrue;
10678 final_delay=next_image->delay;
10680 if (final_delay != initial_delay || final_delay > 1UL*
10681 next_image->ticks_per_second)
10682 mng_info->need_fram=1;
10684 #if defined(PNG_WRITE_EMPTY_PLTE_SUPPORTED) || \
10685 defined(PNG_MNG_FEATURES_SUPPORTED)
10687 check for global palette possibility.
10689 if (image->matte != MagickFalse)
10690 need_local_plte=MagickTrue;
10692 if (need_local_plte == 0)
10694 if (ImageIsGray(image) == MagickFalse)
10695 all_images_are_gray=MagickFalse;
10696 mng_info->equal_palettes=PalettesAreEqual(image,next_image);
10697 if (use_global_plte == 0)
10698 use_global_plte=mng_info->equal_palettes;
10699 need_local_plte=!mng_info->equal_palettes;
10702 if (GetNextImageInList(next_image) != (Image *) NULL)
10704 if (next_image->background_color.red !=
10705 next_image->next->background_color.red ||
10706 next_image->background_color.green !=
10707 next_image->next->background_color.green ||
10708 next_image->background_color.blue !=
10709 next_image->next->background_color.blue)
10710 mng_info->equal_backgrounds=MagickFalse;
10712 if (next_image->gamma != next_image->next->gamma)
10713 mng_info->equal_gammas=MagickFalse;
10715 if (next_image->rendering_intent !=
10716 next_image->next->rendering_intent)
10717 mng_info->equal_srgbs=MagickFalse;
10719 if ((next_image->units != next_image->next->units) ||
10720 (next_image->x_resolution != next_image->next->x_resolution) ||
10721 (next_image->y_resolution != next_image->next->y_resolution))
10722 mng_info->equal_physs=MagickFalse;
10724 if (mng_info->equal_chrms)
10726 if (next_image->chromaticity.red_primary.x !=
10727 next_image->next->chromaticity.red_primary.x ||
10728 next_image->chromaticity.red_primary.y !=
10729 next_image->next->chromaticity.red_primary.y ||
10730 next_image->chromaticity.green_primary.x !=
10731 next_image->next->chromaticity.green_primary.x ||
10732 next_image->chromaticity.green_primary.y !=
10733 next_image->next->chromaticity.green_primary.y ||
10734 next_image->chromaticity.blue_primary.x !=
10735 next_image->next->chromaticity.blue_primary.x ||
10736 next_image->chromaticity.blue_primary.y !=
10737 next_image->next->chromaticity.blue_primary.y ||
10738 next_image->chromaticity.white_point.x !=
10739 next_image->next->chromaticity.white_point.x ||
10740 next_image->chromaticity.white_point.y !=
10741 next_image->next->chromaticity.white_point.y)
10742 mng_info->equal_chrms=MagickFalse;
10746 next_image=GetNextImageInList(next_image);
10748 if (image_count < 2)
10750 mng_info->equal_backgrounds=MagickFalse;
10751 mng_info->equal_chrms=MagickFalse;
10752 mng_info->equal_gammas=MagickFalse;
10753 mng_info->equal_srgbs=MagickFalse;
10754 mng_info->equal_physs=MagickFalse;
10755 use_global_plte=MagickFalse;
10756 #ifdef PNG_WRITE_EMPTY_PLTE_SUPPORTED
10757 need_local_plte=MagickTrue;
10759 need_iterations=MagickFalse;
10762 if (mng_info->need_fram == MagickFalse)
10765 Only certain framing rates 100/n are exactly representable without
10766 the FRAM chunk but we'll allow some slop in VLC files
10768 if (final_delay == 0)
10770 if (need_iterations != MagickFalse)
10773 It's probably a GIF with loop; don't run it *too* fast.
10775 if (mng_info->adjoin)
10778 (void) ThrowMagickException(&image->exception,
10779 GetMagickModule(),CoderWarning,
10780 "input has zero delay between all frames; assuming",
10785 mng_info->ticks_per_second=0;
10787 if (final_delay != 0)
10788 mng_info->ticks_per_second=(png_uint_32)
10789 (image->ticks_per_second/final_delay);
10790 if (final_delay > 50)
10791 mng_info->ticks_per_second=2;
10793 if (final_delay > 75)
10794 mng_info->ticks_per_second=1;
10796 if (final_delay > 125)
10797 mng_info->need_fram=MagickTrue;
10799 if (need_defi && final_delay > 2 && (final_delay != 4) &&
10800 (final_delay != 5) && (final_delay != 10) && (final_delay != 20) &&
10801 (final_delay != 25) && (final_delay != 50) && (final_delay !=
10802 1UL*image->ticks_per_second))
10803 mng_info->need_fram=MagickTrue; /* make it exact; cannot be VLC */
10806 if (mng_info->need_fram != MagickFalse)
10807 mng_info->ticks_per_second=1UL*image->ticks_per_second;
10809 If pseudocolor, we should also check to see if all the
10810 palettes are identical and write a global PLTE if they are.
10814 Write the MNG version 1.0 signature and MHDR chunk.
10816 (void) WriteBlob(image,8,(const unsigned char *) "\212MNG\r\n\032\n");
10817 (void) WriteBlobMSBULong(image,28L); /* chunk data length=28 */
10818 PNGType(chunk,mng_MHDR);
10819 LogPNGChunk(logging,mng_MHDR,28L);
10820 PNGLong(chunk+4,(png_uint_32) mng_info->page.width);
10821 PNGLong(chunk+8,(png_uint_32) mng_info->page.height);
10822 PNGLong(chunk+12,mng_info->ticks_per_second);
10823 PNGLong(chunk+16,0L); /* layer count=unknown */
10824 PNGLong(chunk+20,0L); /* frame count=unknown */
10825 PNGLong(chunk+24,0L); /* play time=unknown */
10830 if (need_defi || mng_info->need_fram || use_global_plte)
10831 PNGLong(chunk+28,27L); /* simplicity=LC+JNG */
10834 PNGLong(chunk+28,25L); /* simplicity=VLC+JNG */
10839 if (need_defi || mng_info->need_fram || use_global_plte)
10840 PNGLong(chunk+28,19L); /* simplicity=LC+JNG, no transparency */
10843 PNGLong(chunk+28,17L); /* simplicity=VLC+JNG, no transparency */
10851 if (need_defi || mng_info->need_fram || use_global_plte)
10852 PNGLong(chunk+28,11L); /* simplicity=LC */
10855 PNGLong(chunk+28,9L); /* simplicity=VLC */
10860 if (need_defi || mng_info->need_fram || use_global_plte)
10861 PNGLong(chunk+28,3L); /* simplicity=LC, no transparency */
10864 PNGLong(chunk+28,1L); /* simplicity=VLC, no transparency */
10867 (void) WriteBlob(image,32,chunk);
10868 (void) WriteBlobMSBULong(image,crc32(0,chunk,32));
10869 option=GetImageOption(image_info,"mng:need-cacheoff");
10870 if (option != (const char *) NULL)
10876 Write "nEED CACHEOFF" to turn playback caching off for streaming MNG.
10878 PNGType(chunk,mng_nEED);
10879 length=CopyMagickString((char *) chunk+4,"CACHEOFF",20);
10880 (void) WriteBlobMSBULong(image,(size_t) length);
10881 LogPNGChunk(logging,mng_nEED,(size_t) length);
10883 (void) WriteBlob(image,length,chunk);
10884 (void) WriteBlobMSBULong(image,crc32(0,chunk,(uInt) length));
10886 if ((GetPreviousImageInList(image) == (Image *) NULL) &&
10887 (GetNextImageInList(image) != (Image *) NULL) &&
10888 (image->iterations != 1))
10891 Write MNG TERM chunk
10893 (void) WriteBlobMSBULong(image,10L); /* data length=10 */
10894 PNGType(chunk,mng_TERM);
10895 LogPNGChunk(logging,mng_TERM,10L);
10896 chunk[4]=3; /* repeat animation */
10897 chunk[5]=0; /* show last frame when done */
10898 PNGLong(chunk+6,(png_uint_32) (mng_info->ticks_per_second*
10899 final_delay/MagickMax(image->ticks_per_second,1)));
10901 if (image->iterations == 0)
10902 PNGLong(chunk+10,PNG_UINT_31_MAX);
10905 PNGLong(chunk+10,(png_uint_32) image->iterations);
10907 if (logging != MagickFalse)
10909 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10910 " TERM delay: %.20g",(double) (mng_info->ticks_per_second*
10911 final_delay/MagickMax(image->ticks_per_second,1)));
10913 if (image->iterations == 0)
10914 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10915 " TERM iterations: %.20g",(double) PNG_UINT_31_MAX);
10918 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10919 " Image iterations: %.20g",(double) image->iterations);
10921 (void) WriteBlob(image,14,chunk);
10922 (void) WriteBlobMSBULong(image,crc32(0,chunk,14));
10925 To do: check for cHRM+gAMA == sRGB, and write sRGB instead.
10927 if ((image->colorspace == sRGBColorspace || image->rendering_intent) &&
10928 mng_info->equal_srgbs)
10931 Write MNG sRGB chunk
10933 (void) WriteBlobMSBULong(image,1L);
10934 PNGType(chunk,mng_sRGB);
10935 LogPNGChunk(logging,mng_sRGB,1L);
10937 if (image->rendering_intent != UndefinedIntent)
10938 chunk[4]=(unsigned char)
10939 Magick_RenderingIntent_to_PNG_RenderingIntent(
10940 (image->rendering_intent));
10943 chunk[4]=(unsigned char)
10944 Magick_RenderingIntent_to_PNG_RenderingIntent(
10945 (PerceptualIntent));
10947 (void) WriteBlob(image,5,chunk);
10948 (void) WriteBlobMSBULong(image,crc32(0,chunk,5));
10949 mng_info->have_write_global_srgb=MagickTrue;
10954 if (image->gamma && mng_info->equal_gammas)
10957 Write MNG gAMA chunk
10959 (void) WriteBlobMSBULong(image,4L);
10960 PNGType(chunk,mng_gAMA);
10961 LogPNGChunk(logging,mng_gAMA,4L);
10962 PNGLong(chunk+4,(png_uint_32) (100000*image->gamma+0.5));
10963 (void) WriteBlob(image,8,chunk);
10964 (void) WriteBlobMSBULong(image,crc32(0,chunk,8));
10965 mng_info->have_write_global_gama=MagickTrue;
10967 if (mng_info->equal_chrms)
10973 Write MNG cHRM chunk
10975 (void) WriteBlobMSBULong(image,32L);
10976 PNGType(chunk,mng_cHRM);
10977 LogPNGChunk(logging,mng_cHRM,32L);
10978 primary=image->chromaticity.white_point;
10979 PNGLong(chunk+4,(png_uint_32) (100000*primary.x+0.5));
10980 PNGLong(chunk+8,(png_uint_32) (100000*primary.y+0.5));
10981 primary=image->chromaticity.red_primary;
10982 PNGLong(chunk+12,(png_uint_32) (100000*primary.x+0.5));
10983 PNGLong(chunk+16,(png_uint_32) (100000*primary.y+0.5));
10984 primary=image->chromaticity.green_primary;
10985 PNGLong(chunk+20,(png_uint_32) (100000*primary.x+0.5));
10986 PNGLong(chunk+24,(png_uint_32) (100000*primary.y+0.5));
10987 primary=image->chromaticity.blue_primary;
10988 PNGLong(chunk+28,(png_uint_32) (100000*primary.x+0.5));
10989 PNGLong(chunk+32,(png_uint_32) (100000*primary.y+0.5));
10990 (void) WriteBlob(image,36,chunk);
10991 (void) WriteBlobMSBULong(image,crc32(0,chunk,36));
10992 mng_info->have_write_global_chrm=MagickTrue;
10995 if (image->x_resolution && image->y_resolution && mng_info->equal_physs)
10998 Write MNG pHYs chunk
11000 (void) WriteBlobMSBULong(image,9L);
11001 PNGType(chunk,mng_pHYs);
11002 LogPNGChunk(logging,mng_pHYs,9L);
11004 if (image->units == PixelsPerInchResolution)
11006 PNGLong(chunk+4,(png_uint_32)
11007 (image->x_resolution*100.0/2.54+0.5));
11009 PNGLong(chunk+8,(png_uint_32)
11010 (image->y_resolution*100.0/2.54+0.5));
11017 if (image->units == PixelsPerCentimeterResolution)
11019 PNGLong(chunk+4,(png_uint_32)
11020 (image->x_resolution*100.0+0.5));
11022 PNGLong(chunk+8,(png_uint_32)
11023 (image->y_resolution*100.0+0.5));
11030 PNGLong(chunk+4,(png_uint_32) (image->x_resolution+0.5));
11031 PNGLong(chunk+8,(png_uint_32) (image->y_resolution+0.5));
11035 (void) WriteBlob(image,13,chunk);
11036 (void) WriteBlobMSBULong(image,crc32(0,chunk,13));
11039 Write MNG BACK chunk and global bKGD chunk, if the image is transparent
11040 or does not cover the entire frame.
11042 if (write_mng && (image->matte || image->page.x > 0 ||
11043 image->page.y > 0 || (image->page.width &&
11044 (image->page.width+image->page.x < mng_info->page.width))
11045 || (image->page.height && (image->page.height+image->page.y
11046 < mng_info->page.height))))
11048 (void) WriteBlobMSBULong(image,6L);
11049 PNGType(chunk,mng_BACK);
11050 LogPNGChunk(logging,mng_BACK,6L);
11051 red=ScaleQuantumToShort(image->background_color.red);
11052 green=ScaleQuantumToShort(image->background_color.green);
11053 blue=ScaleQuantumToShort(image->background_color.blue);
11054 PNGShort(chunk+4,red);
11055 PNGShort(chunk+6,green);
11056 PNGShort(chunk+8,blue);
11057 (void) WriteBlob(image,10,chunk);
11058 (void) WriteBlobMSBULong(image,crc32(0,chunk,10));
11059 if (mng_info->equal_backgrounds)
11061 (void) WriteBlobMSBULong(image,6L);
11062 PNGType(chunk,mng_bKGD);
11063 LogPNGChunk(logging,mng_bKGD,6L);
11064 (void) WriteBlob(image,10,chunk);
11065 (void) WriteBlobMSBULong(image,crc32(0,chunk,10));
11069 #ifdef PNG_WRITE_EMPTY_PLTE_SUPPORTED
11070 if ((need_local_plte == MagickFalse) &&
11071 (image->storage_class == PseudoClass) &&
11072 (all_images_are_gray == MagickFalse))
11078 Write MNG PLTE chunk
11080 data_length=3*image->colors;
11081 (void) WriteBlobMSBULong(image,data_length);
11082 PNGType(chunk,mng_PLTE);
11083 LogPNGChunk(logging,mng_PLTE,data_length);
11085 for (i=0; i < (ssize_t) image->colors; i++)
11087 chunk[4+i*3]=ScaleQuantumToChar(image->colormap[i].red) & 0xff;
11088 chunk[5+i*3]=ScaleQuantumToChar(image->colormap[i].green) & 0xff;
11089 chunk[6+i*3]=ScaleQuantumToChar(image->colormap[i].blue) & 0xff;
11092 (void) WriteBlob(image,data_length+4,chunk);
11093 (void) WriteBlobMSBULong(image,crc32(0,chunk,(uInt) (data_length+4)));
11094 mng_info->have_write_global_plte=MagickTrue;
11100 #if defined(PNG_WRITE_EMPTY_PLTE_SUPPORTED) || \
11101 defined(PNG_MNG_FEATURES_SUPPORTED)
11102 mng_info->equal_palettes=MagickFalse;
11106 if (mng_info->adjoin)
11108 #if defined(PNG_WRITE_EMPTY_PLTE_SUPPORTED) || \
11109 defined(PNG_MNG_FEATURES_SUPPORTED)
11111 If we aren't using a global palette for the entire MNG, check to
11112 see if we can use one for two or more consecutive images.
11114 if (need_local_plte && use_global_plte && !all_images_are_gray)
11116 if (mng_info->IsPalette)
11119 When equal_palettes is true, this image has the same palette
11120 as the previous PseudoClass image
11122 mng_info->have_write_global_plte=mng_info->equal_palettes;
11123 mng_info->equal_palettes=PalettesAreEqual(image,image->next);
11124 if (mng_info->equal_palettes && !mng_info->have_write_global_plte)
11127 Write MNG PLTE chunk
11132 data_length=3*image->colors;
11133 (void) WriteBlobMSBULong(image,data_length);
11134 PNGType(chunk,mng_PLTE);
11135 LogPNGChunk(logging,mng_PLTE,data_length);
11137 for (i=0; i < (ssize_t) image->colors; i++)
11139 chunk[4+i*3]=ScaleQuantumToChar(image->colormap[i].red);
11140 chunk[5+i*3]=ScaleQuantumToChar(image->colormap[i].green);
11141 chunk[6+i*3]=ScaleQuantumToChar(image->colormap[i].blue);
11144 (void) WriteBlob(image,data_length+4,chunk);
11145 (void) WriteBlobMSBULong(image,crc32(0,chunk,
11146 (uInt) (data_length+4)));
11147 mng_info->have_write_global_plte=MagickTrue;
11151 mng_info->have_write_global_plte=MagickFalse;
11162 previous_x=mng_info->page.x;
11163 previous_y=mng_info->page.y;
11170 mng_info->page=image->page;
11171 if ((mng_info->page.x != previous_x) ||
11172 (mng_info->page.y != previous_y))
11174 (void) WriteBlobMSBULong(image,12L); /* data length=12 */
11175 PNGType(chunk,mng_DEFI);
11176 LogPNGChunk(logging,mng_DEFI,12L);
11177 chunk[4]=0; /* object 0 MSB */
11178 chunk[5]=0; /* object 0 LSB */
11179 chunk[6]=0; /* visible */
11180 chunk[7]=0; /* abstract */
11181 PNGLong(chunk+8,(png_uint_32) mng_info->page.x);
11182 PNGLong(chunk+12,(png_uint_32) mng_info->page.y);
11183 (void) WriteBlob(image,16,chunk);
11184 (void) WriteBlobMSBULong(image,crc32(0,chunk,16));
11189 mng_info->write_mng=write_mng;
11191 if ((int) image->dispose >= 3)
11192 mng_info->framing_mode=3;
11194 if (mng_info->need_fram && mng_info->adjoin &&
11195 ((image->delay != mng_info->delay) ||
11196 (mng_info->framing_mode != mng_info->old_framing_mode)))
11198 if (image->delay == mng_info->delay)
11201 Write a MNG FRAM chunk with the new framing mode.
11203 (void) WriteBlobMSBULong(image,1L); /* data length=1 */
11204 PNGType(chunk,mng_FRAM);
11205 LogPNGChunk(logging,mng_FRAM,1L);
11206 chunk[4]=(unsigned char) mng_info->framing_mode;
11207 (void) WriteBlob(image,5,chunk);
11208 (void) WriteBlobMSBULong(image,crc32(0,chunk,5));
11213 Write a MNG FRAM chunk with the delay.
11215 (void) WriteBlobMSBULong(image,10L); /* data length=10 */
11216 PNGType(chunk,mng_FRAM);
11217 LogPNGChunk(logging,mng_FRAM,10L);
11218 chunk[4]=(unsigned char) mng_info->framing_mode;
11219 chunk[5]=0; /* frame name separator (no name) */
11220 chunk[6]=2; /* flag for changing default delay */
11221 chunk[7]=0; /* flag for changing frame timeout */
11222 chunk[8]=0; /* flag for changing frame clipping */
11223 chunk[9]=0; /* flag for changing frame sync_id */
11224 PNGLong(chunk+10,(png_uint_32)
11225 ((mng_info->ticks_per_second*
11226 image->delay)/MagickMax(image->ticks_per_second,1)));
11227 (void) WriteBlob(image,14,chunk);
11228 (void) WriteBlobMSBULong(image,crc32(0,chunk,14));
11229 mng_info->delay=(png_uint_32) image->delay;
11231 mng_info->old_framing_mode=mng_info->framing_mode;
11234 #if defined(JNG_SUPPORTED)
11235 if (image_info->compression == JPEGCompression)
11240 if (logging != MagickFalse)
11241 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11242 " Writing JNG object.");
11243 /* To do: specify the desired alpha compression method. */
11244 write_info=CloneImageInfo(image_info);
11245 write_info->compression=UndefinedCompression;
11246 status=WriteOneJNGImage(mng_info,write_info,image);
11247 write_info=DestroyImageInfo(write_info);
11252 if (logging != MagickFalse)
11253 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11254 " Writing PNG object.");
11256 mng_info->need_blob = MagickFalse;
11258 /* We don't want any ancillary chunks written */
11259 mng_info->ping_exclude_bKGD=MagickTrue;
11260 mng_info->ping_exclude_cHRM=MagickTrue;
11261 mng_info->ping_exclude_EXIF=MagickTrue;
11262 mng_info->ping_exclude_gAMA=MagickTrue;
11263 mng_info->ping_exclude_cHRM=MagickTrue;
11264 mng_info->ping_exclude_iCCP=MagickTrue;
11265 /* mng_info->ping_exclude_iTXt=MagickTrue; */
11266 mng_info->ping_exclude_oFFs=MagickTrue;
11267 mng_info->ping_exclude_pHYs=MagickTrue;
11268 mng_info->ping_exclude_sRGB=MagickTrue;
11269 mng_info->ping_exclude_tEXt=MagickTrue;
11270 mng_info->ping_exclude_tRNS=MagickTrue;
11271 mng_info->ping_exclude_vpAg=MagickTrue;
11272 mng_info->ping_exclude_zCCP=MagickTrue;
11273 mng_info->ping_exclude_zTXt=MagickTrue;
11275 status=WriteOnePNGImage(mng_info,image_info,image);
11278 if (status == MagickFalse)
11280 MngInfoFreeStruct(mng_info,&have_mng_structure);
11281 (void) CloseBlob(image);
11282 return(MagickFalse);
11284 (void) CatchImageException(image);
11285 if (GetNextImageInList(image) == (Image *) NULL)
11287 image=SyncNextImageInList(image);
11288 status=SetImageProgress(image,SaveImagesTag,scene++,
11289 GetImageListLength(image));
11291 if (status == MagickFalse)
11294 } while (mng_info->adjoin);
11298 while (GetPreviousImageInList(image) != (Image *) NULL)
11299 image=GetPreviousImageInList(image);
11301 Write the MEND chunk.
11303 (void) WriteBlobMSBULong(image,0x00000000L);
11304 PNGType(chunk,mng_MEND);
11305 LogPNGChunk(logging,mng_MEND,0L);
11306 (void) WriteBlob(image,4,chunk);
11307 (void) WriteBlobMSBULong(image,crc32(0,chunk,4));
11310 Relinquish resources.
11312 (void) CloseBlob(image);
11313 MngInfoFreeStruct(mng_info,&have_mng_structure);
11315 if (logging != MagickFalse)
11316 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"exit WriteMNGImage()");
11318 return(MagickTrue);
11320 #else /* PNG_LIBPNG_VER > 10011 */
11322 static MagickBooleanType WritePNGImage(const ImageInfo *image_info,Image *image)
11325 printf("Your PNG library is too old: You have libpng-%s\n",
11326 PNG_LIBPNG_VER_STRING);
11328 ThrowBinaryException(CoderError,"PNG library is too old",
11329 image_info->filename);
11332 static MagickBooleanType WriteMNGImage(const ImageInfo *image_info,Image *image)
11334 return(WritePNGImage(image_info,image));
11336 #endif /* PNG_LIBPNG_VER > 10011 */