2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13 % Read/Write X Windows system Pixmap Format %
20 % Copyright 1999-2016 ImageMagick Studio LLC, a non-profit organization %
21 % dedicated to making software imaging solutions freely available. %
23 % You may not use this file except in compliance with the License. You may %
24 % obtain a copy of the License at %
26 % http://www.imagemagick.org/script/license.php %
28 % Unless required by applicable law or agreed to in writing, software %
29 % distributed under the License is distributed on an "AS IS" BASIS, %
30 % WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %
31 % See the License for the specific language governing permissions and %
32 % limitations under the License. %
34 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
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"
77 static MagickBooleanType
78 WritePICONImage(const ImageInfo *,Image *,ExceptionInfo *),
79 WriteXPMImage(const ImageInfo *,Image *,ExceptionInfo *);
82 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
90 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
92 % IsXPM() returns MagickTrue if the image format type, identified by the
93 % magick string, is XPM.
95 % The format of the IsXPM method is:
97 % MagickBooleanType IsXPM(const unsigned char *magick,const size_t length)
99 % A description of each parameter follows:
101 % o magick: compare image format pattern against these bytes. or
104 % o length: Specifies the length of the magick string.
107 static MagickBooleanType IsXPM(const unsigned char *magick,const size_t length)
111 if (LocaleNCompare((char *) magick+1,"* XPM *",7) == 0)
117 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
121 % R e a d X P M I m a g e %
125 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
127 % ReadXPMImage() reads an X11 pixmap image file and returns it. It
128 % allocates the memory necessary for the new Image structure and returns a
129 % pointer to the new image.
131 % The format of the ReadXPMImage method is:
133 % Image *ReadXPMImage(const ImageInfo *image_info,ExceptionInfo *exception)
135 % A description of each parameter follows:
137 % o image_info: the image info.
139 % o exception: return any errors or warnings in this structure.
143 static int CompareXPMColor(const void *target,const void *source)
149 p=(const char *) target;
150 q=(const char *) source;
154 static ssize_t CopyXPMColor(char *destination,const char *source,size_t length)
160 while (length-- && (*p != '\0'))
161 *destination++=(*p++);
164 return((ssize_t) (p-source));
167 static char *NextXPMLine(char *p)
169 assert(p != (char *) NULL);
171 if (p != (char *) NULL)
176 static char *ParseXPMColor(char *color,MagickBooleanType search_start)
178 #define NumberTargets 6
191 *const targets[NumberTargets] = { "c ", "g ", "g4 ", "m ", "b ", "s " };
193 if (search_start != MagickFalse)
195 for (i=0; i < NumberTargets; i++)
198 for (q=targets[i]; *p != '\0'; p++)
204 if (isspace((int) ((unsigned char) (*(p-1)))) == 0)
217 return((char *) NULL);
219 for (p=color+1; *p != '\0'; p++)
223 if (isspace((int) ((unsigned char) (*(p-1)))) == 0)
225 if (isspace((int) ((unsigned char) (*p))) != 0)
227 for (i=0; i < NumberTargets; i++)
229 if ((*p == *targets[i]) && (*(p+1) == *(targets[i]+1)))
236 static Image *ReadXPMImage(const ImageInfo *image_info,ExceptionInfo *exception)
240 key[MagickPathExtent],
241 target[MagickPathExtent],
282 assert(image_info != (const ImageInfo *) NULL);
283 assert(image_info->signature == MagickCoreSignature);
284 if (image_info->debug != MagickFalse)
285 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
286 image_info->filename);
287 assert(exception != (ExceptionInfo *) NULL);
288 assert(exception->signature == MagickCoreSignature);
289 image=AcquireImage(image_info,exception);
290 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
291 if (status == MagickFalse)
293 image=DestroyImageList(image);
294 return((Image *) NULL);
299 length=MagickPathExtent;
300 xpm_buffer=(char *) AcquireQuantumMemory((size_t) length,sizeof(*xpm_buffer));
301 if (xpm_buffer == (char *) NULL)
302 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
305 while (ReadBlobString(image,p) != (char *) NULL)
307 if ((*p == '#') && ((p == xpm_buffer) || (*(p-1) == '\n')))
309 if ((*p == '}') && (*(p+1) == ';'))
312 if ((size_t) (p-xpm_buffer+MagickPathExtent) < length)
315 xpm_buffer=(char *) ResizeQuantumMemory(xpm_buffer,length+MagickPathExtent,
316 sizeof(*xpm_buffer));
317 if (xpm_buffer == (char *) NULL)
319 p=xpm_buffer+strlen(xpm_buffer);
321 if (xpm_buffer == (char *) NULL)
322 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
328 for (p=xpm_buffer; *p != '\0'; p++)
332 count=(ssize_t) sscanf(p+1,"%lu %lu %lu %lu",&columns,&rows,&colors,&width);
333 image->columns=columns;
335 image->colors=colors;
339 if ((count != 4) || (width == 0) || (width > 10) || (image->columns == 0) ||
340 (image->rows == 0) || (image->colors == 0))
341 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
343 Remove unquoted characters.
351 if (active != MagickFalse)
353 active=active != MagickFalse ? MagickFalse : MagickTrue;
355 if (active != MagickFalse)
360 Initialize image structure.
362 xpm_colors=NewSplayTree(CompareXPMColor,RelinquishMagickMemory,
363 (void *(*)(void *)) NULL);
364 if (AcquireImageColormap(image,image->colors,exception) == MagickFalse)
366 xpm_buffer=DestroyString(xpm_buffer);
367 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
373 next=NextXPMLine(xpm_buffer);
374 for (j=0; (j < (ssize_t) image->colors) && (next != (char *) NULL); j++)
378 (void) CopyXPMColor(key,p,MagickMin((size_t) width,MagickPathExtent-1));
379 status=AddValueToSplayTree(xpm_colors,ConstantString(key),(void *) j);
383 (void) CopyMagickString(target,"gray",MagickPathExtent);
384 q=ParseXPMColor(p+width,MagickTrue);
385 if (q != (char *) NULL)
387 while ((isspace((int) ((unsigned char) *q)) == 0) && (*q != '\0'))
391 if (next != (char *) NULL)
392 (void) CopyXPMColor(target,q,MagickMin((size_t) (next-q),
393 MagickPathExtent-1));
395 (void) CopyMagickString(target,q,MagickPathExtent);
396 q=ParseXPMColor(target,MagickFalse);
397 if (q != (char *) NULL)
401 grey=strstr(target,"grey");
402 if (grey != (char *) NULL)
404 if (LocaleCompare(target,"none") == 0)
406 image->storage_class=DirectClass;
407 image->alpha_trait=BlendPixelTrait;
409 status=QueryColorCompliance(target,XPMCompliance,&image->colormap[j],
411 if (status == MagickFalse)
413 if (image->depth < image->colormap[j].depth)
414 image->depth=image->colormap[j].depth;
416 if (j < (ssize_t) image->colors)
418 xpm_colors=DestroySplayTree(xpm_colors);
419 xpm_buffer=DestroyString(xpm_buffer);
420 ThrowReaderException(CorruptImageError,"CorruptImage");
423 if (image_info->ping == MagickFalse)
428 status=SetImageExtent(image,image->columns,image->rows,exception);
429 if (status == MagickFalse)
430 return(DestroyImageList(image));
431 for (y=0; y < (ssize_t) image->rows; y++)
434 if (p == (char *) NULL)
436 r=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
437 if (r == (Quantum *) NULL)
439 for (x=0; x < (ssize_t) image->columns; x++)
441 ssize_t count=CopyXPMColor(key,p,MagickMin(width,MagickPathExtent-1));
442 if (count != (ssize_t) width)
444 j=(ssize_t) GetValueFromSplayTree(xpm_colors,key);
445 if (image->storage_class == PseudoClass)
446 SetPixelIndex(image,(Quantum) j,r);
447 SetPixelViaPixelInfo(image,image->colormap+j,r);
449 r+=GetPixelChannels(image);
451 if (x < (ssize_t) image->columns)
453 if (SyncAuthenticPixels(image,exception) == MagickFalse)
456 if (y < (ssize_t) image->rows)
458 xpm_colors=DestroySplayTree(xpm_colors);
459 xpm_buffer=DestroyString(xpm_buffer);
460 ThrowReaderException(CorruptImageError,"NotEnoughPixelData");
464 Relinquish resources.
466 xpm_buffer=DestroyString(xpm_buffer);
467 xpm_colors=DestroySplayTree(xpm_colors);
468 (void) CloseBlob(image);
469 return(GetFirstImageInList(image));
473 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
477 % R e g i s t e r X P M I m a g e %
481 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
483 % RegisterXPMImage() adds attributes for the XPM image format to
484 % the list of supported formats. The attributes include the image format
485 % tag, a method to read and/or write the format, whether the format
486 % supports the saving of more than one frame to the same file or blob,
487 % whether the format supports native in-memory I/O, and a brief
488 % description of the format.
490 % The format of the RegisterXPMImage method is:
492 % size_t RegisterXPMImage(void)
495 ModuleExport size_t RegisterXPMImage(void)
500 entry=AcquireMagickInfo("XPM","PICON","Personal Icon");
501 entry->decoder=(DecodeImageHandler *) ReadXPMImage;
502 entry->encoder=(EncodeImageHandler *) WritePICONImage;
503 entry->flags^=CoderAdjoinFlag;
504 (void) RegisterMagickInfo(entry);
505 entry=AcquireMagickInfo("XPM","PM","X Windows system pixmap (color)");
506 entry->decoder=(DecodeImageHandler *) ReadXPMImage;
507 entry->encoder=(EncodeImageHandler *) WriteXPMImage;
508 entry->flags^=CoderAdjoinFlag;
509 entry->flags|=CoderStealthFlag;
510 (void) RegisterMagickInfo(entry);
511 entry=AcquireMagickInfo("XPM","XPM","X Windows system pixmap (color)");
512 entry->decoder=(DecodeImageHandler *) ReadXPMImage;
513 entry->encoder=(EncodeImageHandler *) WriteXPMImage;
514 entry->magick=(IsImageFormatHandler *) IsXPM;
515 entry->flags^=CoderAdjoinFlag;
516 (void) RegisterMagickInfo(entry);
517 return(MagickImageCoderSignature);
521 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
525 % U n r e g i s t e r X P M I m a g e %
529 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
531 % UnregisterXPMImage() removes format registrations made by the
532 % XPM module from the list of supported formats.
534 % The format of the UnregisterXPMImage method is:
536 % UnregisterXPMImage(void)
539 ModuleExport void UnregisterXPMImage(void)
541 (void) UnregisterMagickInfo("PICON");
542 (void) UnregisterMagickInfo("PM");
543 (void) UnregisterMagickInfo("XPM");
547 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
551 % W r i t e P I C O N I m a g e %
555 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
557 % WritePICONImage() writes an image to a file in the Personal Icon format.
559 % The format of the WritePICONImage method is:
561 % MagickBooleanType WritePICONImage(const ImageInfo *image_info,
562 % Image *image,ExceptionInfo *exception)
564 % A description of each parameter follows.
566 % o image_info: the image info.
568 % o image: The image.
570 % o exception: return any errors or warnings in this structure.
573 static MagickBooleanType WritePICONImage(const ImageInfo *image_info,
574 Image *image,ExceptionInfo *exception)
576 #define ColormapExtent 155
577 #define GraymapExtent 95
578 #define PiconGeometry "48x48>"
583 0x47, 0x49, 0x46, 0x38, 0x37, 0x61, 0x06, 0x00, 0x05, 0x00, 0xf4, 0x05,
584 0x00, 0x00, 0x00, 0x00, 0x2f, 0x4f, 0x4f, 0x70, 0x80, 0x90, 0x7e, 0x7e,
585 0x7e, 0xdc, 0xdc, 0xdc, 0xff, 0xff, 0xff, 0x00, 0x00, 0x80, 0x00, 0x00,
586 0xff, 0x1e, 0x90, 0xff, 0x87, 0xce, 0xeb, 0xe6, 0xe6, 0xfa, 0x00, 0xff,
587 0xff, 0x80, 0x00, 0x80, 0xb2, 0x22, 0x22, 0x2e, 0x8b, 0x57, 0x32, 0xcd,
588 0x32, 0x00, 0xff, 0x00, 0x98, 0xfb, 0x98, 0xff, 0x00, 0xff, 0xff, 0x00,
589 0x00, 0xff, 0x63, 0x47, 0xff, 0xa5, 0x00, 0xff, 0xd7, 0x00, 0xff, 0xff,
590 0x00, 0xee, 0x82, 0xee, 0xa0, 0x52, 0x2d, 0xcd, 0x85, 0x3f, 0xd2, 0xb4,
591 0x8c, 0xf5, 0xde, 0xb3, 0xff, 0xfa, 0xcd, 0x00, 0x00, 0x00, 0x00, 0x00,
592 0x00, 0x21, 0xf9, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00,
593 0x00, 0x00, 0x06, 0x00, 0x05, 0x00, 0x00, 0x05, 0x18, 0x20, 0x10, 0x08,
594 0x03, 0x51, 0x18, 0x07, 0x92, 0x28, 0x0b, 0xd3, 0x38, 0x0f, 0x14, 0x49,
595 0x13, 0x55, 0x59, 0x17, 0x96, 0x69, 0x1b, 0xd7, 0x85, 0x00, 0x3b,
599 0x47, 0x49, 0x46, 0x38, 0x37, 0x61, 0x04, 0x00, 0x04, 0x00, 0xf3, 0x0f,
600 0x00, 0x00, 0x00, 0x00, 0x12, 0x12, 0x12, 0x21, 0x21, 0x21, 0x33, 0x33,
601 0x33, 0x45, 0x45, 0x45, 0x54, 0x54, 0x54, 0x66, 0x66, 0x66, 0x78, 0x78,
602 0x78, 0x87, 0x87, 0x87, 0x99, 0x99, 0x99, 0xab, 0xab, 0xab, 0xba, 0xba,
603 0xba, 0xcc, 0xcc, 0xcc, 0xde, 0xde, 0xde, 0xed, 0xed, 0xed, 0xff, 0xff,
604 0xff, 0x21, 0xf9, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00,
605 0x00, 0x00, 0x04, 0x00, 0x04, 0x00, 0x00, 0x04, 0x0c, 0x10, 0x04, 0x31,
606 0x48, 0x31, 0x07, 0x25, 0xb5, 0x58, 0x73, 0x4f, 0x04, 0x00, 0x3b,
612 Cixel[MaxCixels+1] = " .XoO+@#$%&*=-;:>,<1234567890qwertyuipasdfghjk"
613 "lzxcvbnmMNBVCZASDFGHJKLPIUYTREWQ!~^/()_`'][{}|";
616 buffer[MagickPathExtent],
617 basename[MagickPathExtent],
618 name[MagickPathExtent],
619 symbol[MagickPathExtent];
641 register const Quantum
652 characters_per_pixel,
661 Open output image file.
663 assert(image_info != (const ImageInfo *) NULL);
664 assert(image_info->signature == MagickCoreSignature);
665 assert(image != (Image *) NULL);
666 assert(image->signature == MagickCoreSignature);
667 if (image->debug != MagickFalse)
668 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
669 assert(exception != (ExceptionInfo *) NULL);
670 assert(exception->signature == MagickCoreSignature);
671 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
672 if (status == MagickFalse)
674 (void) TransformImageColorspace(image,sRGBColorspace,exception);
675 SetGeometry(image,&geometry);
676 (void) ParseMetaGeometry(PiconGeometry,&geometry.x,&geometry.y,
677 &geometry.width,&geometry.height);
678 picon=ResizeImage(image,geometry.width,geometry.height,TriangleFilter,
680 blob_info=CloneImageInfo(image_info);
681 (void) AcquireUniqueFilename(blob_info->filename);
682 if ((image_info->type != TrueColorType) &&
683 (SetImageGray(image,exception) != MagickFalse))
684 affinity_image=BlobToImage(blob_info,Graymap,GraymapExtent,exception);
686 affinity_image=BlobToImage(blob_info,Colormap,ColormapExtent,exception);
687 (void) RelinquishUniqueFileResource(blob_info->filename);
688 blob_info=DestroyImageInfo(blob_info);
689 if ((picon == (Image *) NULL) || (affinity_image == (Image *) NULL))
691 quantize_info=AcquireQuantizeInfo(image_info);
692 status=RemapImage(quantize_info,picon,affinity_image,exception);
693 quantize_info=DestroyQuantizeInfo(quantize_info);
694 affinity_image=DestroyImage(affinity_image);
695 transparent=MagickFalse;
696 if (picon->storage_class == PseudoClass)
698 (void) CompressImageColormap(picon,exception);
699 if (picon->alpha_trait != UndefinedPixelTrait)
700 transparent=MagickTrue;
705 Convert DirectClass to PseudoClass picon.
707 if (picon->alpha_trait != UndefinedPixelTrait)
710 Map all the transparent pixels.
712 for (y=0; y < (ssize_t) picon->rows; y++)
714 q=GetAuthenticPixels(picon,0,y,picon->columns,1,exception);
715 if (q == (Quantum *) NULL)
717 for (x=0; x < (ssize_t) picon->columns; x++)
719 if (GetPixelAlpha(image,q) == (Quantum) TransparentAlpha)
720 transparent=MagickTrue;
722 SetPixelAlpha(picon,OpaqueAlpha,q);
723 q+=GetPixelChannels(picon);
725 if (SyncAuthenticPixels(picon,exception) == MagickFalse)
729 (void) SetImageType(picon,PaletteType,exception);
731 colors=picon->colors;
732 if (transparent != MagickFalse)
735 picon->colormap=(PixelInfo *) ResizeQuantumMemory((void **)
736 picon->colormap,(size_t) colors,sizeof(*picon->colormap));
737 if (picon->colormap == (PixelInfo *) NULL)
738 ThrowWriterException(ResourceLimitError,"MemoryAllocationError");
739 for (y=0; y < (ssize_t) picon->rows; y++)
741 q=GetAuthenticPixels(picon,0,y,picon->columns,1,exception);
742 if (q == (Quantum *) NULL)
744 for (x=0; x < (ssize_t) picon->columns; x++)
746 if (GetPixelAlpha(image,q) == (Quantum) TransparentAlpha)
747 SetPixelIndex(picon,(Quantum) picon->colors,q);
748 q+=GetPixelChannels(picon);
750 if (SyncAuthenticPixels(picon,exception) == MagickFalse)
755 Compute the character per pixel.
757 characters_per_pixel=1;
758 for (k=MaxCixels; (ssize_t) colors > k; k*=MaxCixels)
759 characters_per_pixel++;
763 (void) WriteBlobString(image,"/* XPM */\n");
764 GetPathComponent(picon->filename,BasePath,basename);
765 (void) FormatLocaleString(buffer,MagickPathExtent,
766 "static char *%s[] = {\n",basename);
767 (void) WriteBlobString(image,buffer);
768 (void) WriteBlobString(image,"/* columns rows colors chars-per-pixel */\n");
769 (void) FormatLocaleString(buffer,MagickPathExtent,
770 "\"%.20g %.20g %.20g %.20g\",\n",(double) picon->columns,(double)
771 picon->rows,(double) colors,(double) characters_per_pixel);
772 (void) WriteBlobString(image,buffer);
773 GetPixelInfo(image,&pixel);
774 for (i=0; i < (ssize_t) colors; i++)
779 pixel=picon->colormap[i];
780 pixel.colorspace=sRGBColorspace;
782 pixel.alpha=(double) OpaqueAlpha;
783 (void) QueryColorname(image,&pixel,XPMCompliance,name,exception);
784 if (transparent != MagickFalse)
786 if (i == (ssize_t) (colors-1))
787 (void) CopyMagickString(name,"grey75",MagickPathExtent);
794 for (j=1; j < (ssize_t) characters_per_pixel; j++)
796 k=((i-k)/MaxCixels) % MaxCixels;
800 (void) FormatLocaleString(buffer,MagickPathExtent,"\"%s c %s\",\n",
802 (void) WriteBlobString(image,buffer);
807 (void) WriteBlobString(image,"/* pixels */\n");
808 for (y=0; y < (ssize_t) picon->rows; y++)
810 p=GetVirtualPixels(picon,0,y,picon->columns,1,exception);
811 if (p == (const Quantum *) NULL)
813 (void) WriteBlobString(image,"\"");
814 for (x=0; x < (ssize_t) picon->columns; x++)
816 k=((ssize_t) GetPixelIndex(picon,p) % MaxCixels);
818 for (j=1; j < (ssize_t) characters_per_pixel; j++)
820 k=(((int) GetPixelIndex(picon,p)-k)/MaxCixels) % MaxCixels;
824 (void) CopyMagickString(buffer,symbol,MagickPathExtent);
825 (void) WriteBlobString(image,buffer);
826 p+=GetPixelChannels(image);
828 (void) FormatLocaleString(buffer,MagickPathExtent,"\"%s\n",
829 y == (ssize_t) (picon->rows-1) ? "" : ",");
830 (void) WriteBlobString(image,buffer);
831 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
833 if (status == MagickFalse)
836 picon=DestroyImage(picon);
837 (void) WriteBlobString(image,"};\n");
838 (void) CloseBlob(image);
843 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
847 % W r i t e X P M I m a g e %
851 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
853 % WriteXPMImage() writes an image to a file in the X pixmap format.
855 % The format of the WriteXPMImage method is:
857 % MagickBooleanType WriteXPMImage(const ImageInfo *image_info,
858 % Image *image,ExceptionInfo *exception)
860 % A description of each parameter follows.
862 % o image_info: the image info.
864 % o image: The image.
866 % o exception: return any errors or warnings in this structure.
869 static MagickBooleanType WriteXPMImage(const ImageInfo *image_info,Image *image,
870 ExceptionInfo *exception)
875 Cixel[MaxCixels+1] = " .XoO+@#$%&*=-;:>,<1234567890qwertyuipasdfghjk"
876 "lzxcvbnmMNBVCZASDFGHJKLPIUYTREWQ!~^/()_`'][{}|";
879 buffer[MagickPathExtent],
880 basename[MagickPathExtent],
881 name[MagickPathExtent],
882 symbol[MagickPathExtent];
890 register const Quantum
898 characters_per_pixel;
907 Open output image file.
909 assert(image_info != (const ImageInfo *) NULL);
910 assert(image_info->signature == MagickCoreSignature);
911 assert(image != (Image *) NULL);
912 assert(image->signature == MagickCoreSignature);
913 if (image->debug != MagickFalse)
914 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
915 assert(exception != (ExceptionInfo *) NULL);
916 assert(exception->signature == MagickCoreSignature);
917 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
918 if (status == MagickFalse)
920 if (IssRGBCompatibleColorspace(image->colorspace) == MagickFalse)
921 (void) TransformImageColorspace(image,sRGBColorspace,exception);
923 if (image->alpha_trait == UndefinedPixelTrait)
925 if ((image->storage_class == DirectClass) || (image->colors > 256))
926 (void) SetImageType(image,PaletteType,exception);
935 Identify transparent colormap index.
937 if ((image->storage_class == DirectClass) || (image->colors > 256))
938 (void) SetImageType(image,PaletteBilevelAlphaType,exception);
939 for (i=0; i < (ssize_t) image->colors; i++)
940 if (image->colormap[i].alpha != OpaqueAlpha)
947 alpha=(double) TransparentAlpha-(double)
948 image->colormap[i].alpha;
949 beta=(double) TransparentAlpha-(double)
950 image->colormap[opacity].alpha;
956 (void) SetImageType(image,PaletteBilevelAlphaType,exception);
957 for (i=0; i < (ssize_t) image->colors; i++)
958 if (image->colormap[i].alpha != OpaqueAlpha)
965 alpha=(Quantum) TransparentAlpha-(double)
966 image->colormap[i].alpha;
967 beta=(Quantum) TransparentAlpha-(double)
968 image->colormap[opacity].alpha;
975 image->colormap[opacity].red=image->transparent_color.red;
976 image->colormap[opacity].green=image->transparent_color.green;
977 image->colormap[opacity].blue=image->transparent_color.blue;
981 Compute the character per pixel.
983 characters_per_pixel=1;
984 for (k=MaxCixels; (ssize_t) image->colors > k; k*=MaxCixels)
985 characters_per_pixel++;
989 (void) WriteBlobString(image,"/* XPM */\n");
990 GetPathComponent(image->filename,BasePath,basename);
991 if (isalnum((int) ((unsigned char) *basename)) == 0)
993 (void) FormatLocaleString(buffer,MagickPathExtent,"xpm_%s",basename);
994 (void) CopyMagickString(basename,buffer,MagickPathExtent);
996 if (isalpha((int) ((unsigned char) basename[0])) == 0)
998 for (i=1; basename[i] != '\0'; i++)
999 if (isalnum((int) ((unsigned char) basename[i])) == 0)
1001 (void) FormatLocaleString(buffer,MagickPathExtent,
1002 "static char *%s[] = {\n",basename);
1003 (void) WriteBlobString(image,buffer);
1004 (void) WriteBlobString(image,"/* columns rows colors chars-per-pixel */\n");
1005 (void) FormatLocaleString(buffer,MagickPathExtent,
1006 "\"%.20g %.20g %.20g %.20g \",\n",(double) image->columns,(double)
1007 image->rows,(double) image->colors,(double) characters_per_pixel);
1008 (void) WriteBlobString(image,buffer);
1009 GetPixelInfo(image,&pixel);
1010 for (i=0; i < (ssize_t) image->colors; i++)
1015 pixel=image->colormap[i];
1016 pixel.colorspace=sRGBColorspace;
1018 pixel.alpha=(double) OpaqueAlpha;
1019 (void) QueryColorname(image,&pixel,XPMCompliance,name,exception);
1021 (void) CopyMagickString(name,"None",MagickPathExtent);
1027 for (j=1; j < (ssize_t) characters_per_pixel; j++)
1029 k=((i-k)/MaxCixels) % MaxCixels;
1033 (void) FormatLocaleString(buffer,MagickPathExtent,"\"%s c %s\",\n",symbol,
1035 (void) WriteBlobString(image,buffer);
1040 (void) WriteBlobString(image,"/* pixels */\n");
1041 for (y=0; y < (ssize_t) image->rows; y++)
1043 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
1044 if (p == (const Quantum *) NULL)
1046 (void) WriteBlobString(image,"\"");
1047 for (x=0; x < (ssize_t) image->columns; x++)
1049 k=((ssize_t) GetPixelIndex(image,p) % MaxCixels);
1051 for (j=1; j < (ssize_t) characters_per_pixel; j++)
1053 k=(((int) GetPixelIndex(image,p)-k)/MaxCixels) % MaxCixels;
1057 (void) CopyMagickString(buffer,symbol,MagickPathExtent);
1058 (void) WriteBlobString(image,buffer);
1059 p+=GetPixelChannels(image);
1061 (void) FormatLocaleString(buffer,MagickPathExtent,"\"%s\n",
1062 (y == (ssize_t) (image->rows-1) ? "" : ","));
1063 (void) WriteBlobString(image,buffer);
1064 if (image->previous == (Image *) NULL)
1066 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
1068 if (status == MagickFalse)
1072 (void) WriteBlobString(image,"};\n");
1073 (void) CloseBlob(image);