| /* | 
 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | 
 | %                                                                             % | 
 | %                                                                             % | 
 | %                                                                             % | 
 | %                            X   X  PPPP   M   M                              % | 
 | %                             X X   P   P  MM MM                              % | 
 | %                              X    PPPP   M M M                              % | 
 | %                             X X   P      M   M                              % | 
 | %                            X   X  P      M   M                              % | 
 | %                                                                             % | 
 | %                                                                             % | 
 | %                  Read/Write X Windows system Pixmap Format                  % | 
 | %                                                                             % | 
 | %                              Software Design                                % | 
 | %                                John Cristy                                  % | 
 | %                                 July 1992                                   % | 
 | %                                                                             % | 
 | %                                                                             % | 
 | %  Copyright 1999-2013 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/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/colorspace.h" | 
 | #include "MagickCore/colorspace-private.h" | 
 | #include "MagickCore/exception.h" | 
 | #include "MagickCore/exception-private.h" | 
 | #include "MagickCore/geometry.h" | 
 | #include "MagickCore/image.h" | 
 | #include "MagickCore/image-private.h" | 
 | #include "MagickCore/list.h" | 
 | #include "MagickCore/magick.h" | 
 | #include "MagickCore/memory_.h" | 
 | #include "MagickCore/monitor.h" | 
 | #include "MagickCore/monitor-private.h" | 
 | #include "MagickCore/pixel-accessor.h" | 
 | #include "MagickCore/quantize.h" | 
 | #include "MagickCore/quantum-private.h" | 
 | #include "MagickCore/resize.h" | 
 | #include "MagickCore/resource_.h" | 
 | #include "MagickCore/splay-tree.h" | 
 | #include "MagickCore/static.h" | 
 | #include "MagickCore/string_.h" | 
 | #include "MagickCore/module.h" | 
 | #include "MagickCore/threshold.h" | 
 | #include "MagickCore/utility.h" | 
 |  | 
 | /* | 
 |   Forward declarations. | 
 | */ | 
 | static MagickBooleanType | 
 |   WritePICONImage(const ImageInfo *,Image *,ExceptionInfo *), | 
 |   WriteXPMImage(const ImageInfo *,Image *,ExceptionInfo *); | 
 |  | 
 | /* | 
 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | 
 | %                                                                             % | 
 | %                                                                             % | 
 | %                                                                             % | 
 | %   I s X P M                                                                 % | 
 | %                                                                             % | 
 | %                                                                             % | 
 | %                                                                             % | 
 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | 
 | % | 
 | %  IsXPM() returns MagickTrue if the image format type, identified by the | 
 | %  magick string, is XPM. | 
 | % | 
 | %  The format of the IsXPM method is: | 
 | % | 
 | %      MagickBooleanType IsXPM(const unsigned char *magick,const size_t length) | 
 | % | 
 | %  A description of each parameter follows: | 
 | % | 
 | %    o magick: compare image format pattern against these bytes. or | 
 | %      blob. | 
 | % | 
 | %    o length: Specifies the length of the magick string. | 
 | % | 
 | */ | 
 | static MagickBooleanType IsXPM(const unsigned char *magick,const size_t length) | 
 | { | 
 |   if (length < 9) | 
 |     return(MagickFalse); | 
 |   if (LocaleNCompare((char *) magick+1,"* XPM *",7) == 0) | 
 |     return(MagickTrue); | 
 |   return(MagickFalse); | 
 | } | 
 |  | 
 | /* | 
 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | 
 | %                                                                             % | 
 | %                                                                             % | 
 | %                                                                             % | 
 | %   R e a d X P M I m a g e                                                   % | 
 | %                                                                             % | 
 | %                                                                             % | 
 | %                                                                             % | 
 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | 
 | % | 
 | %  ReadXPMImage() reads an X11 pixmap 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 ReadXPMImage method is: | 
 | % | 
 | %      Image *ReadXPMImage(const ImageInfo *image_info,ExceptionInfo *exception) | 
 | % | 
 | %  A description of each parameter follows: | 
 | % | 
 | %    o image_info: the image info. | 
 | % | 
 | %    o exception: return any errors or warnings in this structure. | 
 | % | 
 | */ | 
 |  | 
 | static int CompareXPMColor(const void *target,const void *source) | 
 | { | 
 |   const char | 
 |     *p, | 
 |     *q; | 
 |   | 
 |   p=(const char *) target; | 
 |   q=(const char *) source; | 
 |   return(strcmp(p,q)); | 
 | } | 
 |  | 
 | static char *CopyXPMColor(char *destination,const char *source,size_t length) | 
 | { | 
 |   while (length-- && (*source != '\0')) | 
 |     *destination++=(*source++); | 
 |   *destination='\0'; | 
 |   return(destination-length); | 
 | } | 
 |  | 
 | static char *NextXPMLine(char *p) | 
 | { | 
 |   assert(p != (char*)NULL); | 
 |   p=strchr(p,'\n'); | 
 |   if (p != (char *) NULL) | 
 |     p++; | 
 |   return(p); | 
 | } | 
 |  | 
 | static inline size_t MagickMin(const size_t x,const size_t y) | 
 | { | 
 |   if (x < y) | 
 |     return(x); | 
 |   return(y); | 
 | } | 
 |  | 
 | static char *ParseXPMColor(char *color) | 
 | { | 
 | #define NumberTargets  6 | 
 |  | 
 |   register char | 
 |     *p, | 
 |     *r; | 
 |  | 
 |   register const char | 
 |     *q; | 
 |  | 
 |   register ssize_t | 
 |     i; | 
 |  | 
 |   static const char | 
 |     *targets[NumberTargets] = { "c ", "g ", "g4 ", "m ", "b ", "s " }; | 
 |  | 
 |   for (i=0; i < NumberTargets; i++) | 
 |   { | 
 |     p=color; | 
 |     for (q=targets[i]; *p != '\0'; p++) | 
 |     { | 
 |       if (*p == '\n') | 
 |         break; | 
 |       if (*p != *q) | 
 |         continue; | 
 |       if (isspace((int) ((unsigned char) (*(p-1)))) == 0) | 
 |         continue; | 
 |       r=p; | 
 |       for ( ; ; ) | 
 |       { | 
 |         if (*q == '\0') | 
 |           return(p); | 
 |         if (*r++ != *q++) | 
 |           break; | 
 |       } | 
 |       q=targets[i]; | 
 |     } | 
 |   } | 
 |   return((char *) NULL); | 
 | } | 
 |  | 
 | static Image *ReadXPMImage(const ImageInfo *image_info,ExceptionInfo *exception) | 
 | { | 
 |   char | 
 |     key[MaxTextExtent], | 
 |     target[MaxTextExtent], | 
 |     *xpm_buffer; | 
 |  | 
 |   Image | 
 |     *image; | 
 |  | 
 |   MagickBooleanType | 
 |     active, | 
 |     status; | 
 |  | 
 |   register char | 
 |     *p, | 
 |     *q, | 
 |     *next; | 
 |  | 
 |   register ssize_t | 
 |     x; | 
 |  | 
 |   register Quantum | 
 |     *r; | 
 |  | 
 |   size_t | 
 |     length; | 
 |  | 
 |   SplayTreeInfo | 
 |     *xpm_colors; | 
 |  | 
 |   ssize_t | 
 |     count, | 
 |     j, | 
 |     y; | 
 |  | 
 |   unsigned long | 
 |     colors, | 
 |     columns, | 
 |     rows, | 
 |     width; | 
 |  | 
 |   /* | 
 |     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); | 
 |     } | 
 |   /* | 
 |     Read XPM file. | 
 |   */ | 
 |   length=MaxTextExtent; | 
 |   xpm_buffer=(char *) AcquireQuantumMemory((size_t) length,sizeof(*xpm_buffer)); | 
 |   p=xpm_buffer; | 
 |   if (xpm_buffer != (char *) NULL) | 
 |     while (ReadBlobString(image,p) != (char *) NULL) | 
 |     { | 
 |       if ((*p == '#') && ((p == xpm_buffer) || (*(p-1) == '\n'))) | 
 |         continue; | 
 |       if ((*p == '}') && (*(p+1) == ';')) | 
 |         break; | 
 |       p+=strlen(p); | 
 |       if ((size_t) (p-xpm_buffer+MaxTextExtent) < length) | 
 |         continue; | 
 |       length<<=1; | 
 |       xpm_buffer=(char *) ResizeQuantumMemory(xpm_buffer,length+MaxTextExtent, | 
 |         sizeof(*xpm_buffer)); | 
 |       if (xpm_buffer == (char *) NULL) | 
 |         break; | 
 |       p=xpm_buffer+strlen(xpm_buffer); | 
 |     } | 
 |   if (xpm_buffer == (char *) NULL) | 
 |     ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed"); | 
 |   /* | 
 |     Remove comments. | 
 |   */ | 
 |   count=0; | 
 |   for (p=xpm_buffer; *p != '\0'; p++) | 
 |   { | 
 |     if (*p != '"') | 
 |       continue; | 
 |     count=(ssize_t) sscanf(p+1,"%lu %lu %lu %lu",&columns,&rows,&colors,&width); | 
 |     image->columns=columns; | 
 |     image->rows=rows; | 
 |     image->colors=colors; | 
 |     if (count == 4) | 
 |       break; | 
 |   } | 
 |   if ((count != 4) || (width > 10) || (image->columns == 0) || | 
 |       (image->rows == 0) || (image->colors == 0)) | 
 |     ThrowReaderException(CorruptImageError,"ImproperImageHeader"); | 
 |   image->depth=16; | 
 |   /* | 
 |     Remove unquoted characters. | 
 |   */ | 
 |   active=MagickFalse; | 
 |   q=xpm_buffer; | 
 |   while (*p != '\0') | 
 |   { | 
 |     if (*p++ == '"') | 
 |       { | 
 |         if (active != MagickFalse) | 
 |           *q++='\n'; | 
 |         active=active != MagickFalse ? MagickFalse : MagickTrue; | 
 |       } | 
 |     if (active != MagickFalse) | 
 |       *q++=(*p); | 
 |   } | 
 |   *q='\0'; | 
 |   /* | 
 |     Initialize image structure. | 
 |   */ | 
 |   xpm_colors=NewSplayTree(CompareXPMColor,RelinquishMagickMemory, | 
 |     (void *(*)(void *)) NULL); | 
 |   if (AcquireImageColormap(image,image->colors,exception) == MagickFalse) | 
 |     ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed"); | 
 |   /* | 
 |     Read image colormap. | 
 |   */ | 
 |   next=NextXPMLine(xpm_buffer); | 
 |   for (j=0; (j < (ssize_t) image->colors) && (next != (char*) NULL); j++) | 
 |   { | 
 |     p=next; | 
 |     next=NextXPMLine(p); | 
 |     (void) CopyXPMColor(key,p,MagickMin((size_t) width,MaxTextExtent)); | 
 |     status=AddValueToSplayTree(xpm_colors,ConstantString(key),(void *) j); | 
 |     /* | 
 |       Parse color. | 
 |     */ | 
 |     (void) CopyMagickString(target,"gray",MaxTextExtent); | 
 |     q=ParseXPMColor(p+width); | 
 |     if (q != (char *) NULL) | 
 |       { | 
 |         while ((isspace((int) ((unsigned char) *q)) == 0) && (*q != '\0')) | 
 |           q++; | 
 |         if (next != (char *) NULL) | 
 |           (void) CopyXPMColor(target,q,MagickMin((size_t) (next-q), | 
 |             MaxTextExtent)); | 
 |         else | 
 |           (void) CopyMagickString(target,q,MaxTextExtent); | 
 |         q=ParseXPMColor(target); | 
 |         if (q != (char *) NULL) | 
 |           *q='\0'; | 
 |       } | 
 |     StripString(target); | 
 |     if (LocaleCompare(target,"none") == 0) | 
 |       { | 
 |         image->storage_class=DirectClass; | 
 |         image->alpha_trait=BlendPixelTrait; | 
 |       } | 
 |     status=QueryColorCompliance(target,AllCompliance,&image->colormap[j], | 
 |       exception); | 
 |     if (status == MagickFalse) | 
 |       break; | 
 |   } | 
 |   if (j < (ssize_t) image->colors) | 
 |     ThrowReaderException(CorruptImageError,"CorruptImage"); | 
 |   j=0; | 
 |   if (image_info->ping == MagickFalse) | 
 |     { | 
 |       /* | 
 |         Read image pixels. | 
 |       */ | 
 |       for (y=0; y < (ssize_t) image->rows; y++) | 
 |       { | 
 |         p=NextXPMLine(p); | 
 |         if (p == (char *) NULL) | 
 |           break; | 
 |         r=QueueAuthenticPixels(image,0,y,image->columns,1,exception); | 
 |         if (r == (Quantum *) NULL) | 
 |           break; | 
 |         for (x=0; x < (ssize_t) image->columns; x++) | 
 |         { | 
 |           (void) CopyXPMColor(key,p,(size_t) width); | 
 |           j=(ssize_t) GetValueFromSplayTree(xpm_colors,key); | 
 |           if (image->storage_class == PseudoClass) | 
 |             SetPixelIndex(image,j,r); | 
 |           SetPixelInfoPixel(image,image->colormap+j,r); | 
 |           p+=width; | 
 |           r+=GetPixelChannels(image); | 
 |         } | 
 |         if (SyncAuthenticPixels(image,exception) == MagickFalse) | 
 |           break; | 
 |       } | 
 |       if (y < (ssize_t) image->rows) | 
 |         ThrowReaderException(CorruptImageError,"NotEnoughPixelData"); | 
 |     } | 
 |   /* | 
 |     Relinquish resources. | 
 |   */ | 
 |   xpm_colors=DestroySplayTree(xpm_colors); | 
 |   (void) CloseBlob(image); | 
 |   return(GetFirstImageInList(image)); | 
 | } | 
 |  | 
 | /* | 
 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | 
 | %                                                                             % | 
 | %                                                                             % | 
 | %                                                                             % | 
 | %   R e g i s t e r X P M I m a g e                                           % | 
 | %                                                                             % | 
 | %                                                                             % | 
 | %                                                                             % | 
 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | 
 | % | 
 | %  RegisterXPMImage() adds attributes for the XPM image format to | 
 | %  the list of supported formats.  The attributes 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 RegisterXPMImage method is: | 
 | % | 
 | %      size_t RegisterXPMImage(void) | 
 | % | 
 | */ | 
 | ModuleExport size_t RegisterXPMImage(void) | 
 | { | 
 |   MagickInfo | 
 |     *entry; | 
 |  | 
 |   entry=SetMagickInfo("PICON"); | 
 |   entry->decoder=(DecodeImageHandler *) ReadXPMImage; | 
 |   entry->encoder=(EncodeImageHandler *) WritePICONImage; | 
 |   entry->adjoin=MagickFalse; | 
 |   entry->description=ConstantString("Personal Icon"); | 
 |   entry->module=ConstantString("XPM"); | 
 |   (void) RegisterMagickInfo(entry); | 
 |   entry=SetMagickInfo("PM"); | 
 |   entry->decoder=(DecodeImageHandler *) ReadXPMImage; | 
 |   entry->encoder=(EncodeImageHandler *) WriteXPMImage; | 
 |   entry->adjoin=MagickFalse; | 
 |   entry->stealth=MagickTrue; | 
 |   entry->description=ConstantString("X Windows system pixmap (color)"); | 
 |   entry->module=ConstantString("XPM"); | 
 |   (void) RegisterMagickInfo(entry); | 
 |   entry=SetMagickInfo("XPM"); | 
 |   entry->decoder=(DecodeImageHandler *) ReadXPMImage; | 
 |   entry->encoder=(EncodeImageHandler *) WriteXPMImage; | 
 |   entry->magick=(IsImageFormatHandler *) IsXPM; | 
 |   entry->adjoin=MagickFalse; | 
 |   entry->description=ConstantString("X Windows system pixmap (color)"); | 
 |   entry->module=ConstantString("XPM"); | 
 |   (void) RegisterMagickInfo(entry); | 
 |   return(MagickImageCoderSignature); | 
 | } | 
 |  | 
 | /* | 
 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | 
 | %                                                                             % | 
 | %                                                                             % | 
 | %                                                                             % | 
 | %   U n r e g i s t e r X P M I m a g e                                       % | 
 | %                                                                             % | 
 | %                                                                             % | 
 | %                                                                             % | 
 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | 
 | % | 
 | %  UnregisterXPMImage() removes format registrations made by the | 
 | %  XPM module from the list of supported formats. | 
 | % | 
 | %  The format of the UnregisterXPMImage method is: | 
 | % | 
 | %      UnregisterXPMImage(void) | 
 | % | 
 | */ | 
 | ModuleExport void UnregisterXPMImage(void) | 
 | { | 
 |   (void) UnregisterMagickInfo("PICON"); | 
 |   (void) UnregisterMagickInfo("PM"); | 
 |   (void) UnregisterMagickInfo("XPM"); | 
 | } | 
 |  | 
 | /* | 
 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | 
 | %                                                                             % | 
 | %                                                                             % | 
 | %                                                                             % | 
 | %   W r i t e P I C O N I m a g e                                             % | 
 | %                                                                             % | 
 | %                                                                             % | 
 | %                                                                             % | 
 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | 
 | % | 
 | %  WritePICONImage() writes an image to a file in the Personal Icon format. | 
 | % | 
 | %  The format of the WritePICONImage method is: | 
 | % | 
 | %      MagickBooleanType WritePICONImage(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 WritePICONImage(const ImageInfo *image_info, | 
 |   Image *image,ExceptionInfo *exception) | 
 | { | 
 | #define ColormapExtent  155 | 
 | #define GraymapExtent  95 | 
 | #define PiconGeometry  "48x48>" | 
 |  | 
 |   static unsigned char | 
 |     Colormap[]= | 
 |     { | 
 |       0x47, 0x49, 0x46, 0x38, 0x37, 0x61, 0x06, 0x00, 0x05, 0x00, 0xf4, 0x05, | 
 |       0x00, 0x00, 0x00, 0x00, 0x2f, 0x4f, 0x4f, 0x70, 0x80, 0x90, 0x7e, 0x7e, | 
 |       0x7e, 0xdc, 0xdc, 0xdc, 0xff, 0xff, 0xff, 0x00, 0x00, 0x80, 0x00, 0x00, | 
 |       0xff, 0x1e, 0x90, 0xff, 0x87, 0xce, 0xeb, 0xe6, 0xe6, 0xfa, 0x00, 0xff, | 
 |       0xff, 0x80, 0x00, 0x80, 0xb2, 0x22, 0x22, 0x2e, 0x8b, 0x57, 0x32, 0xcd, | 
 |       0x32, 0x00, 0xff, 0x00, 0x98, 0xfb, 0x98, 0xff, 0x00, 0xff, 0xff, 0x00, | 
 |       0x00, 0xff, 0x63, 0x47, 0xff, 0xa5, 0x00, 0xff, 0xd7, 0x00, 0xff, 0xff, | 
 |       0x00, 0xee, 0x82, 0xee, 0xa0, 0x52, 0x2d, 0xcd, 0x85, 0x3f, 0xd2, 0xb4, | 
 |       0x8c, 0xf5, 0xde, 0xb3, 0xff, 0xfa, 0xcd, 0x00, 0x00, 0x00, 0x00, 0x00, | 
 |       0x00, 0x21, 0xf9, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, | 
 |       0x00, 0x00, 0x06, 0x00, 0x05, 0x00, 0x00, 0x05, 0x18, 0x20, 0x10, 0x08, | 
 |       0x03, 0x51, 0x18, 0x07, 0x92, 0x28, 0x0b, 0xd3, 0x38, 0x0f, 0x14, 0x49, | 
 |       0x13, 0x55, 0x59, 0x17, 0x96, 0x69, 0x1b, 0xd7, 0x85, 0x00, 0x3b, | 
 |     }, | 
 |     Graymap[]= | 
 |     { | 
 |       0x47, 0x49, 0x46, 0x38, 0x37, 0x61, 0x04, 0x00, 0x04, 0x00, 0xf3, 0x0f, | 
 |       0x00, 0x00, 0x00, 0x00, 0x12, 0x12, 0x12, 0x21, 0x21, 0x21, 0x33, 0x33, | 
 |       0x33, 0x45, 0x45, 0x45, 0x54, 0x54, 0x54, 0x66, 0x66, 0x66, 0x78, 0x78, | 
 |       0x78, 0x87, 0x87, 0x87, 0x99, 0x99, 0x99, 0xab, 0xab, 0xab, 0xba, 0xba, | 
 |       0xba, 0xcc, 0xcc, 0xcc, 0xde, 0xde, 0xde, 0xed, 0xed, 0xed, 0xff, 0xff, | 
 |       0xff, 0x21, 0xf9, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, | 
 |       0x00, 0x00, 0x04, 0x00, 0x04, 0x00, 0x00, 0x04, 0x0c, 0x10, 0x04, 0x31, | 
 |       0x48, 0x31, 0x07, 0x25, 0xb5, 0x58, 0x73, 0x4f, 0x04, 0x00, 0x3b, | 
 |     }; | 
 |  | 
 | #define MaxCixels  92 | 
 |  | 
 |   static const char | 
 |     Cixel[MaxCixels+1] = " .XoO+@#$%&*=-;:>,<1234567890qwertyuipasdfghjk" | 
 |                          "lzxcvbnmMNBVCZASDFGHJKLPIUYTREWQ!~^/()_`'][{}|"; | 
 |  | 
 |   char | 
 |     buffer[MaxTextExtent], | 
 |     basename[MaxTextExtent], | 
 |     name[MaxTextExtent], | 
 |     symbol[MaxTextExtent]; | 
 |  | 
 |   Image | 
 |     *affinity_image, | 
 |     *picon; | 
 |  | 
 |   ImageInfo | 
 |     *blob_info; | 
 |  | 
 |   MagickBooleanType | 
 |     status, | 
 |     transparent; | 
 |  | 
 |   PixelInfo | 
 |     pixel; | 
 |  | 
 |   QuantizeInfo | 
 |     *quantize_info; | 
 |  | 
 |   RectangleInfo | 
 |     geometry; | 
 |  | 
 |   register const Quantum | 
 |     *p; | 
 |  | 
 |   register ssize_t | 
 |     i, | 
 |     x; | 
 |  | 
 |   register Quantum | 
 |     *q; | 
 |  | 
 |   size_t | 
 |     characters_per_pixel, | 
 |     colors; | 
 |  | 
 |   ssize_t | 
 |     j, | 
 |     k, | 
 |     y; | 
 |  | 
 |   /* | 
 |     Open output image file. | 
 |   */ | 
 |   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); | 
 |   if (IssRGBCompatibleColorspace(image->colorspace) == MagickFalse) | 
 |     (void) TransformImageColorspace(image,sRGBColorspace,exception); | 
 |   SetGeometry(image,&geometry); | 
 |   (void) ParseMetaGeometry(PiconGeometry,&geometry.x,&geometry.y, | 
 |     &geometry.width,&geometry.height); | 
 |   picon=ResizeImage(image,geometry.width,geometry.height,TriangleFilter, | 
 |     exception); | 
 |   blob_info=CloneImageInfo(image_info); | 
 |   (void) AcquireUniqueFilename(blob_info->filename); | 
 |   if ((image_info->type != TrueColorType) && | 
 |       (IsImageGray(image,exception) != MagickFalse)) | 
 |     affinity_image=BlobToImage(blob_info,Graymap,GraymapExtent,exception); | 
 |   else | 
 |     affinity_image=BlobToImage(blob_info,Colormap,ColormapExtent,exception); | 
 |   (void) RelinquishUniqueFileResource(blob_info->filename); | 
 |   blob_info=DestroyImageInfo(blob_info); | 
 |   if ((picon == (Image *) NULL) || (affinity_image == (Image *) NULL)) | 
 |     return(MagickFalse); | 
 |   quantize_info=AcquireQuantizeInfo(image_info); | 
 |   status=RemapImage(quantize_info,picon,affinity_image,exception); | 
 |   quantize_info=DestroyQuantizeInfo(quantize_info); | 
 |   affinity_image=DestroyImage(affinity_image); | 
 |   transparent=MagickFalse; | 
 |   if (picon->storage_class == PseudoClass) | 
 |     { | 
 |       (void) CompressImageColormap(picon,exception); | 
 |       if (picon->alpha_trait == BlendPixelTrait) | 
 |         transparent=MagickTrue; | 
 |     } | 
 |   else | 
 |     { | 
 |       /* | 
 |         Convert DirectClass to PseudoClass picon. | 
 |       */ | 
 |       if (picon->alpha_trait == BlendPixelTrait) | 
 |         { | 
 |           /* | 
 |             Map all the transparent pixels. | 
 |           */ | 
 |           for (y=0; y < (ssize_t) picon->rows; y++) | 
 |           { | 
 |             q=GetAuthenticPixels(picon,0,y,picon->columns,1,exception); | 
 |             if (q == (Quantum *) NULL) | 
 |               break; | 
 |             for (x=0; x < (ssize_t) picon->columns; x++) | 
 |             { | 
 |               if (GetPixelAlpha(image,q) == (Quantum) TransparentAlpha) | 
 |                 transparent=MagickTrue; | 
 |               else | 
 |                 SetPixelAlpha(picon,OpaqueAlpha,q); | 
 |               q+=GetPixelChannels(picon); | 
 |             } | 
 |             if (SyncAuthenticPixels(picon,exception) == MagickFalse) | 
 |               break; | 
 |           } | 
 |         } | 
 |       (void) SetImageType(picon,PaletteType,exception); | 
 |     } | 
 |   colors=picon->colors; | 
 |   if (transparent != MagickFalse) | 
 |     { | 
 |       colors++; | 
 |       picon->colormap=(PixelInfo *) ResizeQuantumMemory((void **) | 
 |         picon->colormap,(size_t) colors,sizeof(*picon->colormap)); | 
 |       if (picon->colormap == (PixelInfo *) NULL) | 
 |         ThrowWriterException(ResourceLimitError,"MemoryAllocationError"); | 
 |       for (y=0; y < (ssize_t) picon->rows; y++) | 
 |       { | 
 |         q=GetAuthenticPixels(picon,0,y,picon->columns,1,exception); | 
 |         if (q == (Quantum *) NULL) | 
 |           break; | 
 |         for (x=0; x < (ssize_t) picon->columns; x++) | 
 |         { | 
 |           if (GetPixelAlpha(image,q) == (Quantum) TransparentAlpha) | 
 |             SetPixelIndex(picon,picon->colors,q); | 
 |           q+=GetPixelChannels(picon); | 
 |         } | 
 |         if (SyncAuthenticPixels(picon,exception) == MagickFalse) | 
 |           break; | 
 |       } | 
 |     } | 
 |   /* | 
 |     Compute the character per pixel. | 
 |   */ | 
 |   characters_per_pixel=1; | 
 |   for (k=MaxCixels; (ssize_t) colors > k; k*=MaxCixels) | 
 |     characters_per_pixel++; | 
 |   /* | 
 |     XPM header. | 
 |   */ | 
 |   (void) WriteBlobString(image,"/* XPM */\n"); | 
 |   GetPathComponent(picon->filename,BasePath,basename); | 
 |   (void) FormatLocaleString(buffer,MaxTextExtent, | 
 |     "static char *%s[] = {\n",basename); | 
 |   (void) WriteBlobString(image,buffer); | 
 |   (void) WriteBlobString(image,"/* columns rows colors chars-per-pixel */\n"); | 
 |   (void) FormatLocaleString(buffer,MaxTextExtent, | 
 |     "\"%.20g %.20g %.20g %.20g\",\n",(double) picon->columns,(double) | 
 |     picon->rows,(double) colors,(double) characters_per_pixel); | 
 |   (void) WriteBlobString(image,buffer); | 
 |   GetPixelInfo(image,&pixel); | 
 |   for (i=0; i < (ssize_t) colors; i++) | 
 |   { | 
 |     /* | 
 |       Define XPM color. | 
 |     */ | 
 |     pixel=picon->colormap[i]; | 
 |     pixel.colorspace=sRGBColorspace; | 
 |     pixel.depth=8; | 
 |     pixel.alpha=(double) OpaqueAlpha; | 
 |     (void) QueryColorname(image,&pixel,XPMCompliance,name,exception); | 
 |     if (transparent != MagickFalse) | 
 |       { | 
 |         if (i == (ssize_t) (colors-1)) | 
 |           (void) CopyMagickString(name,"grey75",MaxTextExtent); | 
 |       } | 
 |     /* | 
 |       Write XPM color. | 
 |     */ | 
 |     k=i % MaxCixels; | 
 |     symbol[0]=Cixel[k]; | 
 |     for (j=1; j < (ssize_t) characters_per_pixel; j++) | 
 |     { | 
 |       k=((i-k)/MaxCixels) % MaxCixels; | 
 |       symbol[j]=Cixel[k]; | 
 |     } | 
 |     symbol[j]='\0'; | 
 |     (void) FormatLocaleString(buffer,MaxTextExtent,"\"%s c %s\",\n", | 
 |        symbol,name); | 
 |     (void) WriteBlobString(image,buffer); | 
 |   } | 
 |   /* | 
 |     Define XPM pixels. | 
 |   */ | 
 |   (void) WriteBlobString(image,"/* pixels */\n"); | 
 |   for (y=0; y < (ssize_t) picon->rows; y++) | 
 |   { | 
 |     p=GetVirtualPixels(picon,0,y,picon->columns,1,exception); | 
 |     if (p == (const Quantum *) NULL) | 
 |       break; | 
 |     (void) WriteBlobString(image,"\""); | 
 |     for (x=0; x < (ssize_t) picon->columns; x++) | 
 |     { | 
 |       k=((ssize_t) GetPixelIndex(picon,p) % MaxCixels); | 
 |       symbol[0]=Cixel[k]; | 
 |       for (j=1; j < (ssize_t) characters_per_pixel; j++) | 
 |       { | 
 |         k=(((int) GetPixelIndex(picon,p)-k)/MaxCixels) % MaxCixels; | 
 |         symbol[j]=Cixel[k]; | 
 |       } | 
 |       symbol[j]='\0'; | 
 |       (void) CopyMagickString(buffer,symbol,MaxTextExtent); | 
 |       (void) WriteBlobString(image,buffer); | 
 |       p+=GetPixelChannels(image); | 
 |     } | 
 |     (void) FormatLocaleString(buffer,MaxTextExtent,"\"%s\n", | 
 |       y == (ssize_t) (picon->rows-1) ? "" : ","); | 
 |     (void) WriteBlobString(image,buffer); | 
 |     status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y, | 
 |       picon->rows); | 
 |     if (status == MagickFalse) | 
 |       break; | 
 |   } | 
 |   picon=DestroyImage(picon); | 
 |   (void) WriteBlobString(image,"};\n"); | 
 |   (void) CloseBlob(image); | 
 |   return(MagickTrue); | 
 | } | 
 |  | 
 | /* | 
 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | 
 | %                                                                             % | 
 | %                                                                             % | 
 | %                                                                             % | 
 | %   W r i t e X P M I m a g e                                                 % | 
 | %                                                                             % | 
 | %                                                                             % | 
 | %                                                                             % | 
 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | 
 | % | 
 | %  WriteXPMImage() writes an image to a file in the X pixmap format. | 
 | % | 
 | %  The format of the WriteXPMImage method is: | 
 | % | 
 | %      MagickBooleanType WriteXPMImage(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 WriteXPMImage(const ImageInfo *image_info,Image *image, | 
 |   ExceptionInfo *exception) | 
 | { | 
 | #define MaxCixels  92 | 
 |  | 
 |   static const char | 
 |     Cixel[MaxCixels+1] = " .XoO+@#$%&*=-;:>,<1234567890qwertyuipasdfghjk" | 
 |                          "lzxcvbnmMNBVCZASDFGHJKLPIUYTREWQ!~^/()_`'][{}|"; | 
 |  | 
 |   char | 
 |     buffer[MaxTextExtent], | 
 |     basename[MaxTextExtent], | 
 |     name[MaxTextExtent], | 
 |     symbol[MaxTextExtent]; | 
 |  | 
 |   MagickBooleanType | 
 |     status; | 
 |  | 
 |   PixelInfo | 
 |     pixel; | 
 |  | 
 |   register const Quantum | 
 |     *p; | 
 |  | 
 |   register ssize_t | 
 |     i, | 
 |     x; | 
 |  | 
 |   size_t | 
 |     characters_per_pixel; | 
 |  | 
 |   ssize_t | 
 |     j, | 
 |     k, | 
 |     opacity, | 
 |     y; | 
 |  | 
 |   /* | 
 |     Open output image file. | 
 |   */ | 
 |   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); | 
 |   if (IssRGBCompatibleColorspace(image->colorspace) == MagickFalse) | 
 |     (void) TransformImageColorspace(image,sRGBColorspace,exception); | 
 |   opacity=(-1); | 
 |   if (image->alpha_trait != BlendPixelTrait) | 
 |     { | 
 |       if ((image->storage_class == DirectClass) || (image->colors > 256)) | 
 |         (void) SetImageType(image,PaletteType,exception); | 
 |     } | 
 |   else | 
 |     { | 
 |       double | 
 |         alpha, | 
 |         beta; | 
 |  | 
 |       /* | 
 |         Identify transparent colormap index. | 
 |       */ | 
 |       if ((image->storage_class == DirectClass) || (image->colors > 256)) | 
 |         (void) SetImageType(image,PaletteBilevelMatteType,exception); | 
 |       for (i=0; i < (ssize_t) image->colors; i++) | 
 |         if (image->colormap[i].alpha != OpaqueAlpha) | 
 |           { | 
 |             if (opacity < 0) | 
 |               { | 
 |                 opacity=i; | 
 |                 continue; | 
 |               } | 
 |             alpha=(double) TransparentAlpha-(double) | 
 |               image->colormap[i].alpha; | 
 |             beta=(double) TransparentAlpha-(double) | 
 |               image->colormap[opacity].alpha; | 
 |             if (alpha < beta) | 
 |               opacity=i; | 
 |           } | 
 |       if (opacity == -1) | 
 |         { | 
 |           (void) SetImageType(image,PaletteBilevelMatteType,exception); | 
 |           for (i=0; i < (ssize_t) image->colors; i++) | 
 |             if (image->colormap[i].alpha != OpaqueAlpha) | 
 |               { | 
 |                 if (opacity < 0) | 
 |                   { | 
 |                     opacity=i; | 
 |                     continue; | 
 |                   } | 
 |                 alpha=(Quantum) TransparentAlpha-(double) | 
 |                   image->colormap[i].alpha; | 
 |                 beta=(Quantum) TransparentAlpha-(double) | 
 |                   image->colormap[opacity].alpha; | 
 |                 if (alpha < beta) | 
 |                   opacity=i; | 
 |               } | 
 |         } | 
 |       if (opacity >= 0) | 
 |         { | 
 |           image->colormap[opacity].red=image->transparent_color.red; | 
 |           image->colormap[opacity].green=image->transparent_color.green; | 
 |           image->colormap[opacity].blue=image->transparent_color.blue; | 
 |         } | 
 |     } | 
 |   /* | 
 |     Compute the character per pixel. | 
 |   */ | 
 |   characters_per_pixel=1; | 
 |   for (k=MaxCixels; (ssize_t) image->colors > k; k*=MaxCixels) | 
 |     characters_per_pixel++; | 
 |   /* | 
 |     XPM header. | 
 |   */ | 
 |   (void) WriteBlobString(image,"/* XPM */\n"); | 
 |   GetPathComponent(image->filename,BasePath,basename); | 
 |   if (isalnum((int) ((unsigned char) *basename)) == 0) | 
 |     { | 
 |       (void) FormatLocaleString(buffer,MaxTextExtent,"xpm_%s",basename); | 
 |       (void) CopyMagickString(basename,buffer,MaxTextExtent); | 
 |     } | 
 |   if (isalpha((int) ((unsigned char) basename[0])) == 0) | 
 |     basename[0]='_'; | 
 |   for (i=1; basename[i] != '\0'; i++) | 
 |     if (isalnum((int) ((unsigned char) basename[i])) == 0) | 
 |       basename[i]='_'; | 
 |   (void) FormatLocaleString(buffer,MaxTextExtent, | 
 |     "static char *%s[] = {\n",basename); | 
 |   (void) WriteBlobString(image,buffer); | 
 |   (void) WriteBlobString(image,"/* columns rows colors chars-per-pixel */\n"); | 
 |   (void) FormatLocaleString(buffer,MaxTextExtent, | 
 |     "\"%.20g %.20g %.20g %.20g \",\n",(double) image->columns,(double) | 
 |     image->rows,(double) image->colors,(double) characters_per_pixel); | 
 |   (void) WriteBlobString(image,buffer); | 
 |   GetPixelInfo(image,&pixel); | 
 |   for (i=0; i < (ssize_t) image->colors; i++) | 
 |   { | 
 |     /* | 
 |       Define XPM color. | 
 |     */ | 
 |     pixel=image->colormap[i]; | 
 |     pixel.colorspace=sRGBColorspace; | 
 |     pixel.depth=8; | 
 |     pixel.alpha=(double) OpaqueAlpha; | 
 |     (void) QueryColorname(image,&pixel,XPMCompliance,name,exception); | 
 |     if (i == opacity) | 
 |       (void) CopyMagickString(name,"None",MaxTextExtent); | 
 |     /* | 
 |       Write XPM color. | 
 |     */ | 
 |     k=i % MaxCixels; | 
 |     symbol[0]=Cixel[k]; | 
 |     for (j=1; j < (ssize_t) characters_per_pixel; j++) | 
 |     { | 
 |       k=((i-k)/MaxCixels) % MaxCixels; | 
 |       symbol[j]=Cixel[k]; | 
 |     } | 
 |     symbol[j]='\0'; | 
 |     (void) FormatLocaleString(buffer,MaxTextExtent,"\"%s c %s\",\n",symbol, | 
 |       name); | 
 |     (void) WriteBlobString(image,buffer); | 
 |   } | 
 |   /* | 
 |     Define XPM pixels. | 
 |   */ | 
 |   (void) WriteBlobString(image,"/* pixels */\n"); | 
 |   for (y=0; y < (ssize_t) image->rows; y++) | 
 |   { | 
 |     p=GetVirtualPixels(image,0,y,image->columns,1,exception); | 
 |     if (p == (const Quantum *) NULL) | 
 |       break; | 
 |     (void) WriteBlobString(image,"\""); | 
 |     for (x=0; x < (ssize_t) image->columns; x++) | 
 |     { | 
 |       k=((ssize_t) GetPixelIndex(image,p) % MaxCixels); | 
 |       symbol[0]=Cixel[k]; | 
 |       for (j=1; j < (ssize_t) characters_per_pixel; j++) | 
 |       { | 
 |         k=(((int) GetPixelIndex(image,p)-k)/MaxCixels) % MaxCixels; | 
 |         symbol[j]=Cixel[k]; | 
 |       } | 
 |       symbol[j]='\0'; | 
 |       (void) CopyMagickString(buffer,symbol,MaxTextExtent); | 
 |       (void) WriteBlobString(image,buffer); | 
 |       p+=GetPixelChannels(image); | 
 |     } | 
 |     (void) FormatLocaleString(buffer,MaxTextExtent,"\"%s\n", | 
 |       (y == (ssize_t) (image->rows-1) ? "" : ",")); | 
 |     (void) WriteBlobString(image,buffer); | 
 |     if (image->previous == (Image *) NULL) | 
 |       { | 
 |         status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y, | 
 |           image->rows); | 
 |         if (status == MagickFalse) | 
 |           break; | 
 |       } | 
 |   } | 
 |   (void) WriteBlobString(image,"};\n"); | 
 |   (void) CloseBlob(image); | 
 |   return(MagickTrue); | 
 | } |