2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13 % Read/Write X Windows system Pixmap Format %
20 % Copyright 1999-2019 ImageMagick Studio LLC, a non-profit organization %
21 % dedicated to making software imaging solutions freely available. %
23 % You may not use this file except in compliance with the License. You may %
24 % obtain a copy of the License at %
26 % https://imagemagick.org/script/license.php %
28 % Unless required by applicable law or agreed to in writing, software %
29 % distributed under the License is distributed on an "AS IS" BASIS, %
30 % WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %
31 % See the License for the specific language governing permissions and %
32 % limitations under the License. %
34 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
42 #include "MagickCore/studio.h"
43 #include "MagickCore/attribute.h"
44 #include "MagickCore/blob.h"
45 #include "MagickCore/blob-private.h"
46 #include "MagickCore/cache.h"
47 #include "MagickCore/color.h"
48 #include "MagickCore/color-private.h"
49 #include "MagickCore/colormap.h"
50 #include "MagickCore/colorspace.h"
51 #include "MagickCore/colorspace-private.h"
52 #include "MagickCore/exception.h"
53 #include "MagickCore/exception-private.h"
54 #include "MagickCore/geometry.h"
55 #include "MagickCore/image.h"
56 #include "MagickCore/image-private.h"
57 #include "MagickCore/list.h"
58 #include "MagickCore/magick.h"
59 #include "MagickCore/memory_.h"
60 #include "MagickCore/monitor.h"
61 #include "MagickCore/monitor-private.h"
62 #include "MagickCore/pixel-accessor.h"
63 #include "MagickCore/quantize.h"
64 #include "MagickCore/quantum-private.h"
65 #include "MagickCore/resize.h"
66 #include "MagickCore/resource_.h"
67 #include "MagickCore/splay-tree.h"
68 #include "MagickCore/static.h"
69 #include "MagickCore/string_.h"
70 #include "MagickCore/module.h"
71 #include "MagickCore/threshold.h"
72 #include "MagickCore/utility.h"
78 *xpm_symbolic = (SplayTreeInfo *) NULL;
83 static MagickBooleanType
84 WritePICONImage(const ImageInfo *,Image *,ExceptionInfo *),
85 WriteXPMImage(const ImageInfo *,Image *,ExceptionInfo *);
88 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
96 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
98 % IsXPM() returns MagickTrue if the image format type, identified by the
99 % magick string, is XPM.
101 % The format of the IsXPM method is:
103 % MagickBooleanType IsXPM(const unsigned char *magick,const size_t length)
105 % A description of each parameter follows:
107 % o magick: compare image format pattern against these bytes. or
110 % o length: Specifies the length of the magick string.
113 static MagickBooleanType IsXPM(const unsigned char *magick,const size_t length)
117 if (LocaleNCompare((char *) magick+1,"* XPM *",7) == 0)
123 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
127 % R e a d X P M I m a g e %
131 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
133 % ReadXPMImage() reads an X11 pixmap image file and returns it. It
134 % allocates the memory necessary for the new Image structure and returns a
135 % pointer to the new image.
137 % The format of the ReadXPMImage method is:
139 % Image *ReadXPMImage(const ImageInfo *image_info,ExceptionInfo *exception)
141 % A description of each parameter follows:
143 % o image_info: the image info.
145 % o exception: return any errors or warnings in this structure.
149 static int CompareXPMColor(const void *target,const void *source)
155 p=(const char *) target;
156 q=(const char *) source;
160 static ssize_t CopyXPMColor(char *destination,const char *source,size_t length)
166 while (length-- && (*p != '\0'))
170 *destination++=(*p++);
174 return((ssize_t) (p-source));
177 static char *NextXPMLine(char *p)
179 assert(p != (char *) NULL);
181 if (p != (char *) NULL)
186 static char *ParseXPMColor(char *,MagickBooleanType)
187 magick_attribute((__pure__));
189 static char *ParseXPMColor(char *color,MagickBooleanType search_start)
191 #define NumberTargets 6
204 *const targets[NumberTargets] = { "c ", "g ", "g4 ", "m ", "b ", "s " };
206 if (search_start != MagickFalse)
208 for (i=0; i < NumberTargets; i++)
211 for (q=targets[i]; *p != '\0'; p++)
217 if (isspace((int) ((unsigned char) (*(p-1)))) == 0)
230 return((char *) NULL);
232 for (p=color+1; *p != '\0'; p++)
236 if (isspace((int) ((unsigned char) (*(p-1)))) == 0)
238 if (isspace((int) ((unsigned char) (*p))) != 0)
240 for (i=0; i < NumberTargets; i++)
242 if ((*p == *targets[i]) && (*(p+1) == *(targets[i]+1)))
249 static Image *ReadXPMImage(const ImageInfo *image_info,ExceptionInfo *exception)
253 key[MagickPathExtent],
254 target[MagickPathExtent],
295 assert(image_info != (const ImageInfo *) NULL);
296 assert(image_info->signature == MagickCoreSignature);
297 if (image_info->debug != MagickFalse)
298 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
299 image_info->filename);
300 assert(exception != (ExceptionInfo *) NULL);
301 assert(exception->signature == MagickCoreSignature);
302 image=AcquireImage(image_info,exception);
303 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
304 if (status == MagickFalse)
306 image=DestroyImageList(image);
307 return((Image *) NULL);
312 length=MagickPathExtent;
313 xpm_buffer=(char *) AcquireQuantumMemory((size_t) length,sizeof(*xpm_buffer));
314 if (xpm_buffer == (char *) NULL)
315 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
318 while (ReadBlobString(image,p) != (char *) NULL)
320 if ((*p == '#') && ((p == xpm_buffer) || (*(p-1) == '\n')))
322 if ((*p == '}') && (*(p+1) == ';'))
325 if ((size_t) (p-xpm_buffer+MagickPathExtent) < length)
328 xpm_buffer=(char *) ResizeQuantumMemory(xpm_buffer,length+MagickPathExtent,
329 sizeof(*xpm_buffer));
330 if (xpm_buffer == (char *) NULL)
332 p=xpm_buffer+strlen(xpm_buffer);
334 if (xpm_buffer == (char *) NULL)
335 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
341 for (p=xpm_buffer; *p != '\0'; p++)
345 count=(ssize_t) sscanf(p+1,"%lu %lu %lu %lu",&columns,&rows,&colors,&width);
346 image->columns=columns;
348 image->colors=colors;
352 if ((count != 4) || (width == 0) || (width > 3) ||
353 (image->columns == 0) || (image->rows == 0) ||
354 (image->colors == 0) || (image->colors > MaxColormapSize))
356 xpm_buffer=DestroyString(xpm_buffer);
357 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
360 Remove unquoted characters.
363 for (q=xpm_buffer; *p != '\0'; )
367 if (active != MagickFalse)
369 active=active != MagickFalse ? MagickFalse : MagickTrue;
371 if (active != MagickFalse)
375 if (active != MagickFalse)
377 xpm_buffer=DestroyString(xpm_buffer);
378 ThrowReaderException(CorruptImageError,"UnexpectedEndOfFile");
381 Initialize image structure.
383 xpm_colors=NewSplayTree(CompareXPMColor,RelinquishMagickMemory,
384 (void *(*)(void *)) NULL);
385 if (AcquireImageColormap(image,image->colors,exception) == MagickFalse)
387 xpm_colors=DestroySplayTree(xpm_colors);
388 xpm_buffer=DestroyString(xpm_buffer);
389 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
395 next=NextXPMLine(xpm_buffer);
396 for (j=0; (j < (ssize_t) image->colors) && (next != (char *) NULL); j++)
399 symbolic[MagickPathExtent];
403 if (next == (char *) NULL)
405 length=MagickMin((size_t) width,MagickPathExtent-1);
406 if (CopyXPMColor(key,p,length) != (ssize_t) length)
408 status=AddValueToSplayTree(xpm_colors,ConstantString(key),(void *) j);
412 (void) CopyMagickString(target,"gray",MagickPathExtent);
414 if (strlen(p) > width)
415 q=ParseXPMColor(p+width,MagickTrue);
417 if (q != (char *) NULL)
419 while ((isspace((int) ((unsigned char) *q)) == 0) && (*q != '\0'))
423 (void) CopyXPMColor(target,q,MagickMin((size_t) (next-q),
424 MagickPathExtent-1));
425 q=ParseXPMColor(target,MagickFalse);
426 (void) CopyXPMColor(symbolic,q,MagickMin((size_t) (next-q),
427 MagickPathExtent-1));
428 if (q != (char *) NULL)
432 if (*symbolic != '\0')
433 (void) AddValueToSplayTree(xpm_symbolic,ConstantString(target),
434 ConstantString(symbolic));
435 grey=strstr(target,"grey");
436 if (grey != (char *) NULL)
438 if (LocaleCompare(target,"none") == 0)
440 image->storage_class=DirectClass;
441 image->alpha_trait=BlendPixelTrait;
443 status=QueryColorCompliance(target,XPMCompliance,&image->colormap[j],
445 if (status == MagickFalse)
447 if (image->depth < image->colormap[j].depth)
448 image->depth=image->colormap[j].depth;
450 if (j < (ssize_t) image->colors)
452 xpm_colors=DestroySplayTree(xpm_colors);
453 xpm_buffer=DestroyString(xpm_buffer);
454 ThrowReaderException(CorruptImageError,"CorruptImage");
457 if (image_info->ping == MagickFalse)
462 status=SetImageExtent(image,image->columns,image->rows,exception);
463 if (status == MagickFalse)
465 xpm_colors=DestroySplayTree(xpm_colors);
466 xpm_buffer=DestroyString(xpm_buffer);
467 return(DestroyImageList(image));
469 for (y=0; y < (ssize_t) image->rows; y++)
472 if (p == (char *) NULL)
474 r=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
475 if (r == (Quantum *) NULL)
477 for (x=0; x < (ssize_t) image->columns; x++)
482 count=CopyXPMColor(key,p,MagickMin(width,MagickPathExtent-1));
483 if (count != (ssize_t) width)
485 j=(ssize_t) GetValueFromSplayTree(xpm_colors,key);
486 if (image->storage_class == PseudoClass)
487 SetPixelIndex(image,(Quantum) j,r);
488 SetPixelViaPixelInfo(image,image->colormap+j,r);
490 r+=GetPixelChannels(image);
492 if (x < (ssize_t) image->columns)
494 if (SyncAuthenticPixels(image,exception) == MagickFalse)
497 if (y < (ssize_t) image->rows)
499 xpm_colors=DestroySplayTree(xpm_colors);
500 xpm_buffer=DestroyString(xpm_buffer);
501 ThrowReaderException(CorruptImageError,"NotEnoughPixelData");
505 Relinquish resources.
507 xpm_buffer=DestroyString(xpm_buffer);
508 xpm_colors=DestroySplayTree(xpm_colors);
509 (void) CloseBlob(image);
510 return(GetFirstImageInList(image));
514 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
518 % R e g i s t e r X P M I m a g e %
522 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
524 % RegisterXPMImage() adds attributes for the XPM image format to
525 % the list of supported formats. The attributes include the image format
526 % tag, a method to read and/or write the format, whether the format
527 % supports the saving of more than one frame to the same file or blob,
528 % whether the format supports native in-memory I/O, and a brief
529 % description of the format.
531 % The format of the RegisterXPMImage method is:
533 % size_t RegisterXPMImage(void)
536 ModuleExport size_t RegisterXPMImage(void)
541 if (xpm_symbolic == (SplayTreeInfo *) NULL)
542 xpm_symbolic=NewSplayTree(CompareSplayTreeString,RelinquishMagickMemory,
543 RelinquishMagickMemory);
544 entry=AcquireMagickInfo("XPM","PICON","Personal Icon");
545 entry->decoder=(DecodeImageHandler *) ReadXPMImage;
546 entry->encoder=(EncodeImageHandler *) WritePICONImage;
547 entry->flags^=CoderAdjoinFlag;
548 (void) RegisterMagickInfo(entry);
549 entry=AcquireMagickInfo("XPM","PM","X Windows system pixmap (color)");
550 entry->decoder=(DecodeImageHandler *) ReadXPMImage;
551 entry->encoder=(EncodeImageHandler *) WriteXPMImage;
552 entry->flags^=CoderAdjoinFlag;
553 entry->flags|=CoderStealthFlag;
554 (void) RegisterMagickInfo(entry);
555 entry=AcquireMagickInfo("XPM","XPM","X Windows system pixmap (color)");
556 entry->decoder=(DecodeImageHandler *) ReadXPMImage;
557 entry->encoder=(EncodeImageHandler *) WriteXPMImage;
558 entry->magick=(IsImageFormatHandler *) IsXPM;
559 entry->flags^=CoderAdjoinFlag;
560 (void) RegisterMagickInfo(entry);
561 return(MagickImageCoderSignature);
565 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
569 % U n r e g i s t e r X P M I m a g e %
573 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
575 % UnregisterXPMImage() removes format registrations made by the
576 % XPM module from the list of supported formats.
578 % The format of the UnregisterXPMImage method is:
580 % UnregisterXPMImage(void)
583 ModuleExport void UnregisterXPMImage(void)
585 (void) UnregisterMagickInfo("PICON");
586 (void) UnregisterMagickInfo("PM");
587 (void) UnregisterMagickInfo("XPM");
588 if (xpm_symbolic != (SplayTreeInfo *) NULL)
589 xpm_symbolic=DestroySplayTree(xpm_symbolic);
593 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
597 % W r i t e P I C O N I m a g e %
601 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
603 % WritePICONImage() writes an image to a file in the Personal Icon format.
605 % The format of the WritePICONImage method is:
607 % MagickBooleanType WritePICONImage(const ImageInfo *image_info,
608 % Image *image,ExceptionInfo *exception)
610 % A description of each parameter follows.
612 % o image_info: the image info.
614 % o image: The image.
616 % o exception: return any errors or warnings in this structure.
619 static MagickBooleanType WritePICONImage(const ImageInfo *image_info,
620 Image *image,ExceptionInfo *exception)
622 #define ColormapExtent 155
623 #define GraymapExtent 95
624 #define PiconGeometry "48x48>"
629 0x47, 0x49, 0x46, 0x38, 0x37, 0x61, 0x06, 0x00, 0x05, 0x00, 0xf4, 0x05,
630 0x00, 0x00, 0x00, 0x00, 0x2f, 0x4f, 0x4f, 0x70, 0x80, 0x90, 0x7e, 0x7e,
631 0x7e, 0xdc, 0xdc, 0xdc, 0xff, 0xff, 0xff, 0x00, 0x00, 0x80, 0x00, 0x00,
632 0xff, 0x1e, 0x90, 0xff, 0x87, 0xce, 0xeb, 0xe6, 0xe6, 0xfa, 0x00, 0xff,
633 0xff, 0x80, 0x00, 0x80, 0xb2, 0x22, 0x22, 0x2e, 0x8b, 0x57, 0x32, 0xcd,
634 0x32, 0x00, 0xff, 0x00, 0x98, 0xfb, 0x98, 0xff, 0x00, 0xff, 0xff, 0x00,
635 0x00, 0xff, 0x63, 0x47, 0xff, 0xa5, 0x00, 0xff, 0xd7, 0x00, 0xff, 0xff,
636 0x00, 0xee, 0x82, 0xee, 0xa0, 0x52, 0x2d, 0xcd, 0x85, 0x3f, 0xd2, 0xb4,
637 0x8c, 0xf5, 0xde, 0xb3, 0xff, 0xfa, 0xcd, 0x00, 0x00, 0x00, 0x00, 0x00,
638 0x00, 0x21, 0xf9, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00,
639 0x00, 0x00, 0x06, 0x00, 0x05, 0x00, 0x00, 0x05, 0x18, 0x20, 0x10, 0x08,
640 0x03, 0x51, 0x18, 0x07, 0x92, 0x28, 0x0b, 0xd3, 0x38, 0x0f, 0x14, 0x49,
641 0x13, 0x55, 0x59, 0x17, 0x96, 0x69, 0x1b, 0xd7, 0x85, 0x00, 0x3b,
645 0x47, 0x49, 0x46, 0x38, 0x37, 0x61, 0x04, 0x00, 0x04, 0x00, 0xf3, 0x0f,
646 0x00, 0x00, 0x00, 0x00, 0x12, 0x12, 0x12, 0x21, 0x21, 0x21, 0x33, 0x33,
647 0x33, 0x45, 0x45, 0x45, 0x54, 0x54, 0x54, 0x66, 0x66, 0x66, 0x78, 0x78,
648 0x78, 0x87, 0x87, 0x87, 0x99, 0x99, 0x99, 0xab, 0xab, 0xab, 0xba, 0xba,
649 0xba, 0xcc, 0xcc, 0xcc, 0xde, 0xde, 0xde, 0xed, 0xed, 0xed, 0xff, 0xff,
650 0xff, 0x21, 0xf9, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00,
651 0x00, 0x00, 0x04, 0x00, 0x04, 0x00, 0x00, 0x04, 0x0c, 0x10, 0x04, 0x31,
652 0x48, 0x31, 0x07, 0x25, 0xb5, 0x58, 0x73, 0x4f, 0x04, 0x00, 0x3b,
658 Cixel[MaxCixels+1] = " .XoO+@#$%&*=-;:>,<1234567890qwertyuipasdfghjk"
659 "lzxcvbnmMNBVCZASDFGHJKLPIUYTREWQ!~^/()_`'][{}|";
662 buffer[MagickPathExtent],
663 basename[MagickPathExtent],
664 name[MagickPathExtent],
665 symbol[MagickPathExtent];
687 register const Quantum
698 characters_per_pixel,
707 Open output image file.
709 assert(image_info != (const ImageInfo *) NULL);
710 assert(image_info->signature == MagickCoreSignature);
711 assert(image != (Image *) NULL);
712 assert(image->signature == MagickCoreSignature);
713 if (image->debug != MagickFalse)
714 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
715 assert(exception != (ExceptionInfo *) NULL);
716 assert(exception->signature == MagickCoreSignature);
717 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
718 if (status == MagickFalse)
720 (void) TransformImageColorspace(image,sRGBColorspace,exception);
721 SetGeometry(image,&geometry);
722 (void) ParseMetaGeometry(PiconGeometry,&geometry.x,&geometry.y,
723 &geometry.width,&geometry.height);
724 picon=ResizeImage(image,geometry.width,geometry.height,TriangleFilter,
726 blob_info=CloneImageInfo(image_info);
727 (void) AcquireUniqueFilename(blob_info->filename);
728 if ((image_info->type != TrueColorType) &&
729 (SetImageGray(image,exception) != MagickFalse))
730 affinity_image=BlobToImage(blob_info,Graymap,GraymapExtent,exception);
732 affinity_image=BlobToImage(blob_info,Colormap,ColormapExtent,exception);
733 (void) RelinquishUniqueFileResource(blob_info->filename);
734 blob_info=DestroyImageInfo(blob_info);
735 if ((picon == (Image *) NULL) || (affinity_image == (Image *) NULL))
737 if (affinity_image != (Image *) NULL)
738 affinity_image=DestroyImage(affinity_image);
739 if (picon != (Image *) NULL)
740 picon=DestroyImage(picon);
743 quantize_info=AcquireQuantizeInfo(image_info);
744 status=RemapImage(quantize_info,picon,affinity_image,exception);
745 quantize_info=DestroyQuantizeInfo(quantize_info);
746 affinity_image=DestroyImage(affinity_image);
747 transparent=MagickFalse;
748 if (picon->storage_class == PseudoClass)
750 (void) CompressImageColormap(picon,exception);
751 if (picon->alpha_trait != UndefinedPixelTrait)
752 transparent=MagickTrue;
757 Convert DirectClass to PseudoClass picon.
759 if (picon->alpha_trait != UndefinedPixelTrait)
762 Map all the transparent pixels.
764 for (y=0; y < (ssize_t) picon->rows; y++)
766 q=GetAuthenticPixels(picon,0,y,picon->columns,1,exception);
767 if (q == (Quantum *) NULL)
769 for (x=0; x < (ssize_t) picon->columns; x++)
771 if (GetPixelAlpha(image,q) == (Quantum) TransparentAlpha)
772 transparent=MagickTrue;
774 SetPixelAlpha(picon,OpaqueAlpha,q);
775 q+=GetPixelChannels(picon);
777 if (SyncAuthenticPixels(picon,exception) == MagickFalse)
781 (void) SetImageType(picon,PaletteType,exception);
783 colors=picon->colors;
784 if (transparent != MagickFalse)
787 picon->colormap=(PixelInfo *) ResizeQuantumMemory((void **)
788 picon->colormap,(size_t) colors,sizeof(*picon->colormap));
789 if (picon->colormap == (PixelInfo *) NULL)
790 ThrowWriterException(ResourceLimitError,"MemoryAllocationError");
791 picon->colormap[colors-1].red=0.0;
792 picon->colormap[colors-1].green=0.0;
793 picon->colormap[colors-1].blue=0.0;
794 picon->colormap[colors-1].alpha=TransparentAlpha;
795 for (y=0; y < (ssize_t) picon->rows; y++)
797 q=GetAuthenticPixels(picon,0,y,picon->columns,1,exception);
798 if (q == (Quantum *) NULL)
800 for (x=0; x < (ssize_t) picon->columns; x++)
802 if (GetPixelAlpha(image,q) == (Quantum) TransparentAlpha)
803 SetPixelIndex(picon,(Quantum) picon->colors,q);
804 q+=GetPixelChannels(picon);
806 if (SyncAuthenticPixels(picon,exception) == MagickFalse)
811 Compute the character per pixel.
813 characters_per_pixel=1;
814 for (k=MaxCixels; (ssize_t) colors > k; k*=MaxCixels)
815 characters_per_pixel++;
819 (void) WriteBlobString(image,"/* XPM */\n");
820 GetPathComponent(picon->filename,BasePath,basename);
821 (void) FormatLocaleString(buffer,MagickPathExtent,
822 "static char *%.1024s[] = {\n",basename);
823 (void) WriteBlobString(image,buffer);
824 (void) WriteBlobString(image,"/* columns rows colors chars-per-pixel */\n");
825 (void) FormatLocaleString(buffer,MagickPathExtent,
826 "\"%.20g %.20g %.20g %.20g\",\n",(double) picon->columns,(double)
827 picon->rows,(double) colors,(double) characters_per_pixel);
828 (void) WriteBlobString(image,buffer);
829 GetPixelInfo(image,&pixel);
830 for (i=0; i < (ssize_t) colors; i++)
835 pixel=picon->colormap[i];
836 pixel.colorspace=sRGBColorspace;
838 pixel.alpha=(double) OpaqueAlpha;
839 (void) QueryColorname(image,&pixel,XPMCompliance,name,exception);
840 if (transparent != MagickFalse)
842 if (i == (ssize_t) (colors-1))
843 (void) CopyMagickString(name,"grey75",MagickPathExtent);
850 for (j=1; j < (ssize_t) characters_per_pixel; j++)
852 k=((i-k)/MaxCixels) % MaxCixels;
856 (void) FormatLocaleString(buffer,MagickPathExtent,
857 "\"%.1024s c %.1024s\",\n",symbol,name);
858 (void) WriteBlobString(image,buffer);
863 (void) WriteBlobString(image,"/* pixels */\n");
864 for (y=0; y < (ssize_t) picon->rows; y++)
866 p=GetVirtualPixels(picon,0,y,picon->columns,1,exception);
867 if (p == (const Quantum *) NULL)
869 (void) WriteBlobString(image,"\"");
870 for (x=0; x < (ssize_t) picon->columns; x++)
872 k=((ssize_t) GetPixelIndex(picon,p) % MaxCixels);
874 for (j=1; j < (ssize_t) characters_per_pixel; j++)
876 k=(((int) GetPixelIndex(picon,p)-k)/MaxCixels) % MaxCixels;
880 (void) CopyMagickString(buffer,symbol,MagickPathExtent);
881 (void) WriteBlobString(image,buffer);
882 p+=GetPixelChannels(picon);
884 (void) FormatLocaleString(buffer,MagickPathExtent,"\"%.1024s\n",
885 y == (ssize_t) (picon->rows-1) ? "" : ",");
886 (void) WriteBlobString(image,buffer);
887 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
889 if (status == MagickFalse)
892 picon=DestroyImage(picon);
893 (void) WriteBlobString(image,"};\n");
894 (void) CloseBlob(image);
899 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
903 % W r i t e X P M I m a g e %
907 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
909 % WriteXPMImage() writes an image to a file in the X pixmap format.
911 % The format of the WriteXPMImage method is:
913 % MagickBooleanType WriteXPMImage(const ImageInfo *image_info,
914 % Image *image,ExceptionInfo *exception)
916 % A description of each parameter follows.
918 % o image_info: the image info.
920 % o image: The image.
922 % o exception: return any errors or warnings in this structure.
925 static MagickBooleanType WriteXPMImage(const ImageInfo *image_info,Image *image,
926 ExceptionInfo *exception)
931 Cixel[MaxCixels+1] = " .XoO+@#$%&*=-;:>,<1234567890qwertyuipasdfghjk"
932 "lzxcvbnmMNBVCZASDFGHJKLPIUYTREWQ!~^/()_`'][{}|";
935 buffer[MagickPathExtent],
936 basename[MagickPathExtent],
937 name[MagickPathExtent],
938 symbol[MagickPathExtent];
946 register const Quantum
954 characters_per_pixel;
963 Open output image file.
965 assert(image_info != (const ImageInfo *) NULL);
966 assert(image_info->signature == MagickCoreSignature);
967 assert(image != (Image *) NULL);
968 assert(image->signature == MagickCoreSignature);
969 if (image->debug != MagickFalse)
970 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
971 assert(exception != (ExceptionInfo *) NULL);
972 assert(exception->signature == MagickCoreSignature);
973 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
974 if (status == MagickFalse)
976 if (IssRGBCompatibleColorspace(image->colorspace) == MagickFalse)
977 (void) TransformImageColorspace(image,sRGBColorspace,exception);
979 if (image->alpha_trait == UndefinedPixelTrait)
981 if ((image->storage_class == DirectClass) || (image->colors > 256))
982 (void) SetImageType(image,PaletteType,exception);
991 Identify transparent colormap index.
993 if ((image->storage_class == DirectClass) || (image->colors > 256))
994 (void) SetImageType(image,PaletteBilevelAlphaType,exception);
995 for (i=0; i < (ssize_t) image->colors; i++)
996 if (image->colormap[i].alpha != OpaqueAlpha)
1003 alpha=(double) TransparentAlpha-(double)
1004 image->colormap[i].alpha;
1005 beta=(double) TransparentAlpha-(double)
1006 image->colormap[opacity].alpha;
1012 (void) SetImageType(image,PaletteBilevelAlphaType,exception);
1013 for (i=0; i < (ssize_t) image->colors; i++)
1014 if (image->colormap[i].alpha != OpaqueAlpha)
1021 alpha=(Quantum) TransparentAlpha-(double)
1022 image->colormap[i].alpha;
1023 beta=(Quantum) TransparentAlpha-(double)
1024 image->colormap[opacity].alpha;
1031 image->colormap[opacity].red=image->transparent_color.red;
1032 image->colormap[opacity].green=image->transparent_color.green;
1033 image->colormap[opacity].blue=image->transparent_color.blue;
1037 Compute the character per pixel.
1039 characters_per_pixel=1;
1040 for (k=MaxCixels; (ssize_t) image->colors > k; k*=MaxCixels)
1041 characters_per_pixel++;
1045 (void) WriteBlobString(image,"/* XPM */\n");
1046 GetPathComponent(image->filename,BasePath,basename);
1047 if (isalnum((int) ((unsigned char) *basename)) == 0)
1049 (void) FormatLocaleString(buffer,MagickPathExtent,"xpm_%.1024s",basename);
1050 (void) CopyMagickString(basename,buffer,MagickPathExtent);
1052 if (isalpha((int) ((unsigned char) basename[0])) == 0)
1054 for (i=1; basename[i] != '\0'; i++)
1055 if (isalnum((int) ((unsigned char) basename[i])) == 0)
1057 (void) FormatLocaleString(buffer,MagickPathExtent,
1058 "static char *%.1024s[] = {\n",basename);
1059 (void) WriteBlobString(image,buffer);
1060 (void) WriteBlobString(image,"/* columns rows colors chars-per-pixel */\n");
1061 (void) FormatLocaleString(buffer,MagickPathExtent,
1062 "\"%.20g %.20g %.20g %.20g \",\n",(double) image->columns,(double)
1063 image->rows,(double) image->colors,(double) characters_per_pixel);
1064 (void) WriteBlobString(image,buffer);
1065 GetPixelInfo(image,&pixel);
1066 for (i=0; i < (ssize_t) image->colors; i++)
1074 pixel=image->colormap[i];
1075 pixel.colorspace=sRGBColorspace;
1077 pixel.alpha=(double) OpaqueAlpha;
1078 (void) QueryColorname(image,&pixel,XPMCompliance,name,exception);
1080 (void) CopyMagickString(name,"None",MagickPathExtent);
1086 for (j=1; j < (ssize_t) characters_per_pixel; j++)
1088 k=((i-k)/MaxCixels) % MaxCixels;
1092 symbolic=GetValueFromSplayTree(xpm_symbolic,name);
1093 if (symbolic == (const char *) NULL)
1094 (void) FormatLocaleString(buffer,MagickPathExtent,
1095 "\"%.1024s c %.1024s\",\n",symbol,name);
1097 (void) FormatLocaleString(buffer,MagickPathExtent,
1098 "\"%.1024s c %.1024s %.1024s\",\n",symbol,name,symbolic);
1099 (void) WriteBlobString(image,buffer);
1104 (void) WriteBlobString(image,"/* pixels */\n");
1105 for (y=0; y < (ssize_t) image->rows; y++)
1107 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
1108 if (p == (const Quantum *) NULL)
1110 (void) WriteBlobString(image,"\"");
1111 for (x=0; x < (ssize_t) image->columns; x++)
1113 k=((ssize_t) GetPixelIndex(image,p) % MaxCixels);
1115 for (j=1; j < (ssize_t) characters_per_pixel; j++)
1117 k=(((int) GetPixelIndex(image,p)-k)/MaxCixels) % MaxCixels;
1121 (void) CopyMagickString(buffer,symbol,MagickPathExtent);
1122 (void) WriteBlobString(image,buffer);
1123 p+=GetPixelChannels(image);
1125 (void) FormatLocaleString(buffer,MagickPathExtent,"\"%.1024s\n",
1126 (y == (ssize_t) (image->rows-1) ? "" : ","));
1127 (void) WriteBlobString(image,buffer);
1128 if (image->previous == (Image *) NULL)
1130 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
1132 if (status == MagickFalse)
1136 (void) WriteBlobString(image,"};\n");
1137 (void) CloseBlob(image);