2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13 % Read/Write X Windows system Pixmap Format %
20 % Copyright 1999-2018 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 if (next == (char *) NULL)
384 length=MagickMin((size_t) width,MagickPathExtent-1);
385 if (CopyXPMColor(key,p,length) != (ssize_t) length)
387 status=AddValueToSplayTree(xpm_colors,ConstantString(key),(void *) j);
391 (void) CopyMagickString(target,"gray",MagickPathExtent);
393 if (strlen(p) > width)
394 q=ParseXPMColor(p+width,MagickTrue);
395 if (q != (char *) NULL)
397 while ((isspace((int) ((unsigned char) *q)) == 0) && (*q != '\0'))
401 (void) CopyXPMColor(target,q,MagickMin((size_t) (next-q),
402 MagickPathExtent-1));
403 q=ParseXPMColor(target,MagickFalse);
404 if (q != (char *) NULL)
408 grey=strstr(target,"grey");
409 if (grey != (char *) NULL)
411 if (LocaleCompare(target,"none") == 0)
413 image->storage_class=DirectClass;
414 image->alpha_trait=BlendPixelTrait;
416 status=QueryColorCompliance(target,XPMCompliance,&image->colormap[j],
418 if (status == MagickFalse)
420 if (image->depth < image->colormap[j].depth)
421 image->depth=image->colormap[j].depth;
423 if (j < (ssize_t) image->colors)
425 xpm_colors=DestroySplayTree(xpm_colors);
426 xpm_buffer=DestroyString(xpm_buffer);
427 ThrowReaderException(CorruptImageError,"CorruptImage");
430 if (image_info->ping == MagickFalse)
435 status=SetImageExtent(image,image->columns,image->rows,exception);
436 if (status == MagickFalse)
438 xpm_colors=DestroySplayTree(xpm_colors);
439 xpm_buffer=DestroyString(xpm_buffer);
440 return(DestroyImageList(image));
442 for (y=0; y < (ssize_t) image->rows; y++)
445 if (p == (char *) NULL)
447 r=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
448 if (r == (Quantum *) NULL)
450 for (x=0; x < (ssize_t) image->columns; x++)
452 ssize_t count=CopyXPMColor(key,p,MagickMin(width,MagickPathExtent-1));
453 if (count != (ssize_t) width)
455 j=(ssize_t) GetValueFromSplayTree(xpm_colors,key);
456 if (image->storage_class == PseudoClass)
457 SetPixelIndex(image,(Quantum) j,r);
458 SetPixelViaPixelInfo(image,image->colormap+j,r);
460 r+=GetPixelChannels(image);
462 if (x < (ssize_t) image->columns)
464 if (SyncAuthenticPixels(image,exception) == MagickFalse)
467 if (y < (ssize_t) image->rows)
469 xpm_colors=DestroySplayTree(xpm_colors);
470 xpm_buffer=DestroyString(xpm_buffer);
471 ThrowReaderException(CorruptImageError,"NotEnoughPixelData");
475 Relinquish resources.
477 xpm_buffer=DestroyString(xpm_buffer);
478 xpm_colors=DestroySplayTree(xpm_colors);
479 (void) CloseBlob(image);
480 return(GetFirstImageInList(image));
484 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
488 % R e g i s t e r X P M I m a g e %
492 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
494 % RegisterXPMImage() adds attributes for the XPM image format to
495 % the list of supported formats. The attributes include the image format
496 % tag, a method to read and/or write the format, whether the format
497 % supports the saving of more than one frame to the same file or blob,
498 % whether the format supports native in-memory I/O, and a brief
499 % description of the format.
501 % The format of the RegisterXPMImage method is:
503 % size_t RegisterXPMImage(void)
506 ModuleExport size_t RegisterXPMImage(void)
511 entry=AcquireMagickInfo("XPM","PICON","Personal Icon");
512 entry->decoder=(DecodeImageHandler *) ReadXPMImage;
513 entry->encoder=(EncodeImageHandler *) WritePICONImage;
514 entry->flags^=CoderAdjoinFlag;
515 (void) RegisterMagickInfo(entry);
516 entry=AcquireMagickInfo("XPM","PM","X Windows system pixmap (color)");
517 entry->decoder=(DecodeImageHandler *) ReadXPMImage;
518 entry->encoder=(EncodeImageHandler *) WriteXPMImage;
519 entry->flags^=CoderAdjoinFlag;
520 entry->flags|=CoderStealthFlag;
521 (void) RegisterMagickInfo(entry);
522 entry=AcquireMagickInfo("XPM","XPM","X Windows system pixmap (color)");
523 entry->decoder=(DecodeImageHandler *) ReadXPMImage;
524 entry->encoder=(EncodeImageHandler *) WriteXPMImage;
525 entry->magick=(IsImageFormatHandler *) IsXPM;
526 entry->flags^=CoderAdjoinFlag;
527 (void) RegisterMagickInfo(entry);
528 return(MagickImageCoderSignature);
532 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
536 % U n r e g i s t e r X P M I m a g e %
540 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
542 % UnregisterXPMImage() removes format registrations made by the
543 % XPM module from the list of supported formats.
545 % The format of the UnregisterXPMImage method is:
547 % UnregisterXPMImage(void)
550 ModuleExport void UnregisterXPMImage(void)
552 (void) UnregisterMagickInfo("PICON");
553 (void) UnregisterMagickInfo("PM");
554 (void) UnregisterMagickInfo("XPM");
558 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
562 % W r i t e P I C O N I m a g e %
566 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
568 % WritePICONImage() writes an image to a file in the Personal Icon format.
570 % The format of the WritePICONImage method is:
572 % MagickBooleanType WritePICONImage(const ImageInfo *image_info,
573 % Image *image,ExceptionInfo *exception)
575 % A description of each parameter follows.
577 % o image_info: the image info.
579 % o image: The image.
581 % o exception: return any errors or warnings in this structure.
584 static MagickBooleanType WritePICONImage(const ImageInfo *image_info,
585 Image *image,ExceptionInfo *exception)
587 #define ColormapExtent 155
588 #define GraymapExtent 95
589 #define PiconGeometry "48x48>"
594 0x47, 0x49, 0x46, 0x38, 0x37, 0x61, 0x06, 0x00, 0x05, 0x00, 0xf4, 0x05,
595 0x00, 0x00, 0x00, 0x00, 0x2f, 0x4f, 0x4f, 0x70, 0x80, 0x90, 0x7e, 0x7e,
596 0x7e, 0xdc, 0xdc, 0xdc, 0xff, 0xff, 0xff, 0x00, 0x00, 0x80, 0x00, 0x00,
597 0xff, 0x1e, 0x90, 0xff, 0x87, 0xce, 0xeb, 0xe6, 0xe6, 0xfa, 0x00, 0xff,
598 0xff, 0x80, 0x00, 0x80, 0xb2, 0x22, 0x22, 0x2e, 0x8b, 0x57, 0x32, 0xcd,
599 0x32, 0x00, 0xff, 0x00, 0x98, 0xfb, 0x98, 0xff, 0x00, 0xff, 0xff, 0x00,
600 0x00, 0xff, 0x63, 0x47, 0xff, 0xa5, 0x00, 0xff, 0xd7, 0x00, 0xff, 0xff,
601 0x00, 0xee, 0x82, 0xee, 0xa0, 0x52, 0x2d, 0xcd, 0x85, 0x3f, 0xd2, 0xb4,
602 0x8c, 0xf5, 0xde, 0xb3, 0xff, 0xfa, 0xcd, 0x00, 0x00, 0x00, 0x00, 0x00,
603 0x00, 0x21, 0xf9, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00,
604 0x00, 0x00, 0x06, 0x00, 0x05, 0x00, 0x00, 0x05, 0x18, 0x20, 0x10, 0x08,
605 0x03, 0x51, 0x18, 0x07, 0x92, 0x28, 0x0b, 0xd3, 0x38, 0x0f, 0x14, 0x49,
606 0x13, 0x55, 0x59, 0x17, 0x96, 0x69, 0x1b, 0xd7, 0x85, 0x00, 0x3b,
610 0x47, 0x49, 0x46, 0x38, 0x37, 0x61, 0x04, 0x00, 0x04, 0x00, 0xf3, 0x0f,
611 0x00, 0x00, 0x00, 0x00, 0x12, 0x12, 0x12, 0x21, 0x21, 0x21, 0x33, 0x33,
612 0x33, 0x45, 0x45, 0x45, 0x54, 0x54, 0x54, 0x66, 0x66, 0x66, 0x78, 0x78,
613 0x78, 0x87, 0x87, 0x87, 0x99, 0x99, 0x99, 0xab, 0xab, 0xab, 0xba, 0xba,
614 0xba, 0xcc, 0xcc, 0xcc, 0xde, 0xde, 0xde, 0xed, 0xed, 0xed, 0xff, 0xff,
615 0xff, 0x21, 0xf9, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00,
616 0x00, 0x00, 0x04, 0x00, 0x04, 0x00, 0x00, 0x04, 0x0c, 0x10, 0x04, 0x31,
617 0x48, 0x31, 0x07, 0x25, 0xb5, 0x58, 0x73, 0x4f, 0x04, 0x00, 0x3b,
623 Cixel[MaxCixels+1] = " .XoO+@#$%&*=-;:>,<1234567890qwertyuipasdfghjk"
624 "lzxcvbnmMNBVCZASDFGHJKLPIUYTREWQ!~^/()_`'][{}|";
627 buffer[MagickPathExtent],
628 basename[MagickPathExtent],
629 name[MagickPathExtent],
630 symbol[MagickPathExtent];
652 register const Quantum
663 characters_per_pixel,
672 Open output image file.
674 assert(image_info != (const ImageInfo *) NULL);
675 assert(image_info->signature == MagickCoreSignature);
676 assert(image != (Image *) NULL);
677 assert(image->signature == MagickCoreSignature);
678 if (image->debug != MagickFalse)
679 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
680 assert(exception != (ExceptionInfo *) NULL);
681 assert(exception->signature == MagickCoreSignature);
682 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
683 if (status == MagickFalse)
685 (void) TransformImageColorspace(image,sRGBColorspace,exception);
686 SetGeometry(image,&geometry);
687 (void) ParseMetaGeometry(PiconGeometry,&geometry.x,&geometry.y,
688 &geometry.width,&geometry.height);
689 picon=ResizeImage(image,geometry.width,geometry.height,TriangleFilter,
691 blob_info=CloneImageInfo(image_info);
692 (void) AcquireUniqueFilename(blob_info->filename);
693 if ((image_info->type != TrueColorType) &&
694 (SetImageGray(image,exception) != MagickFalse))
695 affinity_image=BlobToImage(blob_info,Graymap,GraymapExtent,exception);
697 affinity_image=BlobToImage(blob_info,Colormap,ColormapExtent,exception);
698 (void) RelinquishUniqueFileResource(blob_info->filename);
699 blob_info=DestroyImageInfo(blob_info);
700 if ((picon == (Image *) NULL) || (affinity_image == (Image *) NULL))
702 if (affinity_image != (Image *) NULL)
703 affinity_image=DestroyImage(affinity_image);
704 if (picon != (Image *) NULL)
705 picon=DestroyImage(picon);
708 quantize_info=AcquireQuantizeInfo(image_info);
709 status=RemapImage(quantize_info,picon,affinity_image,exception);
710 quantize_info=DestroyQuantizeInfo(quantize_info);
711 affinity_image=DestroyImage(affinity_image);
712 transparent=MagickFalse;
713 if (picon->storage_class == PseudoClass)
715 (void) CompressImageColormap(picon,exception);
716 if (picon->alpha_trait != UndefinedPixelTrait)
717 transparent=MagickTrue;
722 Convert DirectClass to PseudoClass picon.
724 if (picon->alpha_trait != UndefinedPixelTrait)
727 Map all the transparent pixels.
729 for (y=0; y < (ssize_t) picon->rows; y++)
731 q=GetAuthenticPixels(picon,0,y,picon->columns,1,exception);
732 if (q == (Quantum *) NULL)
734 for (x=0; x < (ssize_t) picon->columns; x++)
736 if (GetPixelAlpha(image,q) == (Quantum) TransparentAlpha)
737 transparent=MagickTrue;
739 SetPixelAlpha(picon,OpaqueAlpha,q);
740 q+=GetPixelChannels(picon);
742 if (SyncAuthenticPixels(picon,exception) == MagickFalse)
746 (void) SetImageType(picon,PaletteType,exception);
748 colors=picon->colors;
749 if (transparent != MagickFalse)
752 picon->colormap=(PixelInfo *) ResizeQuantumMemory((void **)
753 picon->colormap,(size_t) colors,sizeof(*picon->colormap));
754 if (picon->colormap == (PixelInfo *) NULL)
755 ThrowWriterException(ResourceLimitError,"MemoryAllocationError");
756 for (y=0; y < (ssize_t) picon->rows; y++)
758 q=GetAuthenticPixels(picon,0,y,picon->columns,1,exception);
759 if (q == (Quantum *) NULL)
761 for (x=0; x < (ssize_t) picon->columns; x++)
763 if (GetPixelAlpha(image,q) == (Quantum) TransparentAlpha)
764 SetPixelIndex(picon,(Quantum) picon->colors,q);
765 q+=GetPixelChannels(picon);
767 if (SyncAuthenticPixels(picon,exception) == MagickFalse)
772 Compute the character per pixel.
774 characters_per_pixel=1;
775 for (k=MaxCixels; (ssize_t) colors > k; k*=MaxCixels)
776 characters_per_pixel++;
780 (void) WriteBlobString(image,"/* XPM */\n");
781 GetPathComponent(picon->filename,BasePath,basename);
782 (void) FormatLocaleString(buffer,MagickPathExtent,
783 "static char *%.1024s[] = {\n",basename);
784 (void) WriteBlobString(image,buffer);
785 (void) WriteBlobString(image,"/* columns rows colors chars-per-pixel */\n");
786 (void) FormatLocaleString(buffer,MagickPathExtent,
787 "\"%.20g %.20g %.20g %.20g\",\n",(double) picon->columns,(double)
788 picon->rows,(double) colors,(double) characters_per_pixel);
789 (void) WriteBlobString(image,buffer);
790 GetPixelInfo(image,&pixel);
791 for (i=0; i < (ssize_t) colors; i++)
796 pixel=picon->colormap[i];
797 pixel.colorspace=sRGBColorspace;
799 pixel.alpha=(double) OpaqueAlpha;
800 (void) QueryColorname(image,&pixel,XPMCompliance,name,exception);
801 if (transparent != MagickFalse)
803 if (i == (ssize_t) (colors-1))
804 (void) CopyMagickString(name,"grey75",MagickPathExtent);
811 for (j=1; j < (ssize_t) characters_per_pixel; j++)
813 k=((i-k)/MaxCixels) % MaxCixels;
817 (void) FormatLocaleString(buffer,MagickPathExtent,
818 "\"%.1024s c %.1024s\",\n",symbol,name);
819 (void) WriteBlobString(image,buffer);
824 (void) WriteBlobString(image,"/* pixels */\n");
825 for (y=0; y < (ssize_t) picon->rows; y++)
827 p=GetVirtualPixels(picon,0,y,picon->columns,1,exception);
828 if (p == (const Quantum *) NULL)
830 (void) WriteBlobString(image,"\"");
831 for (x=0; x < (ssize_t) picon->columns; x++)
833 k=((ssize_t) GetPixelIndex(picon,p) % MaxCixels);
835 for (j=1; j < (ssize_t) characters_per_pixel; j++)
837 k=(((int) GetPixelIndex(picon,p)-k)/MaxCixels) % MaxCixels;
841 (void) CopyMagickString(buffer,symbol,MagickPathExtent);
842 (void) WriteBlobString(image,buffer);
843 p+=GetPixelChannels(picon);
845 (void) FormatLocaleString(buffer,MagickPathExtent,"\"%.1024s\n",
846 y == (ssize_t) (picon->rows-1) ? "" : ",");
847 (void) WriteBlobString(image,buffer);
848 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
850 if (status == MagickFalse)
853 picon=DestroyImage(picon);
854 (void) WriteBlobString(image,"};\n");
855 (void) CloseBlob(image);
860 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
864 % W r i t e X P M I m a g e %
868 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
870 % WriteXPMImage() writes an image to a file in the X pixmap format.
872 % The format of the WriteXPMImage method is:
874 % MagickBooleanType WriteXPMImage(const ImageInfo *image_info,
875 % Image *image,ExceptionInfo *exception)
877 % A description of each parameter follows.
879 % o image_info: the image info.
881 % o image: The image.
883 % o exception: return any errors or warnings in this structure.
886 static MagickBooleanType WriteXPMImage(const ImageInfo *image_info,Image *image,
887 ExceptionInfo *exception)
892 Cixel[MaxCixels+1] = " .XoO+@#$%&*=-;:>,<1234567890qwertyuipasdfghjk"
893 "lzxcvbnmMNBVCZASDFGHJKLPIUYTREWQ!~^/()_`'][{}|";
896 buffer[MagickPathExtent],
897 basename[MagickPathExtent],
898 name[MagickPathExtent],
899 symbol[MagickPathExtent];
907 register const Quantum
915 characters_per_pixel;
924 Open output image file.
926 assert(image_info != (const ImageInfo *) NULL);
927 assert(image_info->signature == MagickCoreSignature);
928 assert(image != (Image *) NULL);
929 assert(image->signature == MagickCoreSignature);
930 if (image->debug != MagickFalse)
931 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
932 assert(exception != (ExceptionInfo *) NULL);
933 assert(exception->signature == MagickCoreSignature);
934 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
935 if (status == MagickFalse)
937 if (IssRGBCompatibleColorspace(image->colorspace) == MagickFalse)
938 (void) TransformImageColorspace(image,sRGBColorspace,exception);
940 if (image->alpha_trait == UndefinedPixelTrait)
942 if ((image->storage_class == DirectClass) || (image->colors > 256))
943 (void) SetImageType(image,PaletteType,exception);
952 Identify transparent colormap index.
954 if ((image->storage_class == DirectClass) || (image->colors > 256))
955 (void) SetImageType(image,PaletteBilevelAlphaType,exception);
956 for (i=0; i < (ssize_t) image->colors; i++)
957 if (image->colormap[i].alpha != OpaqueAlpha)
964 alpha=(double) TransparentAlpha-(double)
965 image->colormap[i].alpha;
966 beta=(double) TransparentAlpha-(double)
967 image->colormap[opacity].alpha;
973 (void) SetImageType(image,PaletteBilevelAlphaType,exception);
974 for (i=0; i < (ssize_t) image->colors; i++)
975 if (image->colormap[i].alpha != OpaqueAlpha)
982 alpha=(Quantum) TransparentAlpha-(double)
983 image->colormap[i].alpha;
984 beta=(Quantum) TransparentAlpha-(double)
985 image->colormap[opacity].alpha;
992 image->colormap[opacity].red=image->transparent_color.red;
993 image->colormap[opacity].green=image->transparent_color.green;
994 image->colormap[opacity].blue=image->transparent_color.blue;
998 Compute the character per pixel.
1000 characters_per_pixel=1;
1001 for (k=MaxCixels; (ssize_t) image->colors > k; k*=MaxCixels)
1002 characters_per_pixel++;
1006 (void) WriteBlobString(image,"/* XPM */\n");
1007 GetPathComponent(image->filename,BasePath,basename);
1008 if (isalnum((int) ((unsigned char) *basename)) == 0)
1010 (void) FormatLocaleString(buffer,MagickPathExtent,"xpm_%.1024s",basename);
1011 (void) CopyMagickString(basename,buffer,MagickPathExtent);
1013 if (isalpha((int) ((unsigned char) basename[0])) == 0)
1015 for (i=1; basename[i] != '\0'; i++)
1016 if (isalnum((int) ((unsigned char) basename[i])) == 0)
1018 (void) FormatLocaleString(buffer,MagickPathExtent,
1019 "static char *%.1024s[] = {\n",basename);
1020 (void) WriteBlobString(image,buffer);
1021 (void) WriteBlobString(image,"/* columns rows colors chars-per-pixel */\n");
1022 (void) FormatLocaleString(buffer,MagickPathExtent,
1023 "\"%.20g %.20g %.20g %.20g \",\n",(double) image->columns,(double)
1024 image->rows,(double) image->colors,(double) characters_per_pixel);
1025 (void) WriteBlobString(image,buffer);
1026 GetPixelInfo(image,&pixel);
1027 for (i=0; i < (ssize_t) image->colors; i++)
1032 pixel=image->colormap[i];
1033 pixel.colorspace=sRGBColorspace;
1035 pixel.alpha=(double) OpaqueAlpha;
1036 (void) QueryColorname(image,&pixel,XPMCompliance,name,exception);
1038 (void) CopyMagickString(name,"None",MagickPathExtent);
1044 for (j=1; j < (ssize_t) characters_per_pixel; j++)
1046 k=((i-k)/MaxCixels) % MaxCixels;
1050 (void) FormatLocaleString(buffer,MagickPathExtent,
1051 "\"%.1024s c %.1024s\",\n",symbol,name);
1052 (void) WriteBlobString(image,buffer);
1057 (void) WriteBlobString(image,"/* pixels */\n");
1058 for (y=0; y < (ssize_t) image->rows; y++)
1060 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
1061 if (p == (const Quantum *) NULL)
1063 (void) WriteBlobString(image,"\"");
1064 for (x=0; x < (ssize_t) image->columns; x++)
1066 k=((ssize_t) GetPixelIndex(image,p) % MaxCixels);
1068 for (j=1; j < (ssize_t) characters_per_pixel; j++)
1070 k=(((int) GetPixelIndex(image,p)-k)/MaxCixels) % MaxCixels;
1074 (void) CopyMagickString(buffer,symbol,MagickPathExtent);
1075 (void) WriteBlobString(image,buffer);
1076 p+=GetPixelChannels(image);
1078 (void) FormatLocaleString(buffer,MagickPathExtent,"\"%.1024s\n",
1079 (y == (ssize_t) (image->rows-1) ? "" : ","));
1080 (void) WriteBlobString(image,buffer);
1081 if (image->previous == (Image *) NULL)
1083 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
1085 if (status == MagickFalse)
1089 (void) WriteBlobString(image,"};\n");
1090 (void) CloseBlob(image);