| /* | 
 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | 
 | %                                                                             % | 
 | %                                                                             % | 
 | %                                                                             % | 
 | %                            M   M  PPPP    CCCC                              % | 
 | %                            MM MM  P   P  C                                  % | 
 | %                            M M M  PPPP   C                                  % | 
 | %                            M   M  P      C                                  % | 
 | %                            M   M  P       CCCC                              % | 
 | %                                                                             % | 
 | %                                                                             % | 
 | %              Read/Write Magick Persistant Cache Image Format                % | 
 | %                                                                             % | 
 | %                              Software Design                                % | 
 | %                                   Cristy                                    % | 
 | %                                 March 2000                                  % | 
 | %                                                                             % | 
 | %                                                                             % | 
 | %  Copyright 1999-2015 ImageMagick Studio LLC, a non-profit organization      % | 
 | %  dedicated to making software imaging solutions freely available.           % | 
 | %                                                                             % | 
 | %  You may not use this file except in compliance with the License.  You may  % | 
 | %  obtain a copy of the License at                                            % | 
 | %                                                                             % | 
 | %    http://www.imagemagick.org/script/license.php                            % | 
 | %                                                                             % | 
 | %  Unless required by applicable law or agreed to in writing, software        % | 
 | %  distributed under the License is distributed on an "AS IS" BASIS,          % | 
 | %  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   % | 
 | %  See the License for the specific language governing permissions and        % | 
 | %  limitations under the License.                                             % | 
 | %                                                                             % | 
 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | 
 | % | 
 | % | 
 | % | 
 | */ | 
 |  | 
 | /* | 
 |   Include declarations. | 
 | */ | 
 | #include "MagickCore/studio.h" | 
 | #include "MagickCore/artifact.h" | 
 | #include "MagickCore/attribute.h" | 
 | #include "MagickCore/blob.h" | 
 | #include "MagickCore/blob-private.h" | 
 | #include "MagickCore/cache.h" | 
 | #include "MagickCore/color.h" | 
 | #include "MagickCore/color-private.h" | 
 | #include "MagickCore/colormap.h" | 
 | #include "MagickCore/constitute.h" | 
 | #include "MagickCore/exception.h" | 
 | #include "MagickCore/exception-private.h" | 
 | #include "MagickCore/geometry.h" | 
 | #include "MagickCore/hashmap.h" | 
 | #include "MagickCore/image.h" | 
 | #include "MagickCore/image-private.h" | 
 | #include "MagickCore/list.h" | 
 | #include "MagickCore/magick.h" | 
 | #include "MagickCore/memory_.h" | 
 | #include "MagickCore/module.h" | 
 | #include "MagickCore/monitor.h" | 
 | #include "MagickCore/monitor-private.h" | 
 | #include "MagickCore/option.h" | 
 | #include "MagickCore/profile.h" | 
 | #include "MagickCore/property.h" | 
 | #include "MagickCore/quantum-private.h" | 
 | #include "MagickCore/static.h" | 
 | #include "MagickCore/statistic.h" | 
 | #include "MagickCore/string_.h" | 
 | #include "MagickCore/string-private.h" | 
 | #include "MagickCore/utility.h" | 
 | #include "MagickCore/version-private.h" | 
 |  | 
 | /* | 
 |   Forward declarations. | 
 | */ | 
 | static MagickBooleanType | 
 |   WriteMPCImage(const ImageInfo *,Image *,ExceptionInfo *); | 
 |  | 
 | /* | 
 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | 
 | %                                                                             % | 
 | %                                                                             % | 
 | %                                                                             % | 
 | %   I s M P C                                                                 % | 
 | %                                                                             % | 
 | %                                                                             % | 
 | %                                                                             % | 
 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | 
 | % | 
 | %  IsMPC() returns MagickTrue if the image format type, identified by the | 
 | %  magick string, is an Magick Persistent Cache image. | 
 | % | 
 | %  The format of the IsMPC method is: | 
 | % | 
 | %      MagickBooleanType IsMPC(const unsigned char *magick,const size_t length) | 
 | % | 
 | %  A description of each parameter follows: | 
 | % | 
 | %    o magick: compare image format pattern against these bytes. | 
 | % | 
 | %    o length: Specifies the length of the magick string. | 
 | % | 
 | */ | 
 | static MagickBooleanType IsMPC(const unsigned char *magick,const size_t length) | 
 | { | 
 |   if (length < 14) | 
 |     return(MagickFalse); | 
 |   if (LocaleNCompare((const char *) magick,"id=MagickCache",14) == 0) | 
 |     return(MagickTrue); | 
 |   return(MagickFalse); | 
 | } | 
 |  | 
 | /* | 
 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | 
 | %                                                                             % | 
 | %                                                                             % | 
 | %                                                                             % | 
 | %   R e a d C A C H E I m a g e                                               % | 
 | %                                                                             % | 
 | %                                                                             % | 
 | %                                                                             % | 
 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | 
 | % | 
 | %  ReadMPCImage() reads an Magick Persistent Cache image file and returns | 
 | %  it.  It allocates the memory necessary for the new Image structure and | 
 | %  returns a pointer to the new image. | 
 | % | 
 | %  The format of the ReadMPCImage method is: | 
 | % | 
 | %      Image *ReadMPCImage(const ImageInfo *image_info,ExceptionInfo *exception) | 
 | % | 
 | %  Decompression code contributed by Kyle Shorter. | 
 | % | 
 | %  A description of each parameter follows: | 
 | % | 
 | %    o image_info: the image info. | 
 | % | 
 | %    o exception: return any errors or warnings in this structure. | 
 | % | 
 | */ | 
 | static Image *ReadMPCImage(const ImageInfo *image_info,ExceptionInfo *exception) | 
 | { | 
 |   char | 
 |     cache_filename[MagickPathExtent], | 
 |     id[MagickPathExtent], | 
 |     keyword[MagickPathExtent], | 
 |     *options; | 
 |  | 
 |   const unsigned char | 
 |     *p; | 
 |  | 
 |   GeometryInfo | 
 |     geometry_info; | 
 |  | 
 |   Image | 
 |     *image; | 
 |  | 
 |   int | 
 |     c; | 
 |  | 
 |   LinkedListInfo | 
 |     *profiles; | 
 |  | 
 |   MagickBooleanType | 
 |     status; | 
 |  | 
 |   MagickOffsetType | 
 |     offset; | 
 |  | 
 |   MagickStatusType | 
 |     flags; | 
 |  | 
 |   register ssize_t | 
 |     i; | 
 |  | 
 |   size_t | 
 |     depth, | 
 |     length; | 
 |  | 
 |   ssize_t | 
 |     count; | 
 |  | 
 |   StringInfo | 
 |     *profile; | 
 |  | 
 |   unsigned int | 
 |     signature; | 
 |  | 
 |   /* | 
 |     Open image file. | 
 |   */ | 
 |   assert(image_info != (const ImageInfo *) NULL); | 
 |   assert(image_info->signature == MagickSignature); | 
 |   if (image_info->debug != MagickFalse) | 
 |     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s", | 
 |       image_info->filename); | 
 |   assert(exception != (ExceptionInfo *) NULL); | 
 |   assert(exception->signature == MagickSignature); | 
 |   image=AcquireImage(image_info,exception); | 
 |   status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception); | 
 |   if (status == MagickFalse) | 
 |     { | 
 |       image=DestroyImageList(image); | 
 |       return((Image *) NULL); | 
 |     } | 
 |   (void) CopyMagickString(cache_filename,image->filename,MagickPathExtent); | 
 |   AppendImageFormat("cache",cache_filename); | 
 |   c=ReadBlobByte(image); | 
 |   if (c == EOF) | 
 |     { | 
 |       image=DestroyImage(image); | 
 |       return((Image *) NULL); | 
 |     } | 
 |   *id='\0'; | 
 |   (void) ResetMagickMemory(keyword,0,sizeof(keyword)); | 
 |   offset=0; | 
 |   do | 
 |   { | 
 |     /* | 
 |       Decode image header;  header terminates one character beyond a ':'. | 
 |     */ | 
 |     profiles=(LinkedListInfo *) NULL; | 
 |     length=MagickPathExtent; | 
 |     options=AcquireString((char *) NULL); | 
 |     signature=GetMagickSignature((const StringInfo *) NULL); | 
 |     image->depth=8; | 
 |     image->compression=NoCompression; | 
 |     while ((isgraph(c) != MagickFalse) && (c != (int) ':')) | 
 |     { | 
 |       register char | 
 |         *p; | 
 |  | 
 |       if (c == (int) '{') | 
 |         { | 
 |           char | 
 |             *comment; | 
 |  | 
 |           /* | 
 |             Read comment-- any text between { }. | 
 |           */ | 
 |           length=MagickPathExtent; | 
 |           comment=AcquireString((char *) NULL); | 
 |           for (p=comment; comment != (char *) NULL; p++) | 
 |           { | 
 |             c=ReadBlobByte(image); | 
 |             if (c == (int) '\\') | 
 |               c=ReadBlobByte(image); | 
 |             else | 
 |               if ((c == EOF) || (c == (int) '}')) | 
 |                 break; | 
 |             if ((size_t) (p-comment+1) >= length) | 
 |               { | 
 |                 *p='\0'; | 
 |                 length<<=1; | 
 |                 comment=(char *) ResizeQuantumMemory(comment,length+ | 
 |                   MagickPathExtent,sizeof(*comment)); | 
 |                 if (comment == (char *) NULL) | 
 |                   break; | 
 |                 p=comment+strlen(comment); | 
 |               } | 
 |             *p=(char) c; | 
 |           } | 
 |           if (comment == (char *) NULL) | 
 |             ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed"); | 
 |           *p='\0'; | 
 |           (void) SetImageProperty(image,"comment",comment,exception); | 
 |           comment=DestroyString(comment); | 
 |           c=ReadBlobByte(image); | 
 |         } | 
 |       else | 
 |         if (isalnum(c) != MagickFalse) | 
 |           { | 
 |             /* | 
 |               Get the keyword. | 
 |             */ | 
 |             length=MagickPathExtent; | 
 |             p=keyword; | 
 |             do | 
 |             { | 
 |               if (c == (int) '=') | 
 |                 break; | 
 |               if ((size_t) (p-keyword) < (MagickPathExtent-1)) | 
 |                 *p++=(char) c; | 
 |               c=ReadBlobByte(image); | 
 |             } while (c != EOF); | 
 |             *p='\0'; | 
 |             p=options; | 
 |             while (isspace((int) ((unsigned char) c)) != 0) | 
 |               c=ReadBlobByte(image); | 
 |             if (c == (int) '=') | 
 |               { | 
 |                 /* | 
 |                   Get the keyword value. | 
 |                 */ | 
 |                 c=ReadBlobByte(image); | 
 |                 while ((c != (int) '}') && (c != EOF)) | 
 |                 { | 
 |                   if ((size_t) (p-options+1) >= length) | 
 |                     { | 
 |                       *p='\0'; | 
 |                       length<<=1; | 
 |                       options=(char *) ResizeQuantumMemory(options,length+ | 
 |                         MagickPathExtent,sizeof(*options)); | 
 |                       if (options == (char *) NULL) | 
 |                         break; | 
 |                       p=options+strlen(options); | 
 |                     } | 
 |                   *p++=(char) c; | 
 |                   c=ReadBlobByte(image); | 
 |                   if (c == '\\') | 
 |                     { | 
 |                       c=ReadBlobByte(image); | 
 |                       if (c == (int) '}') | 
 |                         { | 
 |                           *p++=(char) c; | 
 |                           c=ReadBlobByte(image); | 
 |                         } | 
 |                     } | 
 |                   if (*options != '{') | 
 |                     if (isspace((int) ((unsigned char) c)) != 0) | 
 |                       break; | 
 |                 } | 
 |                 if (options == (char *) NULL) | 
 |                   ThrowReaderException(ResourceLimitError, | 
 |                     "MemoryAllocationFailed"); | 
 |               } | 
 |             *p='\0'; | 
 |             if (*options == '{') | 
 |               (void) CopyMagickString(options,options+1,strlen(options)); | 
 |             /* | 
 |               Assign a value to the specified keyword. | 
 |             */ | 
 |             switch (*keyword) | 
 |             { | 
 |               case 'a': | 
 |               case 'A': | 
 |               { | 
 |                 if (LocaleCompare(keyword,"alpha-trait") == 0) | 
 |                   { | 
 |                     ssize_t | 
 |                       alpha_trait; | 
 |  | 
 |                     alpha_trait=ParseCommandOption(MagickPixelTraitOptions, | 
 |                       MagickFalse,options); | 
 |                     if (alpha_trait < 0) | 
 |                       break; | 
 |                     image->alpha_trait=(PixelTrait) alpha_trait; | 
 |                     break; | 
 |                   } | 
 |                 (void) SetImageProperty(image,keyword,options,exception); | 
 |                 break; | 
 |               } | 
 |               case 'b': | 
 |               case 'B': | 
 |               { | 
 |                 if (LocaleCompare(keyword,"background-color") == 0) | 
 |                   { | 
 |                     (void) QueryColorCompliance(options,AllCompliance, | 
 |                       &image->background_color,exception); | 
 |                     break; | 
 |                   } | 
 |                 if (LocaleCompare(keyword,"blue-primary") == 0) | 
 |                   { | 
 |                     flags=ParseGeometry(options,&geometry_info); | 
 |                     image->chromaticity.blue_primary.x=geometry_info.rho; | 
 |                     image->chromaticity.blue_primary.y=geometry_info.sigma; | 
 |                     if ((flags & SigmaValue) == 0) | 
 |                       image->chromaticity.blue_primary.y= | 
 |                         image->chromaticity.blue_primary.x; | 
 |                     break; | 
 |                   } | 
 |                 if (LocaleCompare(keyword,"border-color") == 0) | 
 |                   { | 
 |                     (void) QueryColorCompliance(options,AllCompliance, | 
 |                       &image->border_color,exception); | 
 |                     break; | 
 |                   } | 
 |                 (void) SetImageProperty(image,keyword,options,exception); | 
 |                 break; | 
 |               } | 
 |               case 'c': | 
 |               case 'C': | 
 |               { | 
 |                 if (LocaleCompare(keyword,"class") == 0) | 
 |                   { | 
 |                     ssize_t | 
 |                       storage_class; | 
 |  | 
 |                     storage_class=ParseCommandOption(MagickClassOptions, | 
 |                       MagickFalse,options); | 
 |                     if (storage_class < 0) | 
 |                       break; | 
 |                     image->storage_class=(ClassType) storage_class; | 
 |                     break; | 
 |                   } | 
 |                 if (LocaleCompare(keyword,"colors") == 0) | 
 |                   { | 
 |                     image->colors=StringToUnsignedLong(options); | 
 |                     break; | 
 |                   } | 
 |                 if (LocaleCompare(keyword,"colorspace") == 0) | 
 |                   { | 
 |                     ssize_t | 
 |                       colorspace; | 
 |  | 
 |                     colorspace=ParseCommandOption(MagickColorspaceOptions, | 
 |                       MagickFalse,options); | 
 |                     if (colorspace < 0) | 
 |                       break; | 
 |                     image->colorspace=(ColorspaceType) colorspace; | 
 |                     break; | 
 |                   } | 
 |                 if (LocaleCompare(keyword,"compression") == 0) | 
 |                   { | 
 |                     ssize_t | 
 |                       compression; | 
 |  | 
 |                     compression=ParseCommandOption(MagickCompressOptions, | 
 |                       MagickFalse,options); | 
 |                     if (compression < 0) | 
 |                       break; | 
 |                     image->compression=(CompressionType) compression; | 
 |                     break; | 
 |                   } | 
 |                 if (LocaleCompare(keyword,"columns") == 0) | 
 |                   { | 
 |                     image->columns=StringToUnsignedLong(options); | 
 |                     break; | 
 |                   } | 
 |                 (void) SetImageProperty(image,keyword,options,exception); | 
 |                 break; | 
 |               } | 
 |               case 'd': | 
 |               case 'D': | 
 |               { | 
 |                 if (LocaleCompare(keyword,"delay") == 0) | 
 |                   { | 
 |                     image->delay=StringToUnsignedLong(options); | 
 |                     break; | 
 |                   } | 
 |                 if (LocaleCompare(keyword,"depth") == 0) | 
 |                   { | 
 |                     image->depth=StringToUnsignedLong(options); | 
 |                     break; | 
 |                   } | 
 |                 if (LocaleCompare(keyword,"dispose") == 0) | 
 |                   { | 
 |                     ssize_t | 
 |                       dispose; | 
 |  | 
 |                     dispose=ParseCommandOption(MagickDisposeOptions,MagickFalse, | 
 |                       options); | 
 |                     if (dispose < 0) | 
 |                       break; | 
 |                     image->dispose=(DisposeType) dispose; | 
 |                     break; | 
 |                   } | 
 |                 (void) SetImageProperty(image,keyword,options,exception); | 
 |                 break; | 
 |               } | 
 |               case 'e': | 
 |               case 'E': | 
 |               { | 
 |                 if (LocaleCompare(keyword,"endian") == 0) | 
 |                   { | 
 |                     ssize_t | 
 |                       endian; | 
 |  | 
 |                     endian=ParseCommandOption(MagickEndianOptions,MagickFalse, | 
 |                       options); | 
 |                     if (endian < 0) | 
 |                       break; | 
 |                     image->endian=(EndianType) endian; | 
 |                     break; | 
 |                   } | 
 |                 if (LocaleCompare(keyword,"error") == 0) | 
 |                   { | 
 |                     image->error.mean_error_per_pixel=StringToDouble(options, | 
 |                       (char **) NULL); | 
 |                     break; | 
 |                   } | 
 |                 (void) SetImageProperty(image,keyword,options,exception); | 
 |                 break; | 
 |               } | 
 |               case 'g': | 
 |               case 'G': | 
 |               { | 
 |                 if (LocaleCompare(keyword,"gamma") == 0) | 
 |                   { | 
 |                     image->gamma=StringToDouble(options,(char **) NULL); | 
 |                     break; | 
 |                   } | 
 |                 if (LocaleCompare(keyword,"green-primary") == 0) | 
 |                   { | 
 |                     flags=ParseGeometry(options,&geometry_info); | 
 |                     image->chromaticity.green_primary.x=geometry_info.rho; | 
 |                     image->chromaticity.green_primary.y=geometry_info.sigma; | 
 |                     if ((flags & SigmaValue) == 0) | 
 |                       image->chromaticity.green_primary.y= | 
 |                         image->chromaticity.green_primary.x; | 
 |                     break; | 
 |                   } | 
 |                 (void) SetImageProperty(image,keyword,options,exception); | 
 |                 break; | 
 |               } | 
 |               case 'i': | 
 |               case 'I': | 
 |               { | 
 |                 if (LocaleCompare(keyword,"id") == 0) | 
 |                   { | 
 |                     (void) CopyMagickString(id,options,MagickPathExtent); | 
 |                     break; | 
 |                   } | 
 |                 if (LocaleCompare(keyword,"iterations") == 0) | 
 |                   { | 
 |                     image->iterations=StringToUnsignedLong(options); | 
 |                     break; | 
 |                   } | 
 |                 (void) SetImageProperty(image,keyword,options,exception); | 
 |                 break; | 
 |               } | 
 |               case 'm': | 
 |               case 'M': | 
 |               { | 
 |                 if (LocaleCompare(keyword,"magick-signature") == 0) | 
 |                   { | 
 |                     signature=(unsigned int) StringToUnsignedLong(options); | 
 |                     break; | 
 |                   } | 
 |                 if (LocaleCompare(keyword,"matte-color") == 0) | 
 |                   { | 
 |                     (void) QueryColorCompliance(options,AllCompliance, | 
 |                       &image->matte_color,exception); | 
 |                     break; | 
 |                   } | 
 |                 if (LocaleCompare(keyword,"maximum-error") == 0) | 
 |                   { | 
 |                     image->error.normalized_maximum_error=StringToDouble( | 
 |                       options,(char **) NULL); | 
 |                     break; | 
 |                   } | 
 |                 if (LocaleCompare(keyword,"mean-error") == 0) | 
 |                   { | 
 |                     image->error.normalized_mean_error=StringToDouble(options, | 
 |                       (char **) NULL); | 
 |                     break; | 
 |                   } | 
 |                 if (LocaleCompare(keyword,"montage") == 0) | 
 |                   { | 
 |                     (void) CloneString(&image->montage,options); | 
 |                     break; | 
 |                   } | 
 |                 (void) SetImageProperty(image,keyword,options,exception); | 
 |                 break; | 
 |               } | 
 |               case 'o': | 
 |               case 'O': | 
 |               { | 
 |                 if (LocaleCompare(keyword,"orientation") == 0) | 
 |                   { | 
 |                     ssize_t | 
 |                       orientation; | 
 |  | 
 |                     orientation=ParseCommandOption(MagickOrientationOptions, | 
 |                       MagickFalse,options); | 
 |                     if (orientation < 0) | 
 |                       break; | 
 |                     image->orientation=(OrientationType) orientation; | 
 |                     break; | 
 |                   } | 
 |                 (void) SetImageProperty(image,keyword,options,exception); | 
 |                 break; | 
 |               } | 
 |               case 'p': | 
 |               case 'P': | 
 |               { | 
 |                 if (LocaleCompare(keyword,"page") == 0) | 
 |                   { | 
 |                     char | 
 |                       *geometry; | 
 |  | 
 |                     geometry=GetPageGeometry(options); | 
 |                     (void) ParseAbsoluteGeometry(geometry,&image->page); | 
 |                     geometry=DestroyString(geometry); | 
 |                     break; | 
 |                   } | 
 |                 if (LocaleCompare(keyword,"pixel-intensity") == 0) | 
 |                   { | 
 |                     ssize_t | 
 |                       intensity; | 
 |  | 
 |                     intensity=ParseCommandOption(MagickPixelIntensityOptions, | 
 |                       MagickFalse,options); | 
 |                     if (intensity < 0) | 
 |                       break; | 
 |                     image->intensity=(PixelIntensityMethod) intensity; | 
 |                     break; | 
 |                   } | 
 |                 if ((LocaleNCompare(keyword,"profile:",8) == 0) || | 
 |                     (LocaleNCompare(keyword,"profile-",8) == 0)) | 
 |                   { | 
 |                     if (profiles == (LinkedListInfo *) NULL) | 
 |                       profiles=NewLinkedList(0); | 
 |                     (void) AppendValueToLinkedList(profiles, | 
 |                       AcquireString(keyword+8)); | 
 |                     profile=BlobToStringInfo((const void *) NULL,(size_t) | 
 |                       StringToLong(options)); | 
 |                     if (profile == (StringInfo *) NULL) | 
 |                       ThrowReaderException(ResourceLimitError, | 
 |                         "MemoryAllocationFailed"); | 
 |                     (void) SetImageProfile(image,keyword+8,profile,exception); | 
 |                     profile=DestroyStringInfo(profile); | 
 |                     break; | 
 |                   } | 
 |                 (void) SetImageProperty(image,keyword,options,exception); | 
 |                 break; | 
 |               } | 
 |               case 'q': | 
 |               case 'Q': | 
 |               { | 
 |                 if (LocaleCompare(keyword,"quality") == 0) | 
 |                   { | 
 |                     image->quality=StringToUnsignedLong(options); | 
 |                     break; | 
 |                   } | 
 |                 (void) SetImageProperty(image,keyword,options,exception); | 
 |                 break; | 
 |               } | 
 |               case 'r': | 
 |               case 'R': | 
 |               { | 
 |                 if (LocaleCompare(keyword,"red-primary") == 0) | 
 |                   { | 
 |                     flags=ParseGeometry(options,&geometry_info); | 
 |                     image->chromaticity.red_primary.x=geometry_info.rho; | 
 |                     if ((flags & SigmaValue) != 0) | 
 |                       image->chromaticity.red_primary.y=geometry_info.sigma; | 
 |                     break; | 
 |                   } | 
 |                 if (LocaleCompare(keyword,"rendering-intent") == 0) | 
 |                   { | 
 |                     ssize_t | 
 |                       rendering_intent; | 
 |  | 
 |                     rendering_intent=ParseCommandOption(MagickIntentOptions, | 
 |                       MagickFalse,options); | 
 |                     if (rendering_intent < 0) | 
 |                       break; | 
 |                     image->rendering_intent=(RenderingIntent) rendering_intent; | 
 |                     break; | 
 |                   } | 
 |                 if (LocaleCompare(keyword,"resolution") == 0) | 
 |                   { | 
 |                     flags=ParseGeometry(options,&geometry_info); | 
 |                     image->resolution.x=geometry_info.rho; | 
 |                     image->resolution.y=geometry_info.sigma; | 
 |                     if ((flags & SigmaValue) == 0) | 
 |                       image->resolution.y=image->resolution.x; | 
 |                     break; | 
 |                   } | 
 |                 if (LocaleCompare(keyword,"rows") == 0) | 
 |                   { | 
 |                     image->rows=StringToUnsignedLong(options); | 
 |                     break; | 
 |                   } | 
 |                 (void) SetImageProperty(image,keyword,options,exception); | 
 |                 break; | 
 |               } | 
 |               case 's': | 
 |               case 'S': | 
 |               { | 
 |                 if (LocaleCompare(keyword,"scene") == 0) | 
 |                   { | 
 |                     image->scene=StringToUnsignedLong(options); | 
 |                     break; | 
 |                   } | 
 |                 (void) SetImageProperty(image,keyword,options,exception); | 
 |                 break; | 
 |               } | 
 |               case 't': | 
 |               case 'T': | 
 |               { | 
 |                 if (LocaleCompare(keyword,"ticks-per-second") == 0) | 
 |                   { | 
 |                     image->ticks_per_second=(ssize_t) StringToLong(options); | 
 |                     break; | 
 |                   } | 
 |                 if (LocaleCompare(keyword,"tile-offset") == 0) | 
 |                   { | 
 |                     char | 
 |                       *geometry; | 
 |  | 
 |                     geometry=GetPageGeometry(options); | 
 |                     (void) ParseAbsoluteGeometry(geometry,&image->tile_offset); | 
 |                     geometry=DestroyString(geometry); | 
 |                   } | 
 |                 if (LocaleCompare(keyword,"type") == 0) | 
 |                   { | 
 |                     ssize_t | 
 |                       type; | 
 |  | 
 |                     type=ParseCommandOption(MagickTypeOptions,MagickFalse, | 
 |                       options); | 
 |                     if (type < 0) | 
 |                       break; | 
 |                     image->type=(ImageType) type; | 
 |                     break; | 
 |                   } | 
 |                 (void) SetImageProperty(image,keyword,options,exception); | 
 |                 break; | 
 |               } | 
 |               case 'u': | 
 |               case 'U': | 
 |               { | 
 |                 if (LocaleCompare(keyword,"units") == 0) | 
 |                   { | 
 |                     ssize_t | 
 |                       units; | 
 |  | 
 |                     units=ParseCommandOption(MagickResolutionOptions, | 
 |                       MagickFalse,options); | 
 |                     if (units < 0) | 
 |                       break; | 
 |                     image->units=(ResolutionType) units; | 
 |                     break; | 
 |                   } | 
 |                 (void) SetImageProperty(image,keyword,options,exception); | 
 |                 break; | 
 |               } | 
 |               case 'w': | 
 |               case 'W': | 
 |               { | 
 |                 if (LocaleCompare(keyword,"white-point") == 0) | 
 |                   { | 
 |                     flags=ParseGeometry(options,&geometry_info); | 
 |                     image->chromaticity.white_point.x=geometry_info.rho; | 
 |                     image->chromaticity.white_point.y=geometry_info.sigma; | 
 |                     if ((flags & SigmaValue) == 0) | 
 |                       image->chromaticity.white_point.y= | 
 |                         image->chromaticity.white_point.x; | 
 |                     break; | 
 |                   } | 
 |                 (void) SetImageProperty(image,keyword,options,exception); | 
 |                 break; | 
 |               } | 
 |               default: | 
 |               { | 
 |                 (void) SetImageProperty(image,keyword,options,exception); | 
 |                 break; | 
 |               } | 
 |             } | 
 |           } | 
 |         else | 
 |           c=ReadBlobByte(image); | 
 |       while (isspace((int) ((unsigned char) c)) != 0) | 
 |         c=ReadBlobByte(image); | 
 |     } | 
 |     options=DestroyString(options); | 
 |     (void) ReadBlobByte(image); | 
 |     /* | 
 |       Verify that required image information is defined. | 
 |     */ | 
 |     if ((LocaleCompare(id,"MagickCache") != 0) || | 
 |         (image->storage_class == UndefinedClass) || | 
 |         (image->compression == UndefinedCompression) || (image->columns == 0) || | 
 |         (image->rows == 0)) | 
 |       ThrowReaderException(CorruptImageError,"ImproperImageHeader"); | 
 |     if (signature != GetMagickSignature((const StringInfo *) NULL)) | 
 |       ThrowReaderException(CacheError,"IncompatibleAPI"); | 
 |     if (image->montage != (char *) NULL) | 
 |       { | 
 |         register char | 
 |           *p; | 
 |  | 
 |         /* | 
 |           Image directory. | 
 |         */ | 
 |         length=MagickPathExtent; | 
 |         image->directory=AcquireString((char *) NULL); | 
 |         p=image->directory; | 
 |         do | 
 |         { | 
 |           *p='\0'; | 
 |           if ((strlen(image->directory)+MagickPathExtent) >= length) | 
 |             { | 
 |               /* | 
 |                 Allocate more memory for the image directory. | 
 |               */ | 
 |               length<<=1; | 
 |               image->directory=(char *) ResizeQuantumMemory(image->directory, | 
 |                 length+MagickPathExtent,sizeof(*image->directory)); | 
 |               if (image->directory == (char *) NULL) | 
 |                 ThrowReaderException(CorruptImageError,"UnableToReadImageData"); | 
 |               p=image->directory+strlen(image->directory); | 
 |             } | 
 |           c=ReadBlobByte(image); | 
 |           *p++=(char) c; | 
 |         } while (c != (int) '\0'); | 
 |       } | 
 |     if (profiles != (LinkedListInfo *) NULL) | 
 |       { | 
 |         const char | 
 |           *name; | 
 |  | 
 |         const StringInfo | 
 |           *profile; | 
 |  | 
 |         register unsigned char | 
 |           *p; | 
 |  | 
 |         /* | 
 |           Read image profiles. | 
 |         */ | 
 |         ResetLinkedListIterator(profiles); | 
 |         name=(const char *) GetNextValueInLinkedList(profiles); | 
 |         while (name != (const char *) NULL) | 
 |         { | 
 |           profile=GetImageProfile(image,name); | 
 |           if (profile != (StringInfo *) NULL) | 
 |             { | 
 |               p=GetStringInfoDatum(profile); | 
 |               count=ReadBlob(image,GetStringInfoLength(profile),p); | 
 |             } | 
 |           name=(const char *) GetNextValueInLinkedList(profiles); | 
 |         } | 
 |         profiles=DestroyLinkedList(profiles,RelinquishMagickMemory); | 
 |       } | 
 |     depth=GetImageQuantumDepth(image,MagickFalse); | 
 |     if (image->storage_class == PseudoClass) | 
 |       { | 
 |         /* | 
 |           Create image colormap. | 
 |         */ | 
 |         if (AcquireImageColormap(image,image->colors,exception) == MagickFalse) | 
 |           ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed"); | 
 |         if (image->colors != 0) | 
 |           { | 
 |             size_t | 
 |               packet_size; | 
 |  | 
 |             unsigned char | 
 |               *colormap; | 
 |  | 
 |             /* | 
 |               Read image colormap from file. | 
 |             */ | 
 |             packet_size=(size_t) (3UL*depth/8UL); | 
 |             colormap=(unsigned char *) AcquireQuantumMemory(image->colors, | 
 |               packet_size*sizeof(*colormap)); | 
 |             if (colormap == (unsigned char *) NULL) | 
 |               ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed"); | 
 |             count=ReadBlob(image,packet_size*image->colors,colormap); | 
 |             if (count != (ssize_t) (packet_size*image->colors)) | 
 |               ThrowReaderException(CorruptImageError, | 
 |                 "InsufficientImageDataInFile"); | 
 |             p=colormap; | 
 |             switch (depth) | 
 |             { | 
 |               default: | 
 |                 ThrowReaderException(CorruptImageError, | 
 |                   "ImageDepthNotSupported"); | 
 |               case 8: | 
 |               { | 
 |                 unsigned char | 
 |                   pixel; | 
 |  | 
 |                 for (i=0; i < (ssize_t) image->colors; i++) | 
 |                 { | 
 |                   p=PushCharPixel(p,&pixel); | 
 |                   image->colormap[i].red=ScaleCharToQuantum(pixel); | 
 |                   p=PushCharPixel(p,&pixel); | 
 |                   image->colormap[i].green=ScaleCharToQuantum(pixel); | 
 |                   p=PushCharPixel(p,&pixel); | 
 |                   image->colormap[i].blue=ScaleCharToQuantum(pixel); | 
 |                 } | 
 |                 break; | 
 |               } | 
 |               case 16: | 
 |               { | 
 |                 unsigned short | 
 |                   pixel; | 
 |  | 
 |                 for (i=0; i < (ssize_t) image->colors; i++) | 
 |                 { | 
 |                   p=PushShortPixel(MSBEndian,p,&pixel); | 
 |                   image->colormap[i].red=ScaleShortToQuantum(pixel); | 
 |                   p=PushShortPixel(MSBEndian,p,&pixel); | 
 |                   image->colormap[i].green=ScaleShortToQuantum(pixel); | 
 |                   p=PushShortPixel(MSBEndian,p,&pixel); | 
 |                   image->colormap[i].blue=ScaleShortToQuantum(pixel); | 
 |                 } | 
 |                 break; | 
 |               } | 
 |               case 32: | 
 |               { | 
 |                 unsigned int | 
 |                   pixel; | 
 |  | 
 |                 for (i=0; i < (ssize_t) image->colors; i++) | 
 |                 { | 
 |                   p=PushLongPixel(MSBEndian,p,&pixel); | 
 |                   image->colormap[i].red=ScaleLongToQuantum(pixel); | 
 |                   p=PushLongPixel(MSBEndian,p,&pixel); | 
 |                   image->colormap[i].green=ScaleLongToQuantum(pixel); | 
 |                   p=PushLongPixel(MSBEndian,p,&pixel); | 
 |                   image->colormap[i].blue=ScaleLongToQuantum(pixel); | 
 |                 } | 
 |                 break; | 
 |               } | 
 |             } | 
 |             colormap=(unsigned char *) RelinquishMagickMemory(colormap); | 
 |           } | 
 |       } | 
 |     if (EOFBlob(image) != MagickFalse) | 
 |       { | 
 |         ThrowFileException(exception,CorruptImageError,"UnexpectedEndOfFile", | 
 |           image->filename); | 
 |         break; | 
 |       } | 
 |     if ((image_info->ping != MagickFalse) && (image_info->number_scenes != 0)) | 
 |       if (image->scene >= (image_info->scene+image_info->number_scenes-1)) | 
 |         break; | 
 |     status=SetImageExtent(image,image->columns,image->rows,exception); | 
 |     if (status == MagickFalse) | 
 |       return(DestroyImageList(image)); | 
 |     /* | 
 |       Attach persistent pixel cache. | 
 |     */ | 
 |     status=PersistPixelCache(image,cache_filename,MagickTrue,&offset,exception); | 
 |     if (status == MagickFalse) | 
 |       ThrowReaderException(CacheError,"UnableToPersistPixelCache"); | 
 |     /* | 
 |       Proceed to next image. | 
 |     */ | 
 |     do | 
 |     { | 
 |       c=ReadBlobByte(image); | 
 |     } while ((isgraph(c) == MagickFalse) && (c != EOF)); | 
 |     if (c != EOF) | 
 |       { | 
 |         /* | 
 |           Allocate next image structure. | 
 |         */ | 
 |         AcquireNextImage(image_info,image,exception); | 
 |         if (GetNextImageInList(image) == (Image *) NULL) | 
 |           { | 
 |             image=DestroyImageList(image); | 
 |             return((Image *) NULL); | 
 |           } | 
 |         image=SyncNextImageInList(image); | 
 |         status=SetImageProgress(image,LoadImagesTag,TellBlob(image), | 
 |           GetBlobSize(image)); | 
 |         if (status == MagickFalse) | 
 |           break; | 
 |       } | 
 |   } while (c != EOF); | 
 |   (void) CloseBlob(image); | 
 |   return(GetFirstImageInList(image)); | 
 | } | 
 |  | 
 | /* | 
 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | 
 | %                                                                             % | 
 | %                                                                             % | 
 | %                                                                             % | 
 | %   R e g i s t e r M P C I m a g e                                           % | 
 | %                                                                             % | 
 | %                                                                             % | 
 | %                                                                             % | 
 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | 
 | % | 
 | %  RegisterMPCImage() adds properties for the Cache image format to | 
 | %  the list of supported formats.  The properties include the image format | 
 | %  tag, a method to read and/or write the format, whether the format | 
 | %  supports the saving of more than one frame to the same file or blob, | 
 | %  whether the format supports native in-memory I/O, and a brief | 
 | %  description of the format. | 
 | % | 
 | %  The format of the RegisterMPCImage method is: | 
 | % | 
 | %      size_t RegisterMPCImage(void) | 
 | % | 
 | */ | 
 | ModuleExport size_t RegisterMPCImage(void) | 
 | { | 
 |   MagickInfo | 
 |     *entry; | 
 |  | 
 |   entry=AcquireMagickInfo("MPC","CACHE", | 
 |     "Magick Persistent Cache image format"); | 
 |   entry->module=ConstantString("CACHE"); | 
 |   entry->flags|=CoderStealthFlag; | 
 |   (void) RegisterMagickInfo(entry); | 
 |   entry=AcquireMagickInfo("MPC","MPC","Magick Persistent Cache image format"); | 
 |   entry->decoder=(DecodeImageHandler *) ReadMPCImage; | 
 |   entry->encoder=(EncodeImageHandler *) WriteMPCImage; | 
 |   entry->magick=(IsImageFormatHandler *) IsMPC; | 
 |   (void) RegisterMagickInfo(entry); | 
 |   return(MagickImageCoderSignature); | 
 | } | 
 |  | 
 | /* | 
 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | 
 | %                                                                             % | 
 | %                                                                             % | 
 | %                                                                             % | 
 | %   U n r e g i s t e r M P C I m a g e                                       % | 
 | %                                                                             % | 
 | %                                                                             % | 
 | %                                                                             % | 
 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | 
 | % | 
 | %  UnregisterMPCImage() removes format registrations made by the | 
 | %  MPC module from the list of supported formats. | 
 | % | 
 | %  The format of the UnregisterMPCImage method is: | 
 | % | 
 | %      UnregisterMPCImage(void) | 
 | % | 
 | */ | 
 | ModuleExport void UnregisterMPCImage(void) | 
 | { | 
 |   (void) UnregisterMagickInfo("CACHE"); | 
 |   (void) UnregisterMagickInfo("MPC"); | 
 | } | 
 |  | 
 | /* | 
 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | 
 | %                                                                             % | 
 | %                                                                             % | 
 | %                                                                             % | 
 | %   W r i t e M P C I m a g e                                                 % | 
 | %                                                                             % | 
 | %                                                                             % | 
 | %                                                                             % | 
 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | 
 | % | 
 | %  WriteMPCImage() writes an Magick Persistent Cache image to a file. | 
 | % | 
 | %  The format of the WriteMPCImage method is: | 
 | % | 
 | %      MagickBooleanType WriteMPCImage(const ImageInfo *image_info, | 
 | %        Image *image,ExceptionInfo *exception) | 
 | % | 
 | %  A description of each parameter follows: | 
 | % | 
 | %    o image_info: the image info. | 
 | % | 
 | %    o image: the image. | 
 | % | 
 | %    o exception: return any errors or warnings in this structure. | 
 | % | 
 | */ | 
 | static MagickBooleanType WriteMPCImage(const ImageInfo *image_info,Image *image, | 
 |   ExceptionInfo *exception) | 
 | { | 
 |   char | 
 |     buffer[MagickPathExtent], | 
 |     cache_filename[MagickPathExtent]; | 
 |  | 
 |   const char | 
 |     *property, | 
 |     *value; | 
 |  | 
 |   MagickBooleanType | 
 |     status; | 
 |  | 
 |   MagickOffsetType | 
 |     offset, | 
 |     scene; | 
 |  | 
 |   register ssize_t | 
 |     i; | 
 |  | 
 |   size_t | 
 |     depth; | 
 |  | 
 |   /* | 
 |     Open persistent cache. | 
 |   */ | 
 |   assert(image_info != (const ImageInfo *) NULL); | 
 |   assert(image_info->signature == MagickSignature); | 
 |   assert(image != (Image *) NULL); | 
 |   assert(image->signature == MagickSignature); | 
 |   if (image->debug != MagickFalse) | 
 |     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); | 
 |   assert(exception != (ExceptionInfo *) NULL); | 
 |   assert(exception->signature == MagickSignature); | 
 |   status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception); | 
 |   if (status == MagickFalse) | 
 |     return(status); | 
 |   (void) CopyMagickString(cache_filename,image->filename,MagickPathExtent); | 
 |   AppendImageFormat("cache",cache_filename); | 
 |   scene=0; | 
 |   offset=0; | 
 |   do | 
 |   { | 
 |     /* | 
 |       Write persistent cache meta-information. | 
 |     */ | 
 |     depth=GetImageQuantumDepth(image,MagickTrue); | 
 |     if ((image->storage_class == PseudoClass) && | 
 |         (image->colors > (size_t) (GetQuantumRange(image->depth)+1))) | 
 |       (void) SetImageStorageClass(image,DirectClass,exception); | 
 |     (void) WriteBlobString(image,"id=MagickCache\n"); | 
 |     (void) FormatLocaleString(buffer,MagickPathExtent,"magick-signature=%u\n", | 
 |       GetMagickSignature((const StringInfo *) NULL)); | 
 |     (void) WriteBlobString(image,buffer); | 
 |     (void) FormatLocaleString(buffer,MagickPathExtent, | 
 |       "class=%s  colors=%.20g  alpha-trait=%s\n",CommandOptionToMnemonic( | 
 |       MagickClassOptions,image->storage_class),(double) image->colors, | 
 |       CommandOptionToMnemonic(MagickPixelTraitOptions,(ssize_t) | 
 |       image->alpha_trait)); | 
 |     (void) WriteBlobString(image,buffer); | 
 |     (void) FormatLocaleString(buffer,MagickPathExtent, | 
 |       "columns=%.20g  rows=%.20g depth=%.20g\n",(double) image->columns, | 
 |       (double) image->rows,(double) image->depth); | 
 |     (void) WriteBlobString(image,buffer); | 
 |     if (image->type != UndefinedType) | 
 |       { | 
 |         (void) FormatLocaleString(buffer,MagickPathExtent,"type=%s\n", | 
 |           CommandOptionToMnemonic(MagickTypeOptions,image->type)); | 
 |         (void) WriteBlobString(image,buffer); | 
 |       } | 
 |     if (image->colorspace != UndefinedColorspace) | 
 |       { | 
 |         (void) FormatLocaleString(buffer,MagickPathExtent,"colorspace=%s\n", | 
 |           CommandOptionToMnemonic(MagickColorspaceOptions,image->colorspace)); | 
 |         (void) WriteBlobString(image,buffer); | 
 |       } | 
 |     if (image->intensity != UndefinedPixelIntensityMethod) | 
 |       { | 
 |         (void) FormatLocaleString(buffer,MagickPathExtent,"pixel-intensity=%s\n", | 
 |           CommandOptionToMnemonic(MagickPixelIntensityOptions, | 
 |           image->intensity)); | 
 |         (void) WriteBlobString(image,buffer); | 
 |       } | 
 |     if (image->endian != UndefinedEndian) | 
 |       { | 
 |         (void) FormatLocaleString(buffer,MagickPathExtent,"endian=%s\n", | 
 |           CommandOptionToMnemonic(MagickEndianOptions,image->endian)); | 
 |         (void) WriteBlobString(image,buffer); | 
 |       } | 
 |     if (image->compression != UndefinedCompression) | 
 |       { | 
 |         (void) FormatLocaleString(buffer,MagickPathExtent, | 
 |           "compression=%s  quality=%.20g\n",CommandOptionToMnemonic( | 
 |           MagickCompressOptions,image->compression),(double) image->quality); | 
 |         (void) WriteBlobString(image,buffer); | 
 |       } | 
 |     if (image->units != UndefinedResolution) | 
 |       { | 
 |         (void) FormatLocaleString(buffer,MagickPathExtent,"units=%s\n", | 
 |           CommandOptionToMnemonic(MagickResolutionOptions,image->units)); | 
 |         (void) WriteBlobString(image,buffer); | 
 |       } | 
 |     if ((image->resolution.x != 0) || (image->resolution.y != 0)) | 
 |       { | 
 |         (void) FormatLocaleString(buffer,MagickPathExtent, | 
 |           "resolution=%gx%g\n",image->resolution.x,image->resolution.y); | 
 |         (void) WriteBlobString(image,buffer); | 
 |       } | 
 |     if ((image->page.width != 0) || (image->page.height != 0)) | 
 |       { | 
 |         (void) FormatLocaleString(buffer,MagickPathExtent, | 
 |           "page=%.20gx%.20g%+.20g%+.20g\n",(double) image->page.width,(double) | 
 |           image->page.height,(double) image->page.x,(double) image->page.y); | 
 |         (void) WriteBlobString(image,buffer); | 
 |       } | 
 |     else | 
 |       if ((image->page.x != 0) || (image->page.y != 0)) | 
 |         { | 
 |           (void) FormatLocaleString(buffer,MagickPathExtent,"page=%+ld%+ld\n", | 
 |             (long) image->page.x,(long) image->page.y); | 
 |           (void) WriteBlobString(image,buffer); | 
 |         } | 
 |     if ((image->tile_offset.x != 0) || (image->tile_offset.y != 0)) | 
 |       { | 
 |         (void) FormatLocaleString(buffer,MagickPathExtent, | 
 |           "tile-offset=%+ld%+ld\n",(long) image->tile_offset.x,(long) | 
 |            image->tile_offset.y); | 
 |         (void) WriteBlobString(image,buffer); | 
 |       } | 
 |     if ((GetNextImageInList(image) != (Image *) NULL) || | 
 |         (GetPreviousImageInList(image) != (Image *) NULL)) | 
 |       { | 
 |         if (image->scene == 0) | 
 |           (void) FormatLocaleString(buffer,MagickPathExtent, | 
 |             "iterations=%.20g  delay=%.20g  ticks-per-second=%.20g\n",(double) | 
 |             image->iterations,(double) image->delay,(double) | 
 |             image->ticks_per_second); | 
 |         else | 
 |           (void) FormatLocaleString(buffer,MagickPathExtent,"scene=%.20g  " | 
 |             "iterations=%.20g  delay=%.20g  ticks-per-second=%.20g\n", | 
 |             (double) image->scene,(double) image->iterations,(double) | 
 |             image->delay,(double) image->ticks_per_second); | 
 |         (void) WriteBlobString(image,buffer); | 
 |       } | 
 |     else | 
 |       { | 
 |         if (image->scene != 0) | 
 |           { | 
 |             (void) FormatLocaleString(buffer,MagickPathExtent,"scene=%.20g\n", | 
 |               (double) image->scene); | 
 |             (void) WriteBlobString(image,buffer); | 
 |           } | 
 |         if (image->iterations != 0) | 
 |           { | 
 |             (void) FormatLocaleString(buffer,MagickPathExtent,"iterations=%.20g\n", | 
 |               (double) image->iterations); | 
 |             (void) WriteBlobString(image,buffer); | 
 |           } | 
 |         if (image->delay != 0) | 
 |           { | 
 |             (void) FormatLocaleString(buffer,MagickPathExtent,"delay=%.20g\n", | 
 |               (double) image->delay); | 
 |             (void) WriteBlobString(image,buffer); | 
 |           } | 
 |         if (image->ticks_per_second != UndefinedTicksPerSecond) | 
 |           { | 
 |             (void) FormatLocaleString(buffer,MagickPathExtent, | 
 |               "ticks-per-second=%.20g\n",(double) image->ticks_per_second); | 
 |             (void) WriteBlobString(image,buffer); | 
 |           } | 
 |       } | 
 |     if (image->gravity != UndefinedGravity) | 
 |       { | 
 |         (void) FormatLocaleString(buffer,MagickPathExtent,"gravity=%s\n", | 
 |           CommandOptionToMnemonic(MagickGravityOptions,image->gravity)); | 
 |         (void) WriteBlobString(image,buffer); | 
 |       } | 
 |     if (image->dispose != UndefinedDispose) | 
 |       { | 
 |         (void) FormatLocaleString(buffer,MagickPathExtent,"dispose=%s\n", | 
 |           CommandOptionToMnemonic(MagickDisposeOptions,image->dispose)); | 
 |         (void) WriteBlobString(image,buffer); | 
 |       } | 
 |     if (image->rendering_intent != UndefinedIntent) | 
 |       { | 
 |         (void) FormatLocaleString(buffer,MagickPathExtent, | 
 |           "rendering-intent=%s\n",CommandOptionToMnemonic(MagickIntentOptions, | 
 |           image->rendering_intent)); | 
 |         (void) WriteBlobString(image,buffer); | 
 |       } | 
 |     if (image->gamma != 0.0) | 
 |       { | 
 |         (void) FormatLocaleString(buffer,MagickPathExtent,"gamma=%g\n", | 
 |           image->gamma); | 
 |         (void) WriteBlobString(image,buffer); | 
 |       } | 
 |     if (image->chromaticity.white_point.x != 0.0) | 
 |       { | 
 |         /* | 
 |           Note chomaticity points. | 
 |         */ | 
 |         (void) FormatLocaleString(buffer,MagickPathExtent,"red-primary=" | 
 |           "%g,%g  green-primary=%g,%g  blue-primary=%g,%g\n", | 
 |           image->chromaticity.red_primary.x,image->chromaticity.red_primary.y, | 
 |           image->chromaticity.green_primary.x, | 
 |           image->chromaticity.green_primary.y, | 
 |           image->chromaticity.blue_primary.x, | 
 |           image->chromaticity.blue_primary.y); | 
 |         (void) WriteBlobString(image,buffer); | 
 |         (void) FormatLocaleString(buffer,MagickPathExtent, | 
 |           "white-point=%g,%g\n",image->chromaticity.white_point.x, | 
 |           image->chromaticity.white_point.y); | 
 |         (void) WriteBlobString(image,buffer); | 
 |       } | 
 |     if (image->orientation != UndefinedOrientation) | 
 |       { | 
 |         (void) FormatLocaleString(buffer,MagickPathExtent, | 
 |           "orientation=%s\n",CommandOptionToMnemonic(MagickOrientationOptions, | 
 |           image->orientation)); | 
 |         (void) WriteBlobString(image,buffer); | 
 |       } | 
 |     if (image->profiles != (void *) NULL) | 
 |       { | 
 |         const char | 
 |           *name; | 
 |  | 
 |         const StringInfo | 
 |           *profile; | 
 |  | 
 |         /* | 
 |           Generic profile. | 
 |         */ | 
 |         ResetImageProfileIterator(image); | 
 |         for (name=GetNextImageProfile(image); name != (const char *) NULL; ) | 
 |         { | 
 |           profile=GetImageProfile(image,name); | 
 |           if (profile != (StringInfo *) NULL) | 
 |             { | 
 |               (void) FormatLocaleString(buffer,MagickPathExtent, | 
 |                 "profile:%s=%.20g\n",name,(double) | 
 |                 GetStringInfoLength(profile)); | 
 |               (void) WriteBlobString(image,buffer); | 
 |             } | 
 |           name=GetNextImageProfile(image); | 
 |         } | 
 |       } | 
 |     if (image->montage != (char *) NULL) | 
 |       { | 
 |         (void) FormatLocaleString(buffer,MagickPathExtent,"montage=%s\n", | 
 |           image->montage); | 
 |         (void) WriteBlobString(image,buffer); | 
 |       } | 
 |     ResetImagePropertyIterator(image); | 
 |     property=GetNextImageProperty(image); | 
 |     while (property != (const char *) NULL) | 
 |     { | 
 |       (void) FormatLocaleString(buffer,MagickPathExtent,"%s=",property); | 
 |       (void) WriteBlobString(image,buffer); | 
 |       value=GetImageProperty(image,property,exception); | 
 |       if (value != (const char *) NULL) | 
 |         { | 
 |           size_t | 
 |             length; | 
 |  | 
 |           length=strlen(value); | 
 |           for (i=0; i < (ssize_t) length; i++) | 
 |             if (isspace((int) ((unsigned char) value[i])) != 0) | 
 |               break; | 
 |           if ((i == (ssize_t) length) && (i != 0)) | 
 |             (void) WriteBlob(image,length,(const unsigned char *) value); | 
 |           else | 
 |             { | 
 |               (void) WriteBlobByte(image,'{'); | 
 |               if (strchr(value,'}') == (char *) NULL) | 
 |                 (void) WriteBlob(image,length,(const unsigned char *) value); | 
 |               else | 
 |                 for (i=0; i < (ssize_t) length; i++) | 
 |                 { | 
 |                   if (value[i] == (int) '}') | 
 |                     (void) WriteBlobByte(image,'\\'); | 
 |                   (void) WriteBlobByte(image,value[i]); | 
 |                 } | 
 |               (void) WriteBlobByte(image,'}'); | 
 |             } | 
 |         } | 
 |       (void) WriteBlobByte(image,'\n'); | 
 |       property=GetNextImageProperty(image); | 
 |     } | 
 |     (void) WriteBlobString(image,"\f\n:\032"); | 
 |     if (image->montage != (char *) NULL) | 
 |       { | 
 |         /* | 
 |           Write montage tile directory. | 
 |         */ | 
 |         if (image->directory != (char *) NULL) | 
 |           (void) WriteBlobString(image,image->directory); | 
 |         (void) WriteBlobByte(image,'\0'); | 
 |       } | 
 |     if (image->profiles != 0) | 
 |       { | 
 |         const char | 
 |           *name; | 
 |  | 
 |         const StringInfo | 
 |           *profile; | 
 |  | 
 |         /* | 
 |           Write image profiles. | 
 |         */ | 
 |         ResetImageProfileIterator(image); | 
 |         name=GetNextImageProfile(image); | 
 |         while (name != (const char *) NULL) | 
 |         { | 
 |           profile=GetImageProfile(image,name); | 
 |           (void) WriteBlob(image,GetStringInfoLength(profile), | 
 |             GetStringInfoDatum(profile)); | 
 |           name=GetNextImageProfile(image); | 
 |         } | 
 |       } | 
 |     if (image->storage_class == PseudoClass) | 
 |       { | 
 |         size_t | 
 |           packet_size; | 
 |  | 
 |         unsigned char | 
 |           *colormap, | 
 |           *q; | 
 |  | 
 |         /* | 
 |           Allocate colormap. | 
 |         */ | 
 |         packet_size=(size_t) (3UL*depth/8UL); | 
 |         colormap=(unsigned char *) AcquireQuantumMemory(image->colors, | 
 |           packet_size*sizeof(*colormap)); | 
 |         if (colormap == (unsigned char *) NULL) | 
 |           return(MagickFalse); | 
 |         /* | 
 |           Write colormap to file. | 
 |         */ | 
 |         q=colormap; | 
 |         for (i=0; i < (ssize_t) image->colors; i++) | 
 |         { | 
 |           switch (depth) | 
 |           { | 
 |             default: | 
 |               ThrowWriterException(CorruptImageError,"ImageDepthNotSupported"); | 
 |             case 32: | 
 |             { | 
 |               unsigned int | 
 |                 pixel; | 
 |  | 
 |               pixel=ScaleQuantumToLong(image->colormap[i].red); | 
 |               q=PopLongPixel(MSBEndian,pixel,q); | 
 |               pixel=ScaleQuantumToLong(image->colormap[i].green); | 
 |               q=PopLongPixel(MSBEndian,pixel,q); | 
 |               pixel=ScaleQuantumToLong(image->colormap[i].blue); | 
 |               q=PopLongPixel(MSBEndian,pixel,q); | 
 |               break; | 
 |             } | 
 |             case 16: | 
 |             { | 
 |               unsigned short | 
 |                 pixel; | 
 |  | 
 |               pixel=ScaleQuantumToShort(image->colormap[i].red); | 
 |               q=PopShortPixel(MSBEndian,pixel,q); | 
 |               pixel=ScaleQuantumToShort(image->colormap[i].green); | 
 |               q=PopShortPixel(MSBEndian,pixel,q); | 
 |               pixel=ScaleQuantumToShort(image->colormap[i].blue); | 
 |               q=PopShortPixel(MSBEndian,pixel,q); | 
 |               break; | 
 |             } | 
 |             case 8: | 
 |             { | 
 |               unsigned char | 
 |                 pixel; | 
 |  | 
 |               pixel=(unsigned char) ScaleQuantumToChar(image->colormap[i].red); | 
 |               q=PopCharPixel(pixel,q); | 
 |               pixel=(unsigned char) ScaleQuantumToChar( | 
 |                 image->colormap[i].green); | 
 |               q=PopCharPixel(pixel,q); | 
 |               pixel=(unsigned char) ScaleQuantumToChar(image->colormap[i].blue); | 
 |               q=PopCharPixel(pixel,q); | 
 |               break; | 
 |             } | 
 |           } | 
 |         } | 
 |         (void) WriteBlob(image,packet_size*image->colors,colormap); | 
 |         colormap=(unsigned char *) RelinquishMagickMemory(colormap); | 
 |       } | 
 |     /* | 
 |       Initialize persistent pixel cache. | 
 |     */ | 
 |     status=PersistPixelCache(image,cache_filename,MagickFalse,&offset, | 
 |       exception); | 
 |     if (status == MagickFalse) | 
 |       ThrowWriterException(CacheError,"UnableToPersistPixelCache"); | 
 |     if (GetNextImageInList(image) == (Image *) NULL) | 
 |       break; | 
 |     image=SyncNextImageInList(image); | 
 |     if (image->progress_monitor != (MagickProgressMonitor) NULL) | 
 |       { | 
 |         status=image->progress_monitor(SaveImagesTag,scene, | 
 |           GetImageListLength(image),image->client_data); | 
 |         if (status == MagickFalse) | 
 |           break; | 
 |       } | 
 |     scene++; | 
 |   } while (image_info->adjoin != MagickFalse); | 
 |   (void) CloseBlob(image); | 
 |   return(status); | 
 | } |