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_buffer=DestroyString(xpm_buffer);
370 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
376 next=NextXPMLine(xpm_buffer);
377 for (j=0; (j < (ssize_t) image->colors) && (next != (char *) NULL); j++)
381 (void) CopyXPMColor(key,p,MagickMin((size_t) width,MagickPathExtent-1));
382 status=AddValueToSplayTree(xpm_colors,ConstantString(key),(void *) j);
386 (void) CopyMagickString(target,"gray",MagickPathExtent);
387 q=ParseXPMColor(p+width,MagickTrue);
388 if (q != (char *) NULL)
390 while ((isspace((int) ((unsigned char) *q)) == 0) && (*q != '\0'))
394 if (next != (char *) NULL)
395 (void) CopyXPMColor(target,q,MagickMin((size_t) (next-q),
396 MagickPathExtent-1));
398 (void) CopyMagickString(target,q,MagickPathExtent);
399 q=ParseXPMColor(target,MagickFalse);
400 if (q != (char *) NULL)
404 grey=strstr(target,"grey");
405 if (grey != (char *) NULL)
407 if (LocaleCompare(target,"none") == 0)
409 image->storage_class=DirectClass;
410 image->alpha_trait=BlendPixelTrait;
412 status=QueryColorCompliance(target,XPMCompliance,&image->colormap[j],
414 if (status == MagickFalse)
416 if (image->depth < image->colormap[j].depth)
417 image->depth=image->colormap[j].depth;
419 if (j < (ssize_t) image->colors)
421 xpm_colors=DestroySplayTree(xpm_colors);
422 xpm_buffer=DestroyString(xpm_buffer);
423 ThrowReaderException(CorruptImageError,"CorruptImage");
426 if (image_info->ping == MagickFalse)
431 status=SetImageExtent(image,image->columns,image->rows,exception);
432 if (status == MagickFalse)
433 return(DestroyImageList(image));
434 for (y=0; y < (ssize_t) image->rows; y++)
437 if (p == (char *) NULL)
439 r=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
440 if (r == (Quantum *) NULL)
442 for (x=0; x < (ssize_t) image->columns; x++)
444 ssize_t count=CopyXPMColor(key,p,MagickMin(width,MagickPathExtent-1));
445 if (count != (ssize_t) width)
447 j=(ssize_t) GetValueFromSplayTree(xpm_colors,key);
448 if (image->storage_class == PseudoClass)
449 SetPixelIndex(image,(Quantum) j,r);
450 SetPixelViaPixelInfo(image,image->colormap+j,r);
452 r+=GetPixelChannels(image);
454 if (x < (ssize_t) image->columns)
456 if (SyncAuthenticPixels(image,exception) == MagickFalse)
459 if (y < (ssize_t) image->rows)
461 xpm_colors=DestroySplayTree(xpm_colors);
462 xpm_buffer=DestroyString(xpm_buffer);
463 ThrowReaderException(CorruptImageError,"NotEnoughPixelData");
467 Relinquish resources.
469 xpm_buffer=DestroyString(xpm_buffer);
470 xpm_colors=DestroySplayTree(xpm_colors);
471 (void) CloseBlob(image);
472 return(GetFirstImageInList(image));
476 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
480 % R e g i s t e r X P M I m a g e %
484 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
486 % RegisterXPMImage() adds attributes for the XPM image format to
487 % the list of supported formats. The attributes include the image format
488 % tag, a method to read and/or write the format, whether the format
489 % supports the saving of more than one frame to the same file or blob,
490 % whether the format supports native in-memory I/O, and a brief
491 % description of the format.
493 % The format of the RegisterXPMImage method is:
495 % size_t RegisterXPMImage(void)
498 ModuleExport size_t RegisterXPMImage(void)
503 entry=AcquireMagickInfo("XPM","PICON","Personal Icon");
504 entry->decoder=(DecodeImageHandler *) ReadXPMImage;
505 entry->encoder=(EncodeImageHandler *) WritePICONImage;
506 entry->flags^=CoderAdjoinFlag;
507 (void) RegisterMagickInfo(entry);
508 entry=AcquireMagickInfo("XPM","PM","X Windows system pixmap (color)");
509 entry->decoder=(DecodeImageHandler *) ReadXPMImage;
510 entry->encoder=(EncodeImageHandler *) WriteXPMImage;
511 entry->flags^=CoderAdjoinFlag;
512 entry->flags|=CoderStealthFlag;
513 (void) RegisterMagickInfo(entry);
514 entry=AcquireMagickInfo("XPM","XPM","X Windows system pixmap (color)");
515 entry->decoder=(DecodeImageHandler *) ReadXPMImage;
516 entry->encoder=(EncodeImageHandler *) WriteXPMImage;
517 entry->magick=(IsImageFormatHandler *) IsXPM;
518 entry->flags^=CoderAdjoinFlag;
519 (void) RegisterMagickInfo(entry);
520 return(MagickImageCoderSignature);
524 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
528 % U n r e g i s t e r X P M I m a g e %
532 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
534 % UnregisterXPMImage() removes format registrations made by the
535 % XPM module from the list of supported formats.
537 % The format of the UnregisterXPMImage method is:
539 % UnregisterXPMImage(void)
542 ModuleExport void UnregisterXPMImage(void)
544 (void) UnregisterMagickInfo("PICON");
545 (void) UnregisterMagickInfo("PM");
546 (void) UnregisterMagickInfo("XPM");
550 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
554 % W r i t e P I C O N I m a g e %
558 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
560 % WritePICONImage() writes an image to a file in the Personal Icon format.
562 % The format of the WritePICONImage method is:
564 % MagickBooleanType WritePICONImage(const ImageInfo *image_info,
565 % Image *image,ExceptionInfo *exception)
567 % A description of each parameter follows.
569 % o image_info: the image info.
571 % o image: The image.
573 % o exception: return any errors or warnings in this structure.
576 static MagickBooleanType WritePICONImage(const ImageInfo *image_info,
577 Image *image,ExceptionInfo *exception)
579 #define ColormapExtent 155
580 #define GraymapExtent 95
581 #define PiconGeometry "48x48>"
586 0x47, 0x49, 0x46, 0x38, 0x37, 0x61, 0x06, 0x00, 0x05, 0x00, 0xf4, 0x05,
587 0x00, 0x00, 0x00, 0x00, 0x2f, 0x4f, 0x4f, 0x70, 0x80, 0x90, 0x7e, 0x7e,
588 0x7e, 0xdc, 0xdc, 0xdc, 0xff, 0xff, 0xff, 0x00, 0x00, 0x80, 0x00, 0x00,
589 0xff, 0x1e, 0x90, 0xff, 0x87, 0xce, 0xeb, 0xe6, 0xe6, 0xfa, 0x00, 0xff,
590 0xff, 0x80, 0x00, 0x80, 0xb2, 0x22, 0x22, 0x2e, 0x8b, 0x57, 0x32, 0xcd,
591 0x32, 0x00, 0xff, 0x00, 0x98, 0xfb, 0x98, 0xff, 0x00, 0xff, 0xff, 0x00,
592 0x00, 0xff, 0x63, 0x47, 0xff, 0xa5, 0x00, 0xff, 0xd7, 0x00, 0xff, 0xff,
593 0x00, 0xee, 0x82, 0xee, 0xa0, 0x52, 0x2d, 0xcd, 0x85, 0x3f, 0xd2, 0xb4,
594 0x8c, 0xf5, 0xde, 0xb3, 0xff, 0xfa, 0xcd, 0x00, 0x00, 0x00, 0x00, 0x00,
595 0x00, 0x21, 0xf9, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00,
596 0x00, 0x00, 0x06, 0x00, 0x05, 0x00, 0x00, 0x05, 0x18, 0x20, 0x10, 0x08,
597 0x03, 0x51, 0x18, 0x07, 0x92, 0x28, 0x0b, 0xd3, 0x38, 0x0f, 0x14, 0x49,
598 0x13, 0x55, 0x59, 0x17, 0x96, 0x69, 0x1b, 0xd7, 0x85, 0x00, 0x3b,
602 0x47, 0x49, 0x46, 0x38, 0x37, 0x61, 0x04, 0x00, 0x04, 0x00, 0xf3, 0x0f,
603 0x00, 0x00, 0x00, 0x00, 0x12, 0x12, 0x12, 0x21, 0x21, 0x21, 0x33, 0x33,
604 0x33, 0x45, 0x45, 0x45, 0x54, 0x54, 0x54, 0x66, 0x66, 0x66, 0x78, 0x78,
605 0x78, 0x87, 0x87, 0x87, 0x99, 0x99, 0x99, 0xab, 0xab, 0xab, 0xba, 0xba,
606 0xba, 0xcc, 0xcc, 0xcc, 0xde, 0xde, 0xde, 0xed, 0xed, 0xed, 0xff, 0xff,
607 0xff, 0x21, 0xf9, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00,
608 0x00, 0x00, 0x04, 0x00, 0x04, 0x00, 0x00, 0x04, 0x0c, 0x10, 0x04, 0x31,
609 0x48, 0x31, 0x07, 0x25, 0xb5, 0x58, 0x73, 0x4f, 0x04, 0x00, 0x3b,
615 Cixel[MaxCixels+1] = " .XoO+@#$%&*=-;:>,<1234567890qwertyuipasdfghjk"
616 "lzxcvbnmMNBVCZASDFGHJKLPIUYTREWQ!~^/()_`'][{}|";
619 buffer[MagickPathExtent],
620 basename[MagickPathExtent],
621 name[MagickPathExtent],
622 symbol[MagickPathExtent];
644 register const Quantum
655 characters_per_pixel,
664 Open output image file.
666 assert(image_info != (const ImageInfo *) NULL);
667 assert(image_info->signature == MagickCoreSignature);
668 assert(image != (Image *) NULL);
669 assert(image->signature == MagickCoreSignature);
670 if (image->debug != MagickFalse)
671 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
672 assert(exception != (ExceptionInfo *) NULL);
673 assert(exception->signature == MagickCoreSignature);
674 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
675 if (status == MagickFalse)
677 (void) TransformImageColorspace(image,sRGBColorspace,exception);
678 SetGeometry(image,&geometry);
679 (void) ParseMetaGeometry(PiconGeometry,&geometry.x,&geometry.y,
680 &geometry.width,&geometry.height);
681 picon=ResizeImage(image,geometry.width,geometry.height,TriangleFilter,
683 blob_info=CloneImageInfo(image_info);
684 (void) AcquireUniqueFilename(blob_info->filename);
685 if ((image_info->type != TrueColorType) &&
686 (SetImageGray(image,exception) != MagickFalse))
687 affinity_image=BlobToImage(blob_info,Graymap,GraymapExtent,exception);
689 affinity_image=BlobToImage(blob_info,Colormap,ColormapExtent,exception);
690 (void) RelinquishUniqueFileResource(blob_info->filename);
691 blob_info=DestroyImageInfo(blob_info);
692 if ((picon == (Image *) NULL) || (affinity_image == (Image *) NULL))
694 if (affinity_image != (Image *) NULL)
695 affinity_image=DestroyImage(affinity_image);
696 if (picon != (Image *) NULL)
697 picon=DestroyImage(picon);
700 quantize_info=AcquireQuantizeInfo(image_info);
701 status=RemapImage(quantize_info,picon,affinity_image,exception);
702 quantize_info=DestroyQuantizeInfo(quantize_info);
703 affinity_image=DestroyImage(affinity_image);
704 transparent=MagickFalse;
705 if (picon->storage_class == PseudoClass)
707 (void) CompressImageColormap(picon,exception);
708 if (picon->alpha_trait != UndefinedPixelTrait)
709 transparent=MagickTrue;
714 Convert DirectClass to PseudoClass picon.
716 if (picon->alpha_trait != UndefinedPixelTrait)
719 Map all the transparent pixels.
721 for (y=0; y < (ssize_t) picon->rows; y++)
723 q=GetAuthenticPixels(picon,0,y,picon->columns,1,exception);
724 if (q == (Quantum *) NULL)
726 for (x=0; x < (ssize_t) picon->columns; x++)
728 if (GetPixelAlpha(image,q) == (Quantum) TransparentAlpha)
729 transparent=MagickTrue;
731 SetPixelAlpha(picon,OpaqueAlpha,q);
732 q+=GetPixelChannels(picon);
734 if (SyncAuthenticPixels(picon,exception) == MagickFalse)
738 (void) SetImageType(picon,PaletteType,exception);
740 colors=picon->colors;
741 if (transparent != MagickFalse)
744 picon->colormap=(PixelInfo *) ResizeQuantumMemory((void **)
745 picon->colormap,(size_t) colors,sizeof(*picon->colormap));
746 if (picon->colormap == (PixelInfo *) NULL)
747 ThrowWriterException(ResourceLimitError,"MemoryAllocationError");
748 for (y=0; y < (ssize_t) picon->rows; y++)
750 q=GetAuthenticPixels(picon,0,y,picon->columns,1,exception);
751 if (q == (Quantum *) NULL)
753 for (x=0; x < (ssize_t) picon->columns; x++)
755 if (GetPixelAlpha(image,q) == (Quantum) TransparentAlpha)
756 SetPixelIndex(picon,(Quantum) picon->colors,q);
757 q+=GetPixelChannels(picon);
759 if (SyncAuthenticPixels(picon,exception) == MagickFalse)
764 Compute the character per pixel.
766 characters_per_pixel=1;
767 for (k=MaxCixels; (ssize_t) colors > k; k*=MaxCixels)
768 characters_per_pixel++;
772 (void) WriteBlobString(image,"/* XPM */\n");
773 GetPathComponent(picon->filename,BasePath,basename);
774 (void) FormatLocaleString(buffer,MagickPathExtent,
775 "static char *%s[] = {\n",basename);
776 (void) WriteBlobString(image,buffer);
777 (void) WriteBlobString(image,"/* columns rows colors chars-per-pixel */\n");
778 (void) FormatLocaleString(buffer,MagickPathExtent,
779 "\"%.20g %.20g %.20g %.20g\",\n",(double) picon->columns,(double)
780 picon->rows,(double) colors,(double) characters_per_pixel);
781 (void) WriteBlobString(image,buffer);
782 GetPixelInfo(image,&pixel);
783 for (i=0; i < (ssize_t) colors; i++)
788 pixel=picon->colormap[i];
789 pixel.colorspace=sRGBColorspace;
791 pixel.alpha=(double) OpaqueAlpha;
792 (void) QueryColorname(image,&pixel,XPMCompliance,name,exception);
793 if (transparent != MagickFalse)
795 if (i == (ssize_t) (colors-1))
796 (void) CopyMagickString(name,"grey75",MagickPathExtent);
803 for (j=1; j < (ssize_t) characters_per_pixel; j++)
805 k=((i-k)/MaxCixels) % MaxCixels;
809 (void) FormatLocaleString(buffer,MagickPathExtent,"\"%s c %s\",\n",
811 (void) WriteBlobString(image,buffer);
816 (void) WriteBlobString(image,"/* pixels */\n");
817 for (y=0; y < (ssize_t) picon->rows; y++)
819 p=GetVirtualPixels(picon,0,y,picon->columns,1,exception);
820 if (p == (const Quantum *) NULL)
822 (void) WriteBlobString(image,"\"");
823 for (x=0; x < (ssize_t) picon->columns; x++)
825 k=((ssize_t) GetPixelIndex(picon,p) % MaxCixels);
827 for (j=1; j < (ssize_t) characters_per_pixel; j++)
829 k=(((int) GetPixelIndex(picon,p)-k)/MaxCixels) % MaxCixels;
833 (void) CopyMagickString(buffer,symbol,MagickPathExtent);
834 (void) WriteBlobString(image,buffer);
835 p+=GetPixelChannels(picon);
837 (void) FormatLocaleString(buffer,MagickPathExtent,"\"%s\n",
838 y == (ssize_t) (picon->rows-1) ? "" : ",");
839 (void) WriteBlobString(image,buffer);
840 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
842 if (status == MagickFalse)
845 picon=DestroyImage(picon);
846 (void) WriteBlobString(image,"};\n");
847 (void) CloseBlob(image);
852 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
856 % W r i t e X P M I m a g e %
860 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
862 % WriteXPMImage() writes an image to a file in the X pixmap format.
864 % The format of the WriteXPMImage method is:
866 % MagickBooleanType WriteXPMImage(const ImageInfo *image_info,
867 % Image *image,ExceptionInfo *exception)
869 % A description of each parameter follows.
871 % o image_info: the image info.
873 % o image: The image.
875 % o exception: return any errors or warnings in this structure.
878 static MagickBooleanType WriteXPMImage(const ImageInfo *image_info,Image *image,
879 ExceptionInfo *exception)
884 Cixel[MaxCixels+1] = " .XoO+@#$%&*=-;:>,<1234567890qwertyuipasdfghjk"
885 "lzxcvbnmMNBVCZASDFGHJKLPIUYTREWQ!~^/()_`'][{}|";
888 buffer[MagickPathExtent],
889 basename[MagickPathExtent],
890 name[MagickPathExtent],
891 symbol[MagickPathExtent];
899 register const Quantum
907 characters_per_pixel;
916 Open output image file.
918 assert(image_info != (const ImageInfo *) NULL);
919 assert(image_info->signature == MagickCoreSignature);
920 assert(image != (Image *) NULL);
921 assert(image->signature == MagickCoreSignature);
922 if (image->debug != MagickFalse)
923 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
924 assert(exception != (ExceptionInfo *) NULL);
925 assert(exception->signature == MagickCoreSignature);
926 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
927 if (status == MagickFalse)
929 if (IssRGBCompatibleColorspace(image->colorspace) == MagickFalse)
930 (void) TransformImageColorspace(image,sRGBColorspace,exception);
932 if (image->alpha_trait == UndefinedPixelTrait)
934 if ((image->storage_class == DirectClass) || (image->colors > 256))
935 (void) SetImageType(image,PaletteType,exception);
944 Identify transparent colormap index.
946 if ((image->storage_class == DirectClass) || (image->colors > 256))
947 (void) SetImageType(image,PaletteBilevelAlphaType,exception);
948 for (i=0; i < (ssize_t) image->colors; i++)
949 if (image->colormap[i].alpha != OpaqueAlpha)
956 alpha=(double) TransparentAlpha-(double)
957 image->colormap[i].alpha;
958 beta=(double) TransparentAlpha-(double)
959 image->colormap[opacity].alpha;
965 (void) SetImageType(image,PaletteBilevelAlphaType,exception);
966 for (i=0; i < (ssize_t) image->colors; i++)
967 if (image->colormap[i].alpha != OpaqueAlpha)
974 alpha=(Quantum) TransparentAlpha-(double)
975 image->colormap[i].alpha;
976 beta=(Quantum) TransparentAlpha-(double)
977 image->colormap[opacity].alpha;
984 image->colormap[opacity].red=image->transparent_color.red;
985 image->colormap[opacity].green=image->transparent_color.green;
986 image->colormap[opacity].blue=image->transparent_color.blue;
990 Compute the character per pixel.
992 characters_per_pixel=1;
993 for (k=MaxCixels; (ssize_t) image->colors > k; k*=MaxCixels)
994 characters_per_pixel++;
998 (void) WriteBlobString(image,"/* XPM */\n");
999 GetPathComponent(image->filename,BasePath,basename);
1000 if (isalnum((int) ((unsigned char) *basename)) == 0)
1002 (void) FormatLocaleString(buffer,MagickPathExtent,"xpm_%s",basename);
1003 (void) CopyMagickString(basename,buffer,MagickPathExtent);
1005 if (isalpha((int) ((unsigned char) basename[0])) == 0)
1007 for (i=1; basename[i] != '\0'; i++)
1008 if (isalnum((int) ((unsigned char) basename[i])) == 0)
1010 (void) FormatLocaleString(buffer,MagickPathExtent,
1011 "static char *%s[] = {\n",basename);
1012 (void) WriteBlobString(image,buffer);
1013 (void) WriteBlobString(image,"/* columns rows colors chars-per-pixel */\n");
1014 (void) FormatLocaleString(buffer,MagickPathExtent,
1015 "\"%.20g %.20g %.20g %.20g \",\n",(double) image->columns,(double)
1016 image->rows,(double) image->colors,(double) characters_per_pixel);
1017 (void) WriteBlobString(image,buffer);
1018 GetPixelInfo(image,&pixel);
1019 for (i=0; i < (ssize_t) image->colors; i++)
1024 pixel=image->colormap[i];
1025 pixel.colorspace=sRGBColorspace;
1027 pixel.alpha=(double) OpaqueAlpha;
1028 (void) QueryColorname(image,&pixel,XPMCompliance,name,exception);
1030 (void) CopyMagickString(name,"None",MagickPathExtent);
1036 for (j=1; j < (ssize_t) characters_per_pixel; j++)
1038 k=((i-k)/MaxCixels) % MaxCixels;
1042 (void) FormatLocaleString(buffer,MagickPathExtent,"\"%s c %s\",\n",symbol,
1044 (void) WriteBlobString(image,buffer);
1049 (void) WriteBlobString(image,"/* pixels */\n");
1050 for (y=0; y < (ssize_t) image->rows; y++)
1052 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
1053 if (p == (const Quantum *) NULL)
1055 (void) WriteBlobString(image,"\"");
1056 for (x=0; x < (ssize_t) image->columns; x++)
1058 k=((ssize_t) GetPixelIndex(image,p) % MaxCixels);
1060 for (j=1; j < (ssize_t) characters_per_pixel; j++)
1062 k=(((int) GetPixelIndex(image,p)-k)/MaxCixels) % MaxCixels;
1066 (void) CopyMagickString(buffer,symbol,MagickPathExtent);
1067 (void) WriteBlobString(image,buffer);
1068 p+=GetPixelChannels(image);
1070 (void) FormatLocaleString(buffer,MagickPathExtent,"\"%s\n",
1071 (y == (ssize_t) (image->rows-1) ? "" : ","));
1072 (void) WriteBlobString(image,buffer);
1073 if (image->previous == (Image *) NULL)
1075 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
1077 if (status == MagickFalse)
1081 (void) WriteBlobString(image,"};\n");
1082 (void) CloseBlob(image);