2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13 % Read/Write X Windows system Pixmap Format %
20 % Copyright 1999-2017 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://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 > 3) ||
340 (image->columns == 0) || (image->rows == 0) ||
341 (image->colors == 0) || (image->colors > MaxColormapSize))
343 xpm_buffer=DestroyString(xpm_buffer);
344 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
347 Remove unquoted characters.
350 for (q=xpm_buffer; *p != '\0'; )
354 if (active != MagickFalse)
356 active=active != MagickFalse ? MagickFalse : MagickTrue;
358 if (active != MagickFalse)
363 Initialize image structure.
365 xpm_colors=NewSplayTree(CompareXPMColor,RelinquishMagickMemory,
366 (void *(*)(void *)) NULL);
367 if (AcquireImageColormap(image,image->colors,exception) == MagickFalse)
369 xpm_colors=DestroySplayTree(xpm_colors);
370 xpm_buffer=DestroyString(xpm_buffer);
371 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
377 next=NextXPMLine(xpm_buffer);
378 for (j=0; (j < (ssize_t) image->colors) && (next != (char *) NULL); j++)
382 (void) CopyXPMColor(key,p,MagickMin((size_t) width,MagickPathExtent-1));
383 status=AddValueToSplayTree(xpm_colors,ConstantString(key),(void *) j);
387 (void) CopyMagickString(target,"gray",MagickPathExtent);
388 q=ParseXPMColor(p+width,MagickTrue);
389 if (q != (char *) NULL)
391 while ((isspace((int) ((unsigned char) *q)) == 0) && (*q != '\0'))
395 if (next != (char *) NULL)
396 (void) CopyXPMColor(target,q,MagickMin((size_t) (next-q),
397 MagickPathExtent-1));
399 (void) CopyMagickString(target,q,MagickPathExtent);
400 q=ParseXPMColor(target,MagickFalse);
401 if (q != (char *) NULL)
405 grey=strstr(target,"grey");
406 if (grey != (char *) NULL)
408 if (LocaleCompare(target,"none") == 0)
410 image->storage_class=DirectClass;
411 image->alpha_trait=BlendPixelTrait;
413 status=QueryColorCompliance(target,XPMCompliance,&image->colormap[j],
415 if (status == MagickFalse)
417 if (image->depth < image->colormap[j].depth)
418 image->depth=image->colormap[j].depth;
420 if (j < (ssize_t) image->colors)
422 xpm_colors=DestroySplayTree(xpm_colors);
423 xpm_buffer=DestroyString(xpm_buffer);
424 ThrowReaderException(CorruptImageError,"CorruptImage");
427 if (image_info->ping == MagickFalse)
432 status=SetImageExtent(image,image->columns,image->rows,exception);
433 if (status == MagickFalse)
435 xpm_colors=DestroySplayTree(xpm_colors);
436 xpm_buffer=DestroyString(xpm_buffer);
437 return(DestroyImageList(image));
439 for (y=0; y < (ssize_t) image->rows; y++)
442 if (p == (char *) NULL)
444 r=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
445 if (r == (Quantum *) NULL)
447 for (x=0; x < (ssize_t) image->columns; x++)
449 ssize_t count=CopyXPMColor(key,p,MagickMin(width,MagickPathExtent-1));
450 if (count != (ssize_t) width)
452 j=(ssize_t) GetValueFromSplayTree(xpm_colors,key);
453 if (image->storage_class == PseudoClass)
454 SetPixelIndex(image,(Quantum) j,r);
455 SetPixelViaPixelInfo(image,image->colormap+j,r);
457 r+=GetPixelChannels(image);
459 if (x < (ssize_t) image->columns)
461 if (SyncAuthenticPixels(image,exception) == MagickFalse)
464 if (y < (ssize_t) image->rows)
466 xpm_colors=DestroySplayTree(xpm_colors);
467 xpm_buffer=DestroyString(xpm_buffer);
468 ThrowReaderException(CorruptImageError,"NotEnoughPixelData");
472 Relinquish resources.
474 xpm_buffer=DestroyString(xpm_buffer);
475 xpm_colors=DestroySplayTree(xpm_colors);
476 (void) CloseBlob(image);
477 return(GetFirstImageInList(image));
481 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
485 % R e g i s t e r X P M I m a g e %
489 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
491 % RegisterXPMImage() adds attributes for the XPM image format to
492 % the list of supported formats. The attributes include the image format
493 % tag, a method to read and/or write the format, whether the format
494 % supports the saving of more than one frame to the same file or blob,
495 % whether the format supports native in-memory I/O, and a brief
496 % description of the format.
498 % The format of the RegisterXPMImage method is:
500 % size_t RegisterXPMImage(void)
503 ModuleExport size_t RegisterXPMImage(void)
508 entry=AcquireMagickInfo("XPM","PICON","Personal Icon");
509 entry->decoder=(DecodeImageHandler *) ReadXPMImage;
510 entry->encoder=(EncodeImageHandler *) WritePICONImage;
511 entry->flags^=CoderAdjoinFlag;
512 (void) RegisterMagickInfo(entry);
513 entry=AcquireMagickInfo("XPM","PM","X Windows system pixmap (color)");
514 entry->decoder=(DecodeImageHandler *) ReadXPMImage;
515 entry->encoder=(EncodeImageHandler *) WriteXPMImage;
516 entry->flags^=CoderAdjoinFlag;
517 entry->flags|=CoderStealthFlag;
518 (void) RegisterMagickInfo(entry);
519 entry=AcquireMagickInfo("XPM","XPM","X Windows system pixmap (color)");
520 entry->decoder=(DecodeImageHandler *) ReadXPMImage;
521 entry->encoder=(EncodeImageHandler *) WriteXPMImage;
522 entry->magick=(IsImageFormatHandler *) IsXPM;
523 entry->flags^=CoderAdjoinFlag;
524 (void) RegisterMagickInfo(entry);
525 return(MagickImageCoderSignature);
529 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
533 % U n r e g i s t e r X P M I m a g e %
537 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
539 % UnregisterXPMImage() removes format registrations made by the
540 % XPM module from the list of supported formats.
542 % The format of the UnregisterXPMImage method is:
544 % UnregisterXPMImage(void)
547 ModuleExport void UnregisterXPMImage(void)
549 (void) UnregisterMagickInfo("PICON");
550 (void) UnregisterMagickInfo("PM");
551 (void) UnregisterMagickInfo("XPM");
555 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
559 % W r i t e P I C O N I m a g e %
563 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
565 % WritePICONImage() writes an image to a file in the Personal Icon format.
567 % The format of the WritePICONImage method is:
569 % MagickBooleanType WritePICONImage(const ImageInfo *image_info,
570 % Image *image,ExceptionInfo *exception)
572 % A description of each parameter follows.
574 % o image_info: the image info.
576 % o image: The image.
578 % o exception: return any errors or warnings in this structure.
581 static MagickBooleanType WritePICONImage(const ImageInfo *image_info,
582 Image *image,ExceptionInfo *exception)
584 #define ColormapExtent 155
585 #define GraymapExtent 95
586 #define PiconGeometry "48x48>"
591 0x47, 0x49, 0x46, 0x38, 0x37, 0x61, 0x06, 0x00, 0x05, 0x00, 0xf4, 0x05,
592 0x00, 0x00, 0x00, 0x00, 0x2f, 0x4f, 0x4f, 0x70, 0x80, 0x90, 0x7e, 0x7e,
593 0x7e, 0xdc, 0xdc, 0xdc, 0xff, 0xff, 0xff, 0x00, 0x00, 0x80, 0x00, 0x00,
594 0xff, 0x1e, 0x90, 0xff, 0x87, 0xce, 0xeb, 0xe6, 0xe6, 0xfa, 0x00, 0xff,
595 0xff, 0x80, 0x00, 0x80, 0xb2, 0x22, 0x22, 0x2e, 0x8b, 0x57, 0x32, 0xcd,
596 0x32, 0x00, 0xff, 0x00, 0x98, 0xfb, 0x98, 0xff, 0x00, 0xff, 0xff, 0x00,
597 0x00, 0xff, 0x63, 0x47, 0xff, 0xa5, 0x00, 0xff, 0xd7, 0x00, 0xff, 0xff,
598 0x00, 0xee, 0x82, 0xee, 0xa0, 0x52, 0x2d, 0xcd, 0x85, 0x3f, 0xd2, 0xb4,
599 0x8c, 0xf5, 0xde, 0xb3, 0xff, 0xfa, 0xcd, 0x00, 0x00, 0x00, 0x00, 0x00,
600 0x00, 0x21, 0xf9, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00,
601 0x00, 0x00, 0x06, 0x00, 0x05, 0x00, 0x00, 0x05, 0x18, 0x20, 0x10, 0x08,
602 0x03, 0x51, 0x18, 0x07, 0x92, 0x28, 0x0b, 0xd3, 0x38, 0x0f, 0x14, 0x49,
603 0x13, 0x55, 0x59, 0x17, 0x96, 0x69, 0x1b, 0xd7, 0x85, 0x00, 0x3b,
607 0x47, 0x49, 0x46, 0x38, 0x37, 0x61, 0x04, 0x00, 0x04, 0x00, 0xf3, 0x0f,
608 0x00, 0x00, 0x00, 0x00, 0x12, 0x12, 0x12, 0x21, 0x21, 0x21, 0x33, 0x33,
609 0x33, 0x45, 0x45, 0x45, 0x54, 0x54, 0x54, 0x66, 0x66, 0x66, 0x78, 0x78,
610 0x78, 0x87, 0x87, 0x87, 0x99, 0x99, 0x99, 0xab, 0xab, 0xab, 0xba, 0xba,
611 0xba, 0xcc, 0xcc, 0xcc, 0xde, 0xde, 0xde, 0xed, 0xed, 0xed, 0xff, 0xff,
612 0xff, 0x21, 0xf9, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00,
613 0x00, 0x00, 0x04, 0x00, 0x04, 0x00, 0x00, 0x04, 0x0c, 0x10, 0x04, 0x31,
614 0x48, 0x31, 0x07, 0x25, 0xb5, 0x58, 0x73, 0x4f, 0x04, 0x00, 0x3b,
620 Cixel[MaxCixels+1] = " .XoO+@#$%&*=-;:>,<1234567890qwertyuipasdfghjk"
621 "lzxcvbnmMNBVCZASDFGHJKLPIUYTREWQ!~^/()_`'][{}|";
624 buffer[MagickPathExtent],
625 basename[MagickPathExtent],
626 name[MagickPathExtent],
627 symbol[MagickPathExtent];
649 register const Quantum
660 characters_per_pixel,
669 Open output image file.
671 assert(image_info != (const ImageInfo *) NULL);
672 assert(image_info->signature == MagickCoreSignature);
673 assert(image != (Image *) NULL);
674 assert(image->signature == MagickCoreSignature);
675 if (image->debug != MagickFalse)
676 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
677 assert(exception != (ExceptionInfo *) NULL);
678 assert(exception->signature == MagickCoreSignature);
679 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
680 if (status == MagickFalse)
682 (void) TransformImageColorspace(image,sRGBColorspace,exception);
683 SetGeometry(image,&geometry);
684 (void) ParseMetaGeometry(PiconGeometry,&geometry.x,&geometry.y,
685 &geometry.width,&geometry.height);
686 picon=ResizeImage(image,geometry.width,geometry.height,TriangleFilter,
688 blob_info=CloneImageInfo(image_info);
689 (void) AcquireUniqueFilename(blob_info->filename);
690 if ((image_info->type != TrueColorType) &&
691 (SetImageGray(image,exception) != MagickFalse))
692 affinity_image=BlobToImage(blob_info,Graymap,GraymapExtent,exception);
694 affinity_image=BlobToImage(blob_info,Colormap,ColormapExtent,exception);
695 (void) RelinquishUniqueFileResource(blob_info->filename);
696 blob_info=DestroyImageInfo(blob_info);
697 if ((picon == (Image *) NULL) || (affinity_image == (Image *) NULL))
699 if (affinity_image != (Image *) NULL)
700 affinity_image=DestroyImage(affinity_image);
701 if (picon != (Image *) NULL)
702 picon=DestroyImage(picon);
705 quantize_info=AcquireQuantizeInfo(image_info);
706 status=RemapImage(quantize_info,picon,affinity_image,exception);
707 quantize_info=DestroyQuantizeInfo(quantize_info);
708 affinity_image=DestroyImage(affinity_image);
709 transparent=MagickFalse;
710 if (picon->storage_class == PseudoClass)
712 (void) CompressImageColormap(picon,exception);
713 if (picon->alpha_trait != UndefinedPixelTrait)
714 transparent=MagickTrue;
719 Convert DirectClass to PseudoClass picon.
721 if (picon->alpha_trait != UndefinedPixelTrait)
724 Map all the transparent pixels.
726 for (y=0; y < (ssize_t) picon->rows; y++)
728 q=GetAuthenticPixels(picon,0,y,picon->columns,1,exception);
729 if (q == (Quantum *) NULL)
731 for (x=0; x < (ssize_t) picon->columns; x++)
733 if (GetPixelAlpha(image,q) == (Quantum) TransparentAlpha)
734 transparent=MagickTrue;
736 SetPixelAlpha(picon,OpaqueAlpha,q);
737 q+=GetPixelChannels(picon);
739 if (SyncAuthenticPixels(picon,exception) == MagickFalse)
743 (void) SetImageType(picon,PaletteType,exception);
745 colors=picon->colors;
746 if (transparent != MagickFalse)
749 picon->colormap=(PixelInfo *) ResizeQuantumMemory((void **)
750 picon->colormap,(size_t) colors,sizeof(*picon->colormap));
751 if (picon->colormap == (PixelInfo *) NULL)
752 ThrowWriterException(ResourceLimitError,"MemoryAllocationError");
753 for (y=0; y < (ssize_t) picon->rows; y++)
755 q=GetAuthenticPixels(picon,0,y,picon->columns,1,exception);
756 if (q == (Quantum *) NULL)
758 for (x=0; x < (ssize_t) picon->columns; x++)
760 if (GetPixelAlpha(image,q) == (Quantum) TransparentAlpha)
761 SetPixelIndex(picon,(Quantum) picon->colors,q);
762 q+=GetPixelChannels(picon);
764 if (SyncAuthenticPixels(picon,exception) == MagickFalse)
769 Compute the character per pixel.
771 characters_per_pixel=1;
772 for (k=MaxCixels; (ssize_t) colors > k; k*=MaxCixels)
773 characters_per_pixel++;
777 (void) WriteBlobString(image,"/* XPM */\n");
778 GetPathComponent(picon->filename,BasePath,basename);
779 (void) FormatLocaleString(buffer,MagickPathExtent,
780 "static char *%s[] = {\n",basename);
781 (void) WriteBlobString(image,buffer);
782 (void) WriteBlobString(image,"/* columns rows colors chars-per-pixel */\n");
783 (void) FormatLocaleString(buffer,MagickPathExtent,
784 "\"%.20g %.20g %.20g %.20g\",\n",(double) picon->columns,(double)
785 picon->rows,(double) colors,(double) characters_per_pixel);
786 (void) WriteBlobString(image,buffer);
787 GetPixelInfo(image,&pixel);
788 for (i=0; i < (ssize_t) colors; i++)
793 pixel=picon->colormap[i];
794 pixel.colorspace=sRGBColorspace;
796 pixel.alpha=(double) OpaqueAlpha;
797 (void) QueryColorname(image,&pixel,XPMCompliance,name,exception);
798 if (transparent != MagickFalse)
800 if (i == (ssize_t) (colors-1))
801 (void) CopyMagickString(name,"grey75",MagickPathExtent);
808 for (j=1; j < (ssize_t) characters_per_pixel; j++)
810 k=((i-k)/MaxCixels) % MaxCixels;
814 (void) FormatLocaleString(buffer,MagickPathExtent,"\"%s c %s\",\n",
816 (void) WriteBlobString(image,buffer);
821 (void) WriteBlobString(image,"/* pixels */\n");
822 for (y=0; y < (ssize_t) picon->rows; y++)
824 p=GetVirtualPixels(picon,0,y,picon->columns,1,exception);
825 if (p == (const Quantum *) NULL)
827 (void) WriteBlobString(image,"\"");
828 for (x=0; x < (ssize_t) picon->columns; x++)
830 k=((ssize_t) GetPixelIndex(picon,p) % MaxCixels);
832 for (j=1; j < (ssize_t) characters_per_pixel; j++)
834 k=(((int) GetPixelIndex(picon,p)-k)/MaxCixels) % MaxCixels;
838 (void) CopyMagickString(buffer,symbol,MagickPathExtent);
839 (void) WriteBlobString(image,buffer);
840 p+=GetPixelChannels(picon);
842 (void) FormatLocaleString(buffer,MagickPathExtent,"\"%s\n",
843 y == (ssize_t) (picon->rows-1) ? "" : ",");
844 (void) WriteBlobString(image,buffer);
845 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
847 if (status == MagickFalse)
850 picon=DestroyImage(picon);
851 (void) WriteBlobString(image,"};\n");
852 (void) CloseBlob(image);
857 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
861 % W r i t e X P M I m a g e %
865 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
867 % WriteXPMImage() writes an image to a file in the X pixmap format.
869 % The format of the WriteXPMImage method is:
871 % MagickBooleanType WriteXPMImage(const ImageInfo *image_info,
872 % Image *image,ExceptionInfo *exception)
874 % A description of each parameter follows.
876 % o image_info: the image info.
878 % o image: The image.
880 % o exception: return any errors or warnings in this structure.
883 static MagickBooleanType WriteXPMImage(const ImageInfo *image_info,Image *image,
884 ExceptionInfo *exception)
889 Cixel[MaxCixels+1] = " .XoO+@#$%&*=-;:>,<1234567890qwertyuipasdfghjk"
890 "lzxcvbnmMNBVCZASDFGHJKLPIUYTREWQ!~^/()_`'][{}|";
893 buffer[MagickPathExtent],
894 basename[MagickPathExtent],
895 name[MagickPathExtent],
896 symbol[MagickPathExtent];
904 register const Quantum
912 characters_per_pixel;
921 Open output image file.
923 assert(image_info != (const ImageInfo *) NULL);
924 assert(image_info->signature == MagickCoreSignature);
925 assert(image != (Image *) NULL);
926 assert(image->signature == MagickCoreSignature);
927 if (image->debug != MagickFalse)
928 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
929 assert(exception != (ExceptionInfo *) NULL);
930 assert(exception->signature == MagickCoreSignature);
931 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
932 if (status == MagickFalse)
934 if (IssRGBCompatibleColorspace(image->colorspace) == MagickFalse)
935 (void) TransformImageColorspace(image,sRGBColorspace,exception);
937 if (image->alpha_trait == UndefinedPixelTrait)
939 if ((image->storage_class == DirectClass) || (image->colors > 256))
940 (void) SetImageType(image,PaletteType,exception);
949 Identify transparent colormap index.
951 if ((image->storage_class == DirectClass) || (image->colors > 256))
952 (void) SetImageType(image,PaletteBilevelAlphaType,exception);
953 for (i=0; i < (ssize_t) image->colors; i++)
954 if (image->colormap[i].alpha != OpaqueAlpha)
961 alpha=(double) TransparentAlpha-(double)
962 image->colormap[i].alpha;
963 beta=(double) TransparentAlpha-(double)
964 image->colormap[opacity].alpha;
970 (void) SetImageType(image,PaletteBilevelAlphaType,exception);
971 for (i=0; i < (ssize_t) image->colors; i++)
972 if (image->colormap[i].alpha != OpaqueAlpha)
979 alpha=(Quantum) TransparentAlpha-(double)
980 image->colormap[i].alpha;
981 beta=(Quantum) TransparentAlpha-(double)
982 image->colormap[opacity].alpha;
989 image->colormap[opacity].red=image->transparent_color.red;
990 image->colormap[opacity].green=image->transparent_color.green;
991 image->colormap[opacity].blue=image->transparent_color.blue;
995 Compute the character per pixel.
997 characters_per_pixel=1;
998 for (k=MaxCixels; (ssize_t) image->colors > k; k*=MaxCixels)
999 characters_per_pixel++;
1003 (void) WriteBlobString(image,"/* XPM */\n");
1004 GetPathComponent(image->filename,BasePath,basename);
1005 if (isalnum((int) ((unsigned char) *basename)) == 0)
1007 (void) FormatLocaleString(buffer,MagickPathExtent,"xpm_%s",basename);
1008 (void) CopyMagickString(basename,buffer,MagickPathExtent);
1010 if (isalpha((int) ((unsigned char) basename[0])) == 0)
1012 for (i=1; basename[i] != '\0'; i++)
1013 if (isalnum((int) ((unsigned char) basename[i])) == 0)
1015 (void) FormatLocaleString(buffer,MagickPathExtent,
1016 "static char *%s[] = {\n",basename);
1017 (void) WriteBlobString(image,buffer);
1018 (void) WriteBlobString(image,"/* columns rows colors chars-per-pixel */\n");
1019 (void) FormatLocaleString(buffer,MagickPathExtent,
1020 "\"%.20g %.20g %.20g %.20g \",\n",(double) image->columns,(double)
1021 image->rows,(double) image->colors,(double) characters_per_pixel);
1022 (void) WriteBlobString(image,buffer);
1023 GetPixelInfo(image,&pixel);
1024 for (i=0; i < (ssize_t) image->colors; i++)
1029 pixel=image->colormap[i];
1030 pixel.colorspace=sRGBColorspace;
1032 pixel.alpha=(double) OpaqueAlpha;
1033 (void) QueryColorname(image,&pixel,XPMCompliance,name,exception);
1035 (void) CopyMagickString(name,"None",MagickPathExtent);
1041 for (j=1; j < (ssize_t) characters_per_pixel; j++)
1043 k=((i-k)/MaxCixels) % MaxCixels;
1047 (void) FormatLocaleString(buffer,MagickPathExtent,"\"%s c %s\",\n",symbol,
1049 (void) WriteBlobString(image,buffer);
1054 (void) WriteBlobString(image,"/* pixels */\n");
1055 for (y=0; y < (ssize_t) image->rows; y++)
1057 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
1058 if (p == (const Quantum *) NULL)
1060 (void) WriteBlobString(image,"\"");
1061 for (x=0; x < (ssize_t) image->columns; x++)
1063 k=((ssize_t) GetPixelIndex(image,p) % MaxCixels);
1065 for (j=1; j < (ssize_t) characters_per_pixel; j++)
1067 k=(((int) GetPixelIndex(image,p)-k)/MaxCixels) % MaxCixels;
1071 (void) CopyMagickString(buffer,symbol,MagickPathExtent);
1072 (void) WriteBlobString(image,buffer);
1073 p+=GetPixelChannels(image);
1075 (void) FormatLocaleString(buffer,MagickPathExtent,"\"%s\n",
1076 (y == (ssize_t) (image->rows-1) ? "" : ","));
1077 (void) WriteBlobString(image,buffer);
1078 if (image->previous == (Image *) NULL)
1080 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
1082 if (status == MagickFalse)
1086 (void) WriteBlobString(image,"};\n");
1087 (void) CloseBlob(image);