2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13 % Read/Write Magick Persistant Cache Image Format %
20 % Copyright 1999-2010 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 "magick/studio.h"
44 #include "magick/artifact.h"
45 #include "magick/attribute.h"
46 #include "magick/blob.h"
47 #include "magick/blob-private.h"
48 #include "magick/cache.h"
49 #include "magick/color.h"
50 #include "magick/color-private.h"
51 #include "magick/colormap.h"
52 #include "magick/constitute.h"
53 #include "magick/exception.h"
54 #include "magick/exception-private.h"
55 #include "magick/geometry.h"
56 #include "magick/hashmap.h"
57 #include "magick/image.h"
58 #include "magick/image-private.h"
59 #include "magick/list.h"
60 #include "magick/magick.h"
61 #include "magick/memory_.h"
62 #include "magick/module.h"
63 #include "magick/monitor.h"
64 #include "magick/monitor-private.h"
65 #include "magick/option.h"
66 #include "magick/profile.h"
67 #include "magick/property.h"
68 #include "magick/quantum-private.h"
69 #include "magick/static.h"
70 #include "magick/statistic.h"
71 #include "magick/string_.h"
72 #include "magick/string-private.h"
73 #include "magick/utility.h"
78 static MagickBooleanType
79 WriteMPCImage(const ImageInfo *,Image *);
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],
194 assert(image_info != (const ImageInfo *) NULL);
195 assert(image_info->signature == MagickSignature);
196 if (image_info->debug != MagickFalse)
197 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
198 image_info->filename);
199 assert(exception != (ExceptionInfo *) NULL);
200 assert(exception->signature == MagickSignature);
201 image=AcquireImage(image_info);
202 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
203 if (status == MagickFalse)
205 image=DestroyImageList(image);
206 return((Image *) NULL);
208 (void) CopyMagickString(cache_filename,image->filename,MaxTextExtent);
209 AppendImageFormat("cache",cache_filename);
210 c=ReadBlobByte(image);
213 image=DestroyImage(image);
214 return((Image *) NULL);
217 (void) ResetMagickMemory(keyword,0,sizeof(keyword));
222 Decode image header; header terminates one character beyond a ':'.
224 profiles=(LinkedListInfo *) NULL;
225 length=MaxTextExtent;
226 options=AcquireString((char *) NULL);
227 quantum_depth=MAGICKCORE_QUANTUM_DEPTH;
229 image->compression=NoCompression;
230 while ((isgraph(c) != MagickFalse) && (c != (int) ':'))
241 Read comment-- any text between { }.
243 length=MaxTextExtent;
244 comment=AcquireString((char *) NULL);
245 for (p=comment; comment != (char *) NULL; p++)
247 c=ReadBlobByte(image);
248 if ((c == EOF) || (c == (int) '}'))
250 if ((size_t) (p-comment+1) >= length)
254 comment=(char *) ResizeQuantumMemory(comment,length+
255 MaxTextExtent,sizeof(*comment));
256 if (comment == (char *) NULL)
258 p=comment+strlen(comment);
262 if (comment == (char *) NULL)
263 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
265 (void) SetImageProperty(image,"comment",comment);
266 comment=DestroyString(comment);
267 c=ReadBlobByte(image);
270 if (isalnum(c) != MagickFalse)
278 if (isspace((int) ((unsigned char) c)) != 0)
282 if ((size_t) (p-keyword) < (MaxTextExtent-1))
284 c=ReadBlobByte(image);
288 while (isspace((int) ((unsigned char) c)) != 0)
289 c=ReadBlobByte(image);
293 Get the keyword value.
295 c=ReadBlobByte(image);
296 while ((c != (int) '}') && (c != EOF))
298 if ((size_t) (p-options+1) >= length)
302 options=(char *) ResizeQuantumMemory(options,length+
303 MaxTextExtent,sizeof(*options));
304 if (options == (char *) NULL)
306 p=options+strlen(options);
308 if (options == (char *) NULL)
309 ThrowReaderException(ResourceLimitError,
310 "MemoryAllocationFailed");
312 c=ReadBlobByte(image);
314 if (isspace((int) ((unsigned char) c)) != 0)
320 (void) CopyMagickString(options,options+1,MaxTextExtent);
322 Assign a value to the specified keyword.
329 if (LocaleCompare(keyword,"background-color") == 0)
331 (void) QueryColorDatabase(options,&image->background_color,
335 if (LocaleCompare(keyword,"blue-primary") == 0)
337 flags=ParseGeometry(options,&geometry_info);
338 image->chromaticity.blue_primary.x=geometry_info.rho;
339 image->chromaticity.blue_primary.y=geometry_info.sigma;
340 if ((flags & SigmaValue) == 0)
341 image->chromaticity.blue_primary.y=
342 image->chromaticity.blue_primary.x;
345 if (LocaleCompare(keyword,"border-color") == 0)
347 (void) QueryColorDatabase(options,&image->border_color,
351 (void) SetImageProperty(image,keyword,options);
357 if (LocaleCompare(keyword,"class") == 0)
362 storage_class=ParseMagickOption(MagickClassOptions,
363 MagickFalse,options);
364 if (storage_class < 0)
366 image->storage_class=(ClassType) storage_class;
369 if (LocaleCompare(keyword,"colors") == 0)
371 image->colors=StringToUnsignedLong(options);
374 if (LocaleCompare(keyword,"colorspace") == 0)
379 colorspace=ParseMagickOption(MagickColorspaceOptions,
380 MagickFalse,options);
383 image->colorspace=(ColorspaceType) colorspace;
386 if (LocaleCompare(keyword,"compression") == 0)
391 compression=ParseMagickOption(MagickCompressOptions,
392 MagickFalse,options);
395 image->compression=(CompressionType) compression;
398 if (LocaleCompare(keyword,"columns") == 0)
400 image->columns=StringToUnsignedLong(options);
403 (void) SetImageProperty(image,keyword,options);
409 if (LocaleCompare(keyword,"delay") == 0)
411 image->delay=StringToUnsignedLong(options);
414 if (LocaleCompare(keyword,"depth") == 0)
416 image->depth=StringToUnsignedLong(options);
419 if (LocaleCompare(keyword,"dispose") == 0)
424 dispose=ParseMagickOption(MagickDisposeOptions,MagickFalse,
428 image->dispose=(DisposeType) dispose;
431 (void) SetImageProperty(image,keyword,options);
437 if (LocaleCompare(keyword,"endian") == 0)
442 endian=ParseMagickOption(MagickEndianOptions,MagickFalse,
446 image->endian=(EndianType) endian;
449 if (LocaleCompare(keyword,"error") == 0)
451 image->error.mean_error_per_pixel=StringToDouble(options);
454 (void) SetImageProperty(image,keyword,options);
460 if (LocaleCompare(keyword,"gamma") == 0)
462 image->gamma=StringToDouble(options);
465 if (LocaleCompare(keyword,"green-primary") == 0)
467 flags=ParseGeometry(options,&geometry_info);
468 image->chromaticity.green_primary.x=geometry_info.rho;
469 image->chromaticity.green_primary.y=geometry_info.sigma;
470 if ((flags & SigmaValue) == 0)
471 image->chromaticity.green_primary.y=
472 image->chromaticity.green_primary.x;
475 (void) SetImageProperty(image,keyword,options);
481 if (LocaleCompare(keyword,"id") == 0)
483 (void) CopyMagickString(id,options,MaxTextExtent);
486 if (LocaleCompare(keyword,"iterations") == 0)
488 image->iterations=StringToUnsignedLong(options);
491 (void) SetImageProperty(image,keyword,options);
497 if (LocaleCompare(keyword,"matte") == 0)
502 matte=ParseMagickOption(MagickBooleanOptions,MagickFalse,
506 image->matte=(MagickBooleanType) matte;
509 if (LocaleCompare(keyword,"matte-color") == 0)
511 (void) QueryColorDatabase(options,&image->matte_color,
515 if (LocaleCompare(keyword,"maximum-error") == 0)
517 image->error.normalized_maximum_error=StringToDouble(options);
520 if (LocaleCompare(keyword,"mean-error") == 0)
522 image->error.normalized_mean_error=StringToDouble(options);
525 if (LocaleCompare(keyword,"montage") == 0)
527 (void) CloneString(&image->montage,options);
530 (void) SetImageProperty(image,keyword,options);
536 if (LocaleCompare(keyword,"opaque") == 0)
541 matte=ParseMagickOption(MagickBooleanOptions,MagickFalse,
545 image->matte=(MagickBooleanType) matte;
548 if (LocaleCompare(keyword,"orientation") == 0)
553 orientation=ParseMagickOption(MagickOrientationOptions,
554 MagickFalse,options);
557 image->orientation=(OrientationType) orientation;
560 (void) SetImageProperty(image,keyword,options);
566 if (LocaleCompare(keyword,"page") == 0)
571 geometry=GetPageGeometry(options);
572 (void) ParseAbsoluteGeometry(geometry,&image->page);
573 geometry=DestroyString(geometry);
576 if ((LocaleNCompare(keyword,"profile:",8) == 0) ||
577 (LocaleNCompare(keyword,"profile-",8) == 0))
579 if (profiles == (LinkedListInfo *) NULL)
580 profiles=NewLinkedList(0);
581 (void) AppendValueToLinkedList(profiles,
582 AcquireString(keyword+8));
583 profile=AcquireStringInfo((size_t) StringToLong(options));
584 (void) SetImageProfile(image,keyword+8,profile);
585 profile=DestroyStringInfo(profile);
588 (void) SetImageProperty(image,keyword,options);
594 if (LocaleCompare(keyword,"quality") == 0)
596 image->quality=StringToUnsignedLong(options);
599 if (LocaleCompare(keyword,"quantum-depth") == 0)
601 quantum_depth=StringToUnsignedLong(options);
604 (void) SetImageProperty(image,keyword,options);
610 if (LocaleCompare(keyword,"red-primary") == 0)
612 flags=ParseGeometry(options,&geometry_info);
613 image->chromaticity.red_primary.x=geometry_info.rho;
614 if ((flags & SigmaValue) != 0)
615 image->chromaticity.red_primary.y=geometry_info.sigma;
618 if (LocaleCompare(keyword,"rendering-intent") == 0)
623 rendering_intent=ParseMagickOption(MagickIntentOptions,
624 MagickFalse,options);
625 if (rendering_intent < 0)
627 image->rendering_intent=(RenderingIntent) rendering_intent;
630 if (LocaleCompare(keyword,"resolution") == 0)
632 flags=ParseGeometry(options,&geometry_info);
633 image->x_resolution=geometry_info.rho;
634 image->y_resolution=geometry_info.sigma;
635 if ((flags & SigmaValue) == 0)
636 image->y_resolution=image->x_resolution;
639 if (LocaleCompare(keyword,"rows") == 0)
641 image->rows=StringToUnsignedLong(options);
644 (void) SetImageProperty(image,keyword,options);
650 if (LocaleCompare(keyword,"scene") == 0)
652 image->scene=StringToUnsignedLong(options);
655 (void) SetImageProperty(image,keyword,options);
661 if (LocaleCompare(keyword,"ticks-per-second") == 0)
663 image->ticks_per_second=(ssize_t) StringToLong(options);
666 if (LocaleCompare(keyword,"tile-offset") == 0)
671 geometry=GetPageGeometry(options);
672 (void) ParseAbsoluteGeometry(geometry,&image->tile_offset);
673 geometry=DestroyString(geometry);
675 if (LocaleCompare(keyword,"type") == 0)
680 type=ParseMagickOption(MagickTypeOptions,MagickFalse,
684 image->type=(ImageType) type;
687 (void) SetImageProperty(image,keyword,options);
693 if (LocaleCompare(keyword,"units") == 0)
698 units=ParseMagickOption(MagickResolutionOptions,MagickFalse,
702 image->units=(ResolutionType) units;
705 (void) SetImageProperty(image,keyword,options);
711 if (LocaleCompare(keyword,"white-point") == 0)
713 flags=ParseGeometry(options,&geometry_info);
714 image->chromaticity.white_point.x=geometry_info.rho;
715 image->chromaticity.white_point.y=geometry_info.sigma;
716 if ((flags & SigmaValue) == 0)
717 image->chromaticity.white_point.y=
718 image->chromaticity.white_point.x;
721 (void) SetImageProperty(image,keyword,options);
726 (void) SetImageProperty(image,keyword,options);
732 c=ReadBlobByte(image);
733 while (isspace((int) ((unsigned char) c)) != 0)
734 c=ReadBlobByte(image);
736 options=DestroyString(options);
737 (void) ReadBlobByte(image);
739 Verify that required image information is defined.
741 if ((LocaleCompare(id,"MagickCache") != 0) ||
742 (image->storage_class == UndefinedClass) ||
743 (image->compression == UndefinedCompression) || (image->columns == 0) ||
745 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
746 if (quantum_depth != MAGICKCORE_QUANTUM_DEPTH)
747 ThrowReaderException(CacheError,"InconsistentPersistentCacheDepth");
748 if (image->montage != (char *) NULL)
756 length=MaxTextExtent;
757 image->directory=AcquireString((char *) NULL);
762 if ((strlen(image->directory)+MaxTextExtent) >= length)
765 Allocate more memory for the image directory.
768 image->directory=(char *) ResizeQuantumMemory(image->directory,
769 length+MaxTextExtent,sizeof(*image->directory));
770 if (image->directory == (char *) NULL)
771 ThrowReaderException(CorruptImageError,"UnableToReadImageData");
772 p=image->directory+strlen(image->directory);
774 c=ReadBlobByte(image);
776 } while (c != (int) '\0');
778 if (profiles != (LinkedListInfo *) NULL)
786 register unsigned char
792 ResetLinkedListIterator(profiles);
793 name=(const char *) GetNextValueInLinkedList(profiles);
794 while (name != (const char *) NULL)
796 profile=GetImageProfile(image,name);
797 if (profile != (StringInfo *) NULL)
799 p=GetStringInfoDatum(profile);
800 count=ReadBlob(image,GetStringInfoLength(profile),p);
802 name=(const char *) GetNextValueInLinkedList(profiles);
804 profiles=DestroyLinkedList(profiles,RelinquishMagickMemory);
806 depth=GetImageQuantumDepth(image,MagickFalse);
807 if (image->storage_class == PseudoClass)
810 Create image colormap.
812 if (AcquireImageColormap(image,image->colors) == MagickFalse)
813 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
814 if (image->colors != 0)
823 Read image colormap from file.
825 packet_size=(size_t) (3UL*depth/8UL);
826 colormap=(unsigned char *) AcquireQuantumMemory(image->colors,
827 packet_size*sizeof(*colormap));
828 if (colormap == (unsigned char *) NULL)
829 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
830 count=ReadBlob(image,packet_size*image->colors,colormap);
831 if (count != (ssize_t) (packet_size*image->colors))
832 ThrowReaderException(CorruptImageError,
833 "InsufficientImageDataInFile");
838 ThrowReaderException(CorruptImageError,
839 "ImageDepthNotSupported");
845 for (i=0; i < (ssize_t) image->colors; i++)
847 p=PushCharPixel(p,&pixel);
848 image->colormap[i].red=ScaleCharToQuantum(pixel);
849 p=PushCharPixel(p,&pixel);
850 image->colormap[i].green=ScaleCharToQuantum(pixel);
851 p=PushCharPixel(p,&pixel);
852 image->colormap[i].blue=ScaleCharToQuantum(pixel);
861 for (i=0; i < (ssize_t) image->colors; i++)
863 p=PushShortPixel(MSBEndian,p,&pixel);
864 image->colormap[i].red=ScaleShortToQuantum(pixel);
865 p=PushShortPixel(MSBEndian,p,&pixel);
866 image->colormap[i].green=ScaleShortToQuantum(pixel);
867 p=PushShortPixel(MSBEndian,p,&pixel);
868 image->colormap[i].blue=ScaleShortToQuantum(pixel);
877 for (i=0; i < (ssize_t) image->colors; i++)
879 p=PushLongPixel(MSBEndian,p,&pixel);
880 image->colormap[i].red=ScaleLongToQuantum(pixel);
881 p=PushLongPixel(MSBEndian,p,&pixel);
882 image->colormap[i].green=ScaleLongToQuantum(pixel);
883 p=PushLongPixel(MSBEndian,p,&pixel);
884 image->colormap[i].blue=ScaleLongToQuantum(pixel);
889 colormap=(unsigned char *) RelinquishMagickMemory(colormap);
892 if (EOFBlob(image) != MagickFalse)
894 ThrowFileException(exception,CorruptImageError,"UnexpectedEndOfFile",
898 if ((image_info->ping != MagickFalse) && (image_info->number_scenes != 0))
899 if (image->scene >= (image_info->scene+image_info->number_scenes-1))
902 Attach persistent pixel cache.
904 status=PersistPixelCache(image,cache_filename,MagickTrue,&offset,exception);
905 if (status == MagickFalse)
906 ThrowReaderException(CacheError,"UnableToPersistPixelCache");
908 Proceed to next image.
912 c=ReadBlobByte(image);
913 } while ((isgraph(c) == MagickFalse) && (c != EOF));
917 Allocate next image structure.
919 AcquireNextImage(image_info,image);
920 if (GetNextImageInList(image) == (Image *) NULL)
922 image=DestroyImageList(image);
923 return((Image *) NULL);
925 image=SyncNextImageInList(image);
926 status=SetImageProgress(image,LoadImagesTag,TellBlob(image),
928 if (status == MagickFalse)
932 (void) CloseBlob(image);
933 return(GetFirstImageInList(image));
937 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
941 % R e g i s t e r M P C I m a g e %
945 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
947 % RegisterMPCImage() adds properties for the Cache image format to
948 % the list of supported formats. The properties include the image format
949 % tag, a method to read and/or write the format, whether the format
950 % supports the saving of more than one frame to the same file or blob,
951 % whether the format supports native in-memory I/O, and a brief
952 % description of the format.
954 % The format of the RegisterMPCImage method is:
956 % size_t RegisterMPCImage(void)
959 ModuleExport size_t RegisterMPCImage(void)
964 entry=SetMagickInfo("CACHE");
965 entry->description=ConstantString("Magick Persistent Cache image format");
966 entry->module=ConstantString("CACHE");
967 entry->stealth=MagickTrue;
968 (void) RegisterMagickInfo(entry);
969 entry=SetMagickInfo("MPC");
970 entry->decoder=(DecodeImageHandler *) ReadMPCImage;
971 entry->encoder=(EncodeImageHandler *) WriteMPCImage;
972 entry->magick=(IsImageFormatHandler *) IsMPC;
973 entry->description=ConstantString("Magick Persistent Cache image format");
974 entry->module=ConstantString("MPC");
975 (void) RegisterMagickInfo(entry);
976 return(MagickImageCoderSignature);
980 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
984 % U n r e g i s t e r M P C I m a g e %
988 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
990 % UnregisterMPCImage() removes format registrations made by the
991 % MPC module from the list of supported formats.
993 % The format of the UnregisterMPCImage method is:
995 % UnregisterMPCImage(void)
998 ModuleExport void UnregisterMPCImage(void)
1000 (void) UnregisterMagickInfo("CACHE");
1001 (void) UnregisterMagickInfo("MPC");
1005 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1009 % W r i t e M P C I m a g e %
1013 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1015 % WriteMPCImage() writes an Magick Persistent Cache image to a file.
1017 % The format of the WriteMPCImage method is:
1019 % MagickBooleanType WriteMPCImage(const ImageInfo *image_info,Image *image)
1021 % A description of each parameter follows:
1023 % o image_info: the image info.
1025 % o image: the image.
1028 static MagickBooleanType WriteMPCImage(const ImageInfo *image_info,Image *image)
1031 buffer[MaxTextExtent],
1032 cache_filename[MaxTextExtent];
1053 Open persistent cache.
1055 assert(image_info != (const ImageInfo *) NULL);
1056 assert(image_info->signature == MagickSignature);
1057 assert(image != (Image *) NULL);
1058 assert(image->signature == MagickSignature);
1059 if (image->debug != MagickFalse)
1060 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1061 status=OpenBlob(image_info,image,WriteBinaryBlobMode,&image->exception);
1062 if (status == MagickFalse)
1064 (void) CopyMagickString(cache_filename,image->filename,MaxTextExtent);
1065 AppendImageFormat("cache",cache_filename);
1072 Write persistent cache meta-information.
1074 depth=GetImageQuantumDepth(image,MagickTrue);
1075 if ((image->storage_class == PseudoClass) &&
1076 (image->colors > (one << depth)))
1077 image->storage_class=DirectClass;
1078 (void) WriteBlobString(image,"id=MagickCache\n");
1079 (void) FormatMagickString(buffer,MaxTextExtent,"quantum-depth=%d\n",
1080 MAGICKCORE_QUANTUM_DEPTH);
1081 (void) WriteBlobString(image,buffer);
1082 (void) FormatMagickString(buffer,MaxTextExtent,
1083 "class=%s colors=%lu matte=%s\n",MagickOptionToMnemonic(
1084 MagickClassOptions,image->storage_class),(unsigned long) image->colors,
1085 MagickOptionToMnemonic(MagickBooleanOptions,(ssize_t) image->matte));
1086 (void) WriteBlobString(image,buffer);
1087 (void) FormatMagickString(buffer,MaxTextExtent,
1088 "columns=%lu rows=%lu depth=%lu\n",(unsigned long) image->columns,
1089 (unsigned long) image->rows,(unsigned long) image->depth);
1090 (void) WriteBlobString(image,buffer);
1091 if (image->type != UndefinedType)
1093 (void) FormatMagickString(buffer,MaxTextExtent,"type=%s\n",
1094 MagickOptionToMnemonic(MagickTypeOptions,image->type));
1095 (void) WriteBlobString(image,buffer);
1097 if (image->colorspace != UndefinedColorspace)
1099 (void) FormatMagickString(buffer,MaxTextExtent,"colorspace=%s\n",
1100 MagickOptionToMnemonic(MagickColorspaceOptions,image->colorspace));
1101 (void) WriteBlobString(image,buffer);
1103 if (image->endian != UndefinedEndian)
1105 (void) FormatMagickString(buffer,MaxTextExtent,"endian=%s\n",
1106 MagickOptionToMnemonic(MagickEndianOptions,image->endian));
1107 (void) WriteBlobString(image,buffer);
1109 if (image->compression != UndefinedCompression)
1111 (void) FormatMagickString(buffer,MaxTextExtent,
1112 "compression=%s quality=%lu\n",MagickOptionToMnemonic(
1113 MagickCompressOptions,image->compression),(unsigned long)
1115 (void) WriteBlobString(image,buffer);
1117 if (image->units != UndefinedResolution)
1119 (void) FormatMagickString(buffer,MaxTextExtent,"units=%s\n",
1120 MagickOptionToMnemonic(MagickResolutionOptions,image->units));
1121 (void) WriteBlobString(image,buffer);
1123 if ((image->x_resolution != 0) || (image->y_resolution != 0))
1125 (void) FormatMagickString(buffer,MaxTextExtent,
1126 "resolution=%gx%g\n",image->x_resolution,image->y_resolution);
1127 (void) WriteBlobString(image,buffer);
1129 if ((image->page.width != 0) || (image->page.height != 0))
1131 (void) FormatMagickString(buffer,MaxTextExtent,"page=%lux%lu%+ld%+ld\n",
1132 (unsigned long) image->page.width,(unsigned long) image->page.height,
1133 (long) image->page.x,(long) image->page.y);
1134 (void) WriteBlobString(image,buffer);
1137 if ((image->page.x != 0) || (image->page.y != 0))
1139 (void) FormatMagickString(buffer,MaxTextExtent,"page=%+ld%+ld\n",
1140 (long) image->page.x,(long) image->page.y);
1141 (void) WriteBlobString(image,buffer);
1143 if ((image->page.x != 0) || (image->page.y != 0))
1145 (void) FormatMagickString(buffer,MaxTextExtent,"tile-offset=%+ld%+ld\n",
1146 (long) image->tile_offset.x,(long) image->tile_offset.y);
1147 (void) WriteBlobString(image,buffer);
1149 if ((GetNextImageInList(image) != (Image *) NULL) ||
1150 (GetPreviousImageInList(image) != (Image *) NULL))
1152 if (image->scene == 0)
1153 (void) FormatMagickString(buffer,MaxTextExtent,
1154 "iterations=%lu delay=%lu ticks-per-second=%lu\n",(long)
1155 image->iterations,(long) image->delay,(long)
1156 image->ticks_per_second);
1158 (void) FormatMagickString(buffer,MaxTextExtent,
1159 "scene=%lu iterations=%lu delay=%lu ticks-per-second=%lu\n",
1160 (long) image->scene,(long) image->iterations,(long) image->delay,
1161 (long) image->ticks_per_second);
1162 (void) WriteBlobString(image,buffer);
1166 if (image->scene != 0)
1168 (void) FormatMagickString(buffer,MaxTextExtent,"scene=%lu\n",
1169 (unsigned long) image->scene);
1170 (void) WriteBlobString(image,buffer);
1172 if (image->iterations != 0)
1174 (void) FormatMagickString(buffer,MaxTextExtent,"iterations=%lu\n",
1175 (unsigned long) image->iterations);
1176 (void) WriteBlobString(image,buffer);
1178 if (image->delay != 0)
1180 (void) FormatMagickString(buffer,MaxTextExtent,"delay=%lu\n",
1181 (unsigned long) image->delay);
1182 (void) WriteBlobString(image,buffer);
1184 if (image->ticks_per_second != UndefinedTicksPerSecond)
1186 (void) FormatMagickString(buffer,MaxTextExtent,
1187 "ticks-per-second=%lu\n",(unsigned long) image->ticks_per_second);
1188 (void) WriteBlobString(image,buffer);
1191 if (image->gravity != UndefinedGravity)
1193 (void) FormatMagickString(buffer,MaxTextExtent,"gravity=%s\n",
1194 MagickOptionToMnemonic(MagickGravityOptions,image->gravity));
1195 (void) WriteBlobString(image,buffer);
1197 if (image->dispose != UndefinedDispose)
1199 (void) FormatMagickString(buffer,MaxTextExtent,"dispose=%s\n",
1200 MagickOptionToMnemonic(MagickDisposeOptions,image->dispose));
1201 (void) WriteBlobString(image,buffer);
1203 if (image->rendering_intent != UndefinedIntent)
1205 (void) FormatMagickString(buffer,MaxTextExtent,
1206 "rendering-intent=%s\n",
1207 MagickOptionToMnemonic(MagickIntentOptions,image->rendering_intent));
1208 (void) WriteBlobString(image,buffer);
1210 if (image->gamma != 0.0)
1212 (void) FormatMagickString(buffer,MaxTextExtent,"gamma=%g\n",
1214 (void) WriteBlobString(image,buffer);
1216 if (image->chromaticity.white_point.x != 0.0)
1219 Note chomaticity points.
1221 (void) FormatMagickString(buffer,MaxTextExtent,"red-primary="
1222 "%g,%g green-primary=%g,%g blue-primary=%g,%g\n",
1223 image->chromaticity.red_primary.x,image->chromaticity.red_primary.y,
1224 image->chromaticity.green_primary.x,
1225 image->chromaticity.green_primary.y,
1226 image->chromaticity.blue_primary.x,
1227 image->chromaticity.blue_primary.y);
1228 (void) WriteBlobString(image,buffer);
1229 (void) FormatMagickString(buffer,MaxTextExtent,
1230 "white-point=%g,%g\n",image->chromaticity.white_point.x,
1231 image->chromaticity.white_point.y);
1232 (void) WriteBlobString(image,buffer);
1234 if (image->orientation != UndefinedOrientation)
1236 (void) FormatMagickString(buffer,MaxTextExtent,
1237 "orientation=%s\n",MagickOptionToMnemonic(MagickOrientationOptions,
1238 image->orientation));
1239 (void) WriteBlobString(image,buffer);
1241 if (image->profiles != (void *) NULL)
1252 ResetImageProfileIterator(image);
1253 for (name=GetNextImageProfile(image); name != (const char *) NULL; )
1255 profile=GetImageProfile(image,name);
1256 if (profile != (StringInfo *) NULL)
1258 (void) FormatMagickString(buffer,MaxTextExtent,"profile:%s=%lu\n",
1259 name,(unsigned long) GetStringInfoLength(profile));
1260 (void) WriteBlobString(image,buffer);
1262 name=GetNextImageProfile(image);
1265 if (image->montage != (char *) NULL)
1267 (void) FormatMagickString(buffer,MaxTextExtent,"montage=%s\n",
1269 (void) WriteBlobString(image,buffer);
1271 ResetImagePropertyIterator(image);
1272 property=GetNextImageProperty(image);
1273 while (property != (const char *) NULL)
1275 (void) FormatMagickString(buffer,MaxTextExtent,"%s=",property);
1276 (void) WriteBlobString(image,buffer);
1277 value=GetImageProperty(image,property);
1278 if (value != (const char *) NULL)
1280 for (i=0; i < (ssize_t) strlen(value); i++)
1281 if (isspace((int) ((unsigned char) value[i])) != 0)
1283 if (i <= (ssize_t) strlen(value))
1284 (void) WriteBlobByte(image,'{');
1285 (void) WriteBlob(image,strlen(value),(unsigned char *) value);
1286 if (i <= (ssize_t) strlen(value))
1287 (void) WriteBlobByte(image,'}');
1289 (void) WriteBlobByte(image,'\n');
1290 property=GetNextImageProperty(image);
1292 ResetImageArtifactIterator(image);
1293 (void) WriteBlobString(image,"\f\n:\032");
1294 if (image->montage != (char *) NULL)
1297 Write montage tile directory.
1299 if (image->directory != (char *) NULL)
1300 (void) WriteBlobString(image,image->directory);
1301 (void) WriteBlobByte(image,'\0');
1303 if (image->profiles != 0)
1312 Write image profiles.
1314 ResetImageProfileIterator(image);
1315 name=GetNextImageProfile(image);
1316 while (name != (const char *) NULL)
1318 profile=GetImageProfile(image,name);
1319 (void) WriteBlob(image,GetStringInfoLength(profile),
1320 GetStringInfoDatum(profile));
1321 name=GetNextImageProfile(image);
1324 if (image->storage_class == PseudoClass)
1336 packet_size=(size_t) (3UL*depth/8UL);
1337 colormap=(unsigned char *) AcquireQuantumMemory(image->colors,
1338 packet_size*sizeof(*colormap));
1339 if (colormap == (unsigned char *) NULL)
1340 return(MagickFalse);
1342 Write colormap to file.
1345 for (i=0; i < (ssize_t) image->colors; i++)
1350 ThrowWriterException(CorruptImageError,"ImageDepthNotSupported");
1356 pixel=ScaleQuantumToLong(image->colormap[i].red);
1357 q=PopLongPixel(MSBEndian,pixel,q);
1358 pixel=ScaleQuantumToLong(image->colormap[i].green);
1359 q=PopLongPixel(MSBEndian,pixel,q);
1360 pixel=ScaleQuantumToLong(image->colormap[i].blue);
1361 q=PopLongPixel(MSBEndian,pixel,q);
1368 pixel=ScaleQuantumToShort(image->colormap[i].red);
1369 q=PopShortPixel(MSBEndian,pixel,q);
1370 pixel=ScaleQuantumToShort(image->colormap[i].green);
1371 q=PopShortPixel(MSBEndian,pixel,q);
1372 pixel=ScaleQuantumToShort(image->colormap[i].blue);
1373 q=PopShortPixel(MSBEndian,pixel,q);
1381 pixel=(unsigned char) ScaleQuantumToChar(image->colormap[i].red);
1382 q=PopCharPixel(pixel,q);
1383 pixel=(unsigned char) ScaleQuantumToChar(
1384 image->colormap[i].green);
1385 q=PopCharPixel(pixel,q);
1386 pixel=(unsigned char) ScaleQuantumToChar(image->colormap[i].blue);
1387 q=PopCharPixel(pixel,q);
1392 (void) WriteBlob(image,packet_size*image->colors,colormap);
1393 colormap=(unsigned char *) RelinquishMagickMemory(colormap);
1396 Initialize persistent pixel cache.
1398 status=PersistPixelCache(image,cache_filename,MagickFalse,&offset,
1400 if (status == MagickFalse)
1401 ThrowWriterException(CacheError,"UnableToPersistPixelCache");
1402 if (GetNextImageInList(image) == (Image *) NULL)
1404 image=SyncNextImageInList(image);
1405 if (image->progress_monitor != (MagickProgressMonitor) NULL)
1407 status=image->progress_monitor(SaveImagesTag,scene,
1408 GetImageListLength(image),image->client_data);
1409 if (status == MagickFalse)
1413 } while (image_info->adjoin != MagickFalse);
1414 (void) CloseBlob(image);