2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13 % Read/Write Magick Persistant Cache Image Format %
20 % Copyright 1999-2012 ImageMagick Studio LLC, a non-profit organization %
21 % dedicated to making software imaging solutions freely available. %
23 % You may not use this file except in compliance with the License. You may %
24 % obtain a copy of the License at %
26 % http://www.imagemagick.org/script/license.php %
28 % Unless required by applicable law or agreed to in writing, software %
29 % distributed under the License is distributed on an "AS IS" BASIS, %
30 % WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %
31 % See the License for the specific language governing permissions and %
32 % limitations under the License. %
34 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
43 #include "MagickCore/studio.h"
44 #include "MagickCore/artifact.h"
45 #include "MagickCore/attribute.h"
46 #include "MagickCore/blob.h"
47 #include "MagickCore/blob-private.h"
48 #include "MagickCore/cache.h"
49 #include "MagickCore/color.h"
50 #include "MagickCore/color-private.h"
51 #include "MagickCore/colormap.h"
52 #include "MagickCore/constitute.h"
53 #include "MagickCore/exception.h"
54 #include "MagickCore/exception-private.h"
55 #include "MagickCore/geometry.h"
56 #include "MagickCore/hashmap.h"
57 #include "MagickCore/image.h"
58 #include "MagickCore/image-private.h"
59 #include "MagickCore/list.h"
60 #include "MagickCore/magick.h"
61 #include "MagickCore/memory_.h"
62 #include "MagickCore/module.h"
63 #include "MagickCore/monitor.h"
64 #include "MagickCore/monitor-private.h"
65 #include "MagickCore/option.h"
66 #include "MagickCore/profile.h"
67 #include "MagickCore/property.h"
68 #include "MagickCore/quantum-private.h"
69 #include "MagickCore/static.h"
70 #include "MagickCore/statistic.h"
71 #include "MagickCore/string_.h"
72 #include "MagickCore/string-private.h"
73 #include "MagickCore/utility.h"
78 static MagickBooleanType
79 WriteMPCImage(const ImageInfo *,Image *,ExceptionInfo *);
82 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
90 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
92 % IsMPC() returns MagickTrue if the image format type, identified by the
93 % magick string, is an Magick Persistent Cache image.
95 % The format of the IsMPC method is:
97 % MagickBooleanType IsMPC(const unsigned char *magick,const size_t length)
99 % A description of each parameter follows:
101 % o magick: compare image format pattern against these bytes.
103 % o length: Specifies the length of the magick string.
106 static MagickBooleanType IsMPC(const unsigned char *magick,const size_t length)
110 if (LocaleNCompare((const char *) magick,"id=MagickCache",14) == 0)
116 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
120 % R e a d C A C H E I m a g e %
124 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
126 % ReadMPCImage() reads an Magick Persistent Cache image file and returns
127 % it. It allocates the memory necessary for the new Image structure and
128 % returns a pointer to the new image.
130 % The format of the ReadMPCImage method is:
132 % Image *ReadMPCImage(const ImageInfo *image_info,ExceptionInfo *exception)
134 % Decompression code contributed by Kyle Shorter.
136 % A description of each parameter follows:
138 % o image_info: the image info.
140 % o exception: return any errors or warnings in this structure.
143 static Image *ReadMPCImage(const ImageInfo *image_info,ExceptionInfo *exception)
146 cache_filename[MaxTextExtent],
148 keyword[MaxTextExtent],
192 assert(image_info != (const ImageInfo *) NULL);
193 assert(image_info->signature == MagickSignature);
194 if (image_info->debug != MagickFalse)
195 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
196 image_info->filename);
197 assert(exception != (ExceptionInfo *) NULL);
198 assert(exception->signature == MagickSignature);
199 image=AcquireImage(image_info,exception);
200 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
201 if (status == MagickFalse)
203 image=DestroyImageList(image);
204 return((Image *) NULL);
206 (void) CopyMagickString(cache_filename,image->filename,MaxTextExtent);
207 AppendImageFormat("cache",cache_filename);
208 c=ReadBlobByte(image);
211 image=DestroyImage(image);
212 return((Image *) NULL);
215 (void) ResetMagickMemory(keyword,0,sizeof(keyword));
220 Decode image header; header terminates one character beyond a ':'.
222 profiles=(LinkedListInfo *) NULL;
223 length=MaxTextExtent;
224 options=AcquireString((char *) NULL);
225 quantum_depth=MAGICKCORE_QUANTUM_DEPTH;
227 image->compression=NoCompression;
228 while ((isgraph(c) != MagickFalse) && (c != (int) ':'))
239 Read comment-- any text between { }.
241 length=MaxTextExtent;
242 comment=AcquireString((char *) NULL);
243 for (p=comment; comment != (char *) NULL; p++)
245 c=ReadBlobByte(image);
247 c=ReadBlobByte(image);
249 if ((c == EOF) || (c == (int) '}'))
251 if ((size_t) (p-comment+1) >= length)
255 comment=(char *) ResizeQuantumMemory(comment,length+
256 MaxTextExtent,sizeof(*comment));
257 if (comment == (char *) NULL)
259 p=comment+strlen(comment);
263 if (comment == (char *) NULL)
264 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
266 (void) SetImageProperty(image,"comment",comment,exception);
267 comment=DestroyString(comment);
268 c=ReadBlobByte(image);
271 if (isalnum(c) != MagickFalse)
281 if ((size_t) (p-keyword) < (MaxTextExtent-1))
283 c=ReadBlobByte(image);
287 while (isspace((int) ((unsigned char) c)) != 0)
288 c=ReadBlobByte(image);
292 Get the keyword value.
294 c=ReadBlobByte(image);
295 while ((c != (int) '}') && (c != EOF))
297 if ((size_t) (p-options+1) >= length)
301 options=(char *) ResizeQuantumMemory(options,length+
302 MaxTextExtent,sizeof(*options));
303 if (options == (char *) NULL)
305 p=options+strlen(options);
307 if (options == (char *) NULL)
308 ThrowReaderException(ResourceLimitError,
309 "MemoryAllocationFailed");
311 c=ReadBlobByte(image);
314 c=ReadBlobByte(image);
318 c=ReadBlobByte(image);
322 if (isspace((int) ((unsigned char) c)) != 0)
328 (void) strcpy(options,options+1);
330 Assign a value to the specified keyword.
337 if (LocaleCompare(keyword,"background-color") == 0)
339 (void) QueryColorCompliance(options,AllCompliance,
340 &image->background_color,exception);
343 if (LocaleCompare(keyword,"blue-primary") == 0)
345 flags=ParseGeometry(options,&geometry_info);
346 image->chromaticity.blue_primary.x=geometry_info.rho;
347 image->chromaticity.blue_primary.y=geometry_info.sigma;
348 if ((flags & SigmaValue) == 0)
349 image->chromaticity.blue_primary.y=
350 image->chromaticity.blue_primary.x;
353 if (LocaleCompare(keyword,"border-color") == 0)
355 (void) QueryColorCompliance(options,AllCompliance,
356 &image->border_color,exception);
359 (void) SetImageProperty(image,keyword,options,exception);
365 if (LocaleCompare(keyword,"class") == 0)
370 storage_class=ParseCommandOption(MagickClassOptions,
371 MagickFalse,options);
372 if (storage_class < 0)
374 image->storage_class=(ClassType) storage_class;
377 if (LocaleCompare(keyword,"colors") == 0)
379 image->colors=StringToUnsignedLong(options);
382 if (LocaleCompare(keyword,"colorspace") == 0)
387 colorspace=ParseCommandOption(MagickColorspaceOptions,
388 MagickFalse,options);
391 image->colorspace=(ColorspaceType) colorspace;
394 if (LocaleCompare(keyword,"compression") == 0)
399 compression=ParseCommandOption(MagickCompressOptions,
400 MagickFalse,options);
403 image->compression=(CompressionType) compression;
406 if (LocaleCompare(keyword,"columns") == 0)
408 image->columns=StringToUnsignedLong(options);
411 (void) SetImageProperty(image,keyword,options,exception);
417 if (LocaleCompare(keyword,"delay") == 0)
419 image->delay=StringToUnsignedLong(options);
422 if (LocaleCompare(keyword,"depth") == 0)
424 image->depth=StringToUnsignedLong(options);
427 if (LocaleCompare(keyword,"dispose") == 0)
432 dispose=ParseCommandOption(MagickDisposeOptions,MagickFalse,
436 image->dispose=(DisposeType) dispose;
439 (void) SetImageProperty(image,keyword,options,exception);
445 if (LocaleCompare(keyword,"endian") == 0)
450 endian=ParseCommandOption(MagickEndianOptions,MagickFalse,
454 image->endian=(EndianType) endian;
457 if (LocaleCompare(keyword,"error") == 0)
459 image->error.mean_error_per_pixel=StringToDouble(options,
463 (void) SetImageProperty(image,keyword,options,exception);
469 if (LocaleCompare(keyword,"gamma") == 0)
471 image->gamma=StringToDouble(options,(char **) NULL);
474 if (LocaleCompare(keyword,"green-primary") == 0)
476 flags=ParseGeometry(options,&geometry_info);
477 image->chromaticity.green_primary.x=geometry_info.rho;
478 image->chromaticity.green_primary.y=geometry_info.sigma;
479 if ((flags & SigmaValue) == 0)
480 image->chromaticity.green_primary.y=
481 image->chromaticity.green_primary.x;
484 (void) SetImageProperty(image,keyword,options,exception);
490 if (LocaleCompare(keyword,"id") == 0)
492 (void) CopyMagickString(id,options,MaxTextExtent);
495 if (LocaleCompare(keyword,"iterations") == 0)
497 image->iterations=StringToUnsignedLong(options);
500 (void) SetImageProperty(image,keyword,options,exception);
506 if (LocaleCompare(keyword,"matte") == 0)
511 matte=ParseCommandOption(MagickBooleanOptions,MagickFalse,
515 image->matte=(MagickBooleanType) matte;
518 if (LocaleCompare(keyword,"matte-color") == 0)
520 (void) QueryColorCompliance(options,AllCompliance,
521 &image->matte_color,exception);
524 if (LocaleCompare(keyword,"maximum-error") == 0)
526 image->error.normalized_maximum_error=StringToDouble(
527 options,(char **) NULL);
530 if (LocaleCompare(keyword,"mean-error") == 0)
532 image->error.normalized_mean_error=StringToDouble(options,
536 if (LocaleCompare(keyword,"montage") == 0)
538 (void) CloneString(&image->montage,options);
541 (void) SetImageProperty(image,keyword,options,exception);
547 if (LocaleCompare(keyword,"opaque") == 0)
552 matte=ParseCommandOption(MagickBooleanOptions,MagickFalse,
556 image->matte=(MagickBooleanType) matte;
559 if (LocaleCompare(keyword,"orientation") == 0)
564 orientation=ParseCommandOption(MagickOrientationOptions,
565 MagickFalse,options);
568 image->orientation=(OrientationType) orientation;
571 (void) SetImageProperty(image,keyword,options,exception);
577 if (LocaleCompare(keyword,"page") == 0)
582 geometry=GetPageGeometry(options);
583 (void) ParseAbsoluteGeometry(geometry,&image->page);
584 geometry=DestroyString(geometry);
587 if ((LocaleNCompare(keyword,"profile:",8) == 0) ||
588 (LocaleNCompare(keyword,"profile-",8) == 0))
590 if (profiles == (LinkedListInfo *) NULL)
591 profiles=NewLinkedList(0);
592 (void) AppendValueToLinkedList(profiles,
593 AcquireString(keyword+8));
594 profile=BlobToStringInfo((const void *) NULL,(size_t)
595 StringToLong(options));
596 if (profile == (StringInfo *) NULL)
597 ThrowReaderException(ResourceLimitError,
598 "MemoryAllocationFailed");
599 (void) SetImageProfile(image,keyword+8,profile,exception);
600 profile=DestroyStringInfo(profile);
603 (void) SetImageProperty(image,keyword,options,exception);
609 if (LocaleCompare(keyword,"quality") == 0)
611 image->quality=StringToUnsignedLong(options);
614 if (LocaleCompare(keyword,"quantum-depth") == 0)
616 quantum_depth=StringToUnsignedLong(options);
619 (void) SetImageProperty(image,keyword,options,exception);
625 if (LocaleCompare(keyword,"red-primary") == 0)
627 flags=ParseGeometry(options,&geometry_info);
628 image->chromaticity.red_primary.x=geometry_info.rho;
629 if ((flags & SigmaValue) != 0)
630 image->chromaticity.red_primary.y=geometry_info.sigma;
633 if (LocaleCompare(keyword,"rendering-intent") == 0)
638 rendering_intent=ParseCommandOption(MagickIntentOptions,
639 MagickFalse,options);
640 if (rendering_intent < 0)
642 image->rendering_intent=(RenderingIntent) rendering_intent;
645 if (LocaleCompare(keyword,"resolution") == 0)
647 flags=ParseGeometry(options,&geometry_info);
648 image->resolution.x=geometry_info.rho;
649 image->resolution.y=geometry_info.sigma;
650 if ((flags & SigmaValue) == 0)
651 image->resolution.y=image->resolution.x;
654 if (LocaleCompare(keyword,"rows") == 0)
656 image->rows=StringToUnsignedLong(options);
659 (void) SetImageProperty(image,keyword,options,exception);
665 if (LocaleCompare(keyword,"scene") == 0)
667 image->scene=StringToUnsignedLong(options);
670 (void) SetImageProperty(image,keyword,options,exception);
676 if (LocaleCompare(keyword,"ticks-per-second") == 0)
678 image->ticks_per_second=(ssize_t) StringToLong(options);
681 if (LocaleCompare(keyword,"tile-offset") == 0)
686 geometry=GetPageGeometry(options);
687 (void) ParseAbsoluteGeometry(geometry,&image->tile_offset);
688 geometry=DestroyString(geometry);
690 if (LocaleCompare(keyword,"type") == 0)
695 type=ParseCommandOption(MagickTypeOptions,MagickFalse,
699 image->type=(ImageType) type;
702 (void) SetImageProperty(image,keyword,options,exception);
708 if (LocaleCompare(keyword,"units") == 0)
713 units=ParseCommandOption(MagickResolutionOptions,
714 MagickFalse,options);
717 image->units=(ResolutionType) units;
720 (void) SetImageProperty(image,keyword,options,exception);
726 if (LocaleCompare(keyword,"white-point") == 0)
728 flags=ParseGeometry(options,&geometry_info);
729 image->chromaticity.white_point.x=geometry_info.rho;
730 image->chromaticity.white_point.y=geometry_info.sigma;
731 if ((flags & SigmaValue) == 0)
732 image->chromaticity.white_point.y=
733 image->chromaticity.white_point.x;
736 (void) SetImageProperty(image,keyword,options,exception);
741 (void) SetImageProperty(image,keyword,options,exception);
747 c=ReadBlobByte(image);
748 while (isspace((int) ((unsigned char) c)) != 0)
749 c=ReadBlobByte(image);
751 options=DestroyString(options);
752 (void) ReadBlobByte(image);
754 Verify that required image information is defined.
756 if ((LocaleCompare(id,"MagickCache") != 0) ||
757 (image->storage_class == UndefinedClass) ||
758 (image->compression == UndefinedCompression) || (image->columns == 0) ||
760 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
761 if (quantum_depth != MAGICKCORE_QUANTUM_DEPTH)
762 ThrowReaderException(CacheError,"InconsistentPersistentCacheDepth");
763 if (image->montage != (char *) NULL)
771 length=MaxTextExtent;
772 image->directory=AcquireString((char *) NULL);
777 if ((strlen(image->directory)+MaxTextExtent) >= length)
780 Allocate more memory for the image directory.
783 image->directory=(char *) ResizeQuantumMemory(image->directory,
784 length+MaxTextExtent,sizeof(*image->directory));
785 if (image->directory == (char *) NULL)
786 ThrowReaderException(CorruptImageError,"UnableToReadImageData");
787 p=image->directory+strlen(image->directory);
789 c=ReadBlobByte(image);
791 } while (c != (int) '\0');
793 if (profiles != (LinkedListInfo *) NULL)
801 register unsigned char
807 ResetLinkedListIterator(profiles);
808 name=(const char *) GetNextValueInLinkedList(profiles);
809 while (name != (const char *) NULL)
811 profile=GetImageProfile(image,name);
812 if (profile != (StringInfo *) NULL)
814 p=GetStringInfoDatum(profile);
815 count=ReadBlob(image,GetStringInfoLength(profile),p);
817 name=(const char *) GetNextValueInLinkedList(profiles);
819 profiles=DestroyLinkedList(profiles,RelinquishMagickMemory);
821 depth=GetImageQuantumDepth(image,MagickFalse);
822 if (image->storage_class == PseudoClass)
825 Create image colormap.
827 if (AcquireImageColormap(image,image->colors,exception) == MagickFalse)
828 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
829 if (image->colors != 0)
838 Read image colormap from file.
840 packet_size=(size_t) (3UL*depth/8UL);
841 colormap=(unsigned char *) AcquireQuantumMemory(image->colors,
842 packet_size*sizeof(*colormap));
843 if (colormap == (unsigned char *) NULL)
844 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
845 count=ReadBlob(image,packet_size*image->colors,colormap);
846 if (count != (ssize_t) (packet_size*image->colors))
847 ThrowReaderException(CorruptImageError,
848 "InsufficientImageDataInFile");
853 ThrowReaderException(CorruptImageError,
854 "ImageDepthNotSupported");
860 for (i=0; i < (ssize_t) image->colors; i++)
862 p=PushCharPixel(p,&pixel);
863 image->colormap[i].red=ScaleCharToQuantum(pixel);
864 p=PushCharPixel(p,&pixel);
865 image->colormap[i].green=ScaleCharToQuantum(pixel);
866 p=PushCharPixel(p,&pixel);
867 image->colormap[i].blue=ScaleCharToQuantum(pixel);
876 for (i=0; i < (ssize_t) image->colors; i++)
878 p=PushShortPixel(MSBEndian,p,&pixel);
879 image->colormap[i].red=ScaleShortToQuantum(pixel);
880 p=PushShortPixel(MSBEndian,p,&pixel);
881 image->colormap[i].green=ScaleShortToQuantum(pixel);
882 p=PushShortPixel(MSBEndian,p,&pixel);
883 image->colormap[i].blue=ScaleShortToQuantum(pixel);
892 for (i=0; i < (ssize_t) image->colors; i++)
894 p=PushLongPixel(MSBEndian,p,&pixel);
895 image->colormap[i].red=ScaleLongToQuantum(pixel);
896 p=PushLongPixel(MSBEndian,p,&pixel);
897 image->colormap[i].green=ScaleLongToQuantum(pixel);
898 p=PushLongPixel(MSBEndian,p,&pixel);
899 image->colormap[i].blue=ScaleLongToQuantum(pixel);
904 colormap=(unsigned char *) RelinquishMagickMemory(colormap);
907 if (EOFBlob(image) != MagickFalse)
909 ThrowFileException(exception,CorruptImageError,"UnexpectedEndOfFile",
913 if ((image_info->ping != MagickFalse) && (image_info->number_scenes != 0))
914 if (image->scene >= (image_info->scene+image_info->number_scenes-1))
917 Attach persistent pixel cache.
919 status=PersistPixelCache(image,cache_filename,MagickTrue,&offset,exception);
920 if (status == MagickFalse)
921 ThrowReaderException(CacheError,"UnableToPersistPixelCache");
923 Proceed to next image.
927 c=ReadBlobByte(image);
928 } while ((isgraph(c) == MagickFalse) && (c != EOF));
932 Allocate next image structure.
934 AcquireNextImage(image_info,image,exception);
935 if (GetNextImageInList(image) == (Image *) NULL)
937 image=DestroyImageList(image);
938 return((Image *) NULL);
940 image=SyncNextImageInList(image);
941 status=SetImageProgress(image,LoadImagesTag,TellBlob(image),
943 if (status == MagickFalse)
947 (void) CloseBlob(image);
948 return(GetFirstImageInList(image));
952 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
956 % R e g i s t e r M P C I m a g e %
960 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
962 % RegisterMPCImage() adds properties for the Cache image format to
963 % the list of supported formats. The properties include the image format
964 % tag, a method to read and/or write the format, whether the format
965 % supports the saving of more than one frame to the same file or blob,
966 % whether the format supports native in-memory I/O, and a brief
967 % description of the format.
969 % The format of the RegisterMPCImage method is:
971 % size_t RegisterMPCImage(void)
974 ModuleExport size_t RegisterMPCImage(void)
979 entry=SetMagickInfo("CACHE");
980 entry->description=ConstantString("Magick Persistent Cache image format");
981 entry->module=ConstantString("CACHE");
982 entry->stealth=MagickTrue;
983 (void) RegisterMagickInfo(entry);
984 entry=SetMagickInfo("MPC");
985 entry->decoder=(DecodeImageHandler *) ReadMPCImage;
986 entry->encoder=(EncodeImageHandler *) WriteMPCImage;
987 entry->magick=(IsImageFormatHandler *) IsMPC;
988 entry->description=ConstantString("Magick Persistent Cache image format");
989 entry->module=ConstantString("MPC");
990 (void) RegisterMagickInfo(entry);
991 return(MagickImageCoderSignature);
995 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
999 % U n r e g i s t e r M P C I m a g e %
1003 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1005 % UnregisterMPCImage() removes format registrations made by the
1006 % MPC module from the list of supported formats.
1008 % The format of the UnregisterMPCImage method is:
1010 % UnregisterMPCImage(void)
1013 ModuleExport void UnregisterMPCImage(void)
1015 (void) UnregisterMagickInfo("CACHE");
1016 (void) UnregisterMagickInfo("MPC");
1020 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1024 % W r i t e M P C I m a g e %
1028 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1030 % WriteMPCImage() writes an Magick Persistent Cache image to a file.
1032 % The format of the WriteMPCImage method is:
1034 % MagickBooleanType WriteMPCImage(const ImageInfo *image_info,
1035 % Image *image,ExceptionInfo *exception)
1037 % A description of each parameter follows:
1039 % o image_info: the image info.
1041 % o image: the image.
1043 % o exception: return any errors or warnings in this structure.
1046 static MagickBooleanType WriteMPCImage(const ImageInfo *image_info,Image *image,
1047 ExceptionInfo *exception)
1050 buffer[MaxTextExtent],
1051 cache_filename[MaxTextExtent];
1072 Open persistent cache.
1074 assert(image_info != (const ImageInfo *) NULL);
1075 assert(image_info->signature == MagickSignature);
1076 assert(image != (Image *) NULL);
1077 assert(image->signature == MagickSignature);
1078 if (image->debug != MagickFalse)
1079 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1080 assert(exception != (ExceptionInfo *) NULL);
1081 assert(exception->signature == MagickSignature);
1082 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
1083 if (status == MagickFalse)
1085 (void) CopyMagickString(cache_filename,image->filename,MaxTextExtent);
1086 AppendImageFormat("cache",cache_filename);
1093 Write persistent cache meta-information.
1095 depth=GetImageQuantumDepth(image,MagickTrue);
1096 if ((image->storage_class == PseudoClass) &&
1097 (image->colors > (one << depth)))
1098 image->storage_class=DirectClass;
1099 (void) WriteBlobString(image,"id=MagickCache\n");
1100 (void) FormatLocaleString(buffer,MaxTextExtent,"quantum-depth=%d\n",
1101 MAGICKCORE_QUANTUM_DEPTH);
1102 (void) WriteBlobString(image,buffer);
1103 (void) FormatLocaleString(buffer,MaxTextExtent,
1104 "class=%s colors=%.20g matte=%s\n",CommandOptionToMnemonic(
1105 MagickClassOptions,image->storage_class),(double) image->colors,
1106 CommandOptionToMnemonic(MagickBooleanOptions,(ssize_t) image->matte));
1107 (void) WriteBlobString(image,buffer);
1108 (void) FormatLocaleString(buffer,MaxTextExtent,
1109 "columns=%.20g rows=%.20g depth=%.20g\n",(double) image->columns,
1110 (double) image->rows,(double) image->depth);
1111 (void) WriteBlobString(image,buffer);
1112 if (image->type != UndefinedType)
1114 (void) FormatLocaleString(buffer,MaxTextExtent,"type=%s\n",
1115 CommandOptionToMnemonic(MagickTypeOptions,image->type));
1116 (void) WriteBlobString(image,buffer);
1118 if (image->colorspace != UndefinedColorspace)
1120 (void) FormatLocaleString(buffer,MaxTextExtent,"colorspace=%s\n",
1121 CommandOptionToMnemonic(MagickColorspaceOptions,image->colorspace));
1122 (void) WriteBlobString(image,buffer);
1124 if (image->endian != UndefinedEndian)
1126 (void) FormatLocaleString(buffer,MaxTextExtent,"endian=%s\n",
1127 CommandOptionToMnemonic(MagickEndianOptions,image->endian));
1128 (void) WriteBlobString(image,buffer);
1130 if (image->compression != UndefinedCompression)
1132 (void) FormatLocaleString(buffer,MaxTextExtent,
1133 "compression=%s quality=%.20g\n",CommandOptionToMnemonic(
1134 MagickCompressOptions,image->compression),(double) image->quality);
1135 (void) WriteBlobString(image,buffer);
1137 if (image->units != UndefinedResolution)
1139 (void) FormatLocaleString(buffer,MaxTextExtent,"units=%s\n",
1140 CommandOptionToMnemonic(MagickResolutionOptions,image->units));
1141 (void) WriteBlobString(image,buffer);
1143 if ((image->resolution.x != 0) || (image->resolution.y != 0))
1145 (void) FormatLocaleString(buffer,MaxTextExtent,
1146 "resolution=%gx%g\n",image->resolution.x,image->resolution.y);
1147 (void) WriteBlobString(image,buffer);
1149 if ((image->page.width != 0) || (image->page.height != 0))
1151 (void) FormatLocaleString(buffer,MaxTextExtent,
1152 "page=%.20gx%.20g%+.20g%+.20g\n",(double) image->page.width,(double)
1153 image->page.height,(double) image->page.x,(double) image->page.y);
1154 (void) WriteBlobString(image,buffer);
1157 if ((image->page.x != 0) || (image->page.y != 0))
1159 (void) FormatLocaleString(buffer,MaxTextExtent,"page=%+ld%+ld\n",
1160 (long) image->page.x,(long) image->page.y);
1161 (void) WriteBlobString(image,buffer);
1163 if ((image->page.x != 0) || (image->page.y != 0))
1165 (void) FormatLocaleString(buffer,MaxTextExtent,"tile-offset=%+ld%+ld\n",
1166 (long) image->tile_offset.x,(long) image->tile_offset.y);
1167 (void) WriteBlobString(image,buffer);
1169 if ((GetNextImageInList(image) != (Image *) NULL) ||
1170 (GetPreviousImageInList(image) != (Image *) NULL))
1172 if (image->scene == 0)
1173 (void) FormatLocaleString(buffer,MaxTextExtent,
1174 "iterations=%.20g delay=%.20g ticks-per-second=%.20g\n",(double)
1175 image->iterations,(double) image->delay,(double)
1176 image->ticks_per_second);
1178 (void) FormatLocaleString(buffer,MaxTextExtent,"scene=%.20g "
1179 "iterations=%.20g delay=%.20g ticks-per-second=%.20g\n",
1180 (double) image->scene,(double) image->iterations,(double)
1181 image->delay,(double) image->ticks_per_second);
1182 (void) WriteBlobString(image,buffer);
1186 if (image->scene != 0)
1188 (void) FormatLocaleString(buffer,MaxTextExtent,"scene=%.20g\n",
1189 (double) image->scene);
1190 (void) WriteBlobString(image,buffer);
1192 if (image->iterations != 0)
1194 (void) FormatLocaleString(buffer,MaxTextExtent,"iterations=%.20g\n",
1195 (double) image->iterations);
1196 (void) WriteBlobString(image,buffer);
1198 if (image->delay != 0)
1200 (void) FormatLocaleString(buffer,MaxTextExtent,"delay=%.20g\n",
1201 (double) image->delay);
1202 (void) WriteBlobString(image,buffer);
1204 if (image->ticks_per_second != UndefinedTicksPerSecond)
1206 (void) FormatLocaleString(buffer,MaxTextExtent,
1207 "ticks-per-second=%.20g\n",(double) image->ticks_per_second);
1208 (void) WriteBlobString(image,buffer);
1211 if (image->gravity != UndefinedGravity)
1213 (void) FormatLocaleString(buffer,MaxTextExtent,"gravity=%s\n",
1214 CommandOptionToMnemonic(MagickGravityOptions,image->gravity));
1215 (void) WriteBlobString(image,buffer);
1217 if (image->dispose != UndefinedDispose)
1219 (void) FormatLocaleString(buffer,MaxTextExtent,"dispose=%s\n",
1220 CommandOptionToMnemonic(MagickDisposeOptions,image->dispose));
1221 (void) WriteBlobString(image,buffer);
1223 if (image->rendering_intent != UndefinedIntent)
1225 (void) FormatLocaleString(buffer,MaxTextExtent,
1226 "rendering-intent=%s\n",CommandOptionToMnemonic(MagickIntentOptions,
1227 image->rendering_intent));
1228 (void) WriteBlobString(image,buffer);
1230 if (image->gamma != 0.0)
1232 (void) FormatLocaleString(buffer,MaxTextExtent,"gamma=%g\n",
1234 (void) WriteBlobString(image,buffer);
1236 if (image->chromaticity.white_point.x != 0.0)
1239 Note chomaticity points.
1241 (void) FormatLocaleString(buffer,MaxTextExtent,"red-primary="
1242 "%g,%g green-primary=%g,%g blue-primary=%g,%g\n",
1243 image->chromaticity.red_primary.x,image->chromaticity.red_primary.y,
1244 image->chromaticity.green_primary.x,
1245 image->chromaticity.green_primary.y,
1246 image->chromaticity.blue_primary.x,
1247 image->chromaticity.blue_primary.y);
1248 (void) WriteBlobString(image,buffer);
1249 (void) FormatLocaleString(buffer,MaxTextExtent,
1250 "white-point=%g,%g\n",image->chromaticity.white_point.x,
1251 image->chromaticity.white_point.y);
1252 (void) WriteBlobString(image,buffer);
1254 if (image->orientation != UndefinedOrientation)
1256 (void) FormatLocaleString(buffer,MaxTextExtent,
1257 "orientation=%s\n",CommandOptionToMnemonic(MagickOrientationOptions,
1258 image->orientation));
1259 (void) WriteBlobString(image,buffer);
1261 if (image->profiles != (void *) NULL)
1272 ResetImageProfileIterator(image);
1273 for (name=GetNextImageProfile(image); name != (const char *) NULL; )
1275 profile=GetImageProfile(image,name);
1276 if (profile != (StringInfo *) NULL)
1278 (void) FormatLocaleString(buffer,MaxTextExtent,
1279 "profile:%s=%.20g\n",name,(double)
1280 GetStringInfoLength(profile));
1281 (void) WriteBlobString(image,buffer);
1283 name=GetNextImageProfile(image);
1286 if (image->montage != (char *) NULL)
1288 (void) FormatLocaleString(buffer,MaxTextExtent,"montage=%s\n",
1290 (void) WriteBlobString(image,buffer);
1292 ResetImagePropertyIterator(image);
1293 property=GetNextImageProperty(image);
1294 while (property != (const char *) NULL)
1296 (void) FormatLocaleString(buffer,MaxTextExtent,"%s=",property);
1297 (void) WriteBlobString(image,buffer);
1298 value=GetImageProperty(image,property,exception);
1299 if (value != (const char *) NULL)
1301 for (i=0; i < (ssize_t) strlen(value); i++)
1302 if (isspace((int) ((unsigned char) value[i])) != 0)
1304 if (i == (ssize_t) strlen(value))
1305 (void) WriteBlob(image,strlen(value),(const unsigned char *) value);
1308 (void) WriteBlobByte(image,'{');
1309 for (i=0; i < (ssize_t) strlen(value); i++)
1311 if (value[i] == (int) '}')
1312 (void) WriteBlobByte(image,'\\');
1313 (void) WriteBlobByte(image,value[i]);
1315 (void) WriteBlobByte(image,'}');
1318 (void) WriteBlobByte(image,'\n');
1319 property=GetNextImageProperty(image);
1321 ResetImageArtifactIterator(image);
1322 (void) WriteBlobString(image,"\f\n:\032");
1323 if (image->montage != (char *) NULL)
1326 Write montage tile directory.
1328 if (image->directory != (char *) NULL)
1329 (void) WriteBlobString(image,image->directory);
1330 (void) WriteBlobByte(image,'\0');
1332 if (image->profiles != 0)
1341 Write image profiles.
1343 ResetImageProfileIterator(image);
1344 name=GetNextImageProfile(image);
1345 while (name != (const char *) NULL)
1347 profile=GetImageProfile(image,name);
1348 (void) WriteBlob(image,GetStringInfoLength(profile),
1349 GetStringInfoDatum(profile));
1350 name=GetNextImageProfile(image);
1353 if (image->storage_class == PseudoClass)
1365 packet_size=(size_t) (3UL*depth/8UL);
1366 colormap=(unsigned char *) AcquireQuantumMemory(image->colors,
1367 packet_size*sizeof(*colormap));
1368 if (colormap == (unsigned char *) NULL)
1369 return(MagickFalse);
1371 Write colormap to file.
1374 for (i=0; i < (ssize_t) image->colors; i++)
1379 ThrowWriterException(CorruptImageError,"ImageDepthNotSupported");
1385 pixel=ScaleQuantumToLong(image->colormap[i].red);
1386 q=PopLongPixel(MSBEndian,pixel,q);
1387 pixel=ScaleQuantumToLong(image->colormap[i].green);
1388 q=PopLongPixel(MSBEndian,pixel,q);
1389 pixel=ScaleQuantumToLong(image->colormap[i].blue);
1390 q=PopLongPixel(MSBEndian,pixel,q);
1397 pixel=ScaleQuantumToShort(image->colormap[i].red);
1398 q=PopShortPixel(MSBEndian,pixel,q);
1399 pixel=ScaleQuantumToShort(image->colormap[i].green);
1400 q=PopShortPixel(MSBEndian,pixel,q);
1401 pixel=ScaleQuantumToShort(image->colormap[i].blue);
1402 q=PopShortPixel(MSBEndian,pixel,q);
1410 pixel=(unsigned char) ScaleQuantumToChar(image->colormap[i].red);
1411 q=PopCharPixel(pixel,q);
1412 pixel=(unsigned char) ScaleQuantumToChar(
1413 image->colormap[i].green);
1414 q=PopCharPixel(pixel,q);
1415 pixel=(unsigned char) ScaleQuantumToChar(image->colormap[i].blue);
1416 q=PopCharPixel(pixel,q);
1421 (void) WriteBlob(image,packet_size*image->colors,colormap);
1422 colormap=(unsigned char *) RelinquishMagickMemory(colormap);
1425 Initialize persistent pixel cache.
1427 status=PersistPixelCache(image,cache_filename,MagickFalse,&offset,
1429 if (status == MagickFalse)
1430 ThrowWriterException(CacheError,"UnableToPersistPixelCache");
1431 if (GetNextImageInList(image) == (Image *) NULL)
1433 image=SyncNextImageInList(image);
1434 if (image->progress_monitor != (MagickProgressMonitor) NULL)
1436 status=image->progress_monitor(SaveImagesTag,scene,
1437 GetImageListLength(image),image->client_data);
1438 if (status == MagickFalse)
1442 } while (image_info->adjoin != MagickFalse);
1443 (void) CloseBlob(image);