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 > 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 quantize_info=AcquireQuantizeInfo(image_info);
695 status=RemapImage(quantize_info,picon,affinity_image,exception);
696 quantize_info=DestroyQuantizeInfo(quantize_info);
697 affinity_image=DestroyImage(affinity_image);
698 transparent=MagickFalse;
699 if (picon->storage_class == PseudoClass)
701 (void) CompressImageColormap(picon,exception);
702 if (picon->alpha_trait != UndefinedPixelTrait)
703 transparent=MagickTrue;
708 Convert DirectClass to PseudoClass picon.
710 if (picon->alpha_trait != UndefinedPixelTrait)
713 Map all the transparent pixels.
715 for (y=0; y < (ssize_t) picon->rows; y++)
717 q=GetAuthenticPixels(picon,0,y,picon->columns,1,exception);
718 if (q == (Quantum *) NULL)
720 for (x=0; x < (ssize_t) picon->columns; x++)
722 if (GetPixelAlpha(image,q) == (Quantum) TransparentAlpha)
723 transparent=MagickTrue;
725 SetPixelAlpha(picon,OpaqueAlpha,q);
726 q+=GetPixelChannels(picon);
728 if (SyncAuthenticPixels(picon,exception) == MagickFalse)
732 (void) SetImageType(picon,PaletteType,exception);
734 colors=picon->colors;
735 if (transparent != MagickFalse)
738 picon->colormap=(PixelInfo *) ResizeQuantumMemory((void **)
739 picon->colormap,(size_t) colors,sizeof(*picon->colormap));
740 if (picon->colormap == (PixelInfo *) NULL)
741 ThrowWriterException(ResourceLimitError,"MemoryAllocationError");
742 for (y=0; y < (ssize_t) picon->rows; y++)
744 q=GetAuthenticPixels(picon,0,y,picon->columns,1,exception);
745 if (q == (Quantum *) NULL)
747 for (x=0; x < (ssize_t) picon->columns; x++)
749 if (GetPixelAlpha(image,q) == (Quantum) TransparentAlpha)
750 SetPixelIndex(picon,(Quantum) picon->colors,q);
751 q+=GetPixelChannels(picon);
753 if (SyncAuthenticPixels(picon,exception) == MagickFalse)
758 Compute the character per pixel.
760 characters_per_pixel=1;
761 for (k=MaxCixels; (ssize_t) colors > k; k*=MaxCixels)
762 characters_per_pixel++;
766 (void) WriteBlobString(image,"/* XPM */\n");
767 GetPathComponent(picon->filename,BasePath,basename);
768 (void) FormatLocaleString(buffer,MagickPathExtent,
769 "static char *%s[] = {\n",basename);
770 (void) WriteBlobString(image,buffer);
771 (void) WriteBlobString(image,"/* columns rows colors chars-per-pixel */\n");
772 (void) FormatLocaleString(buffer,MagickPathExtent,
773 "\"%.20g %.20g %.20g %.20g\",\n",(double) picon->columns,(double)
774 picon->rows,(double) colors,(double) characters_per_pixel);
775 (void) WriteBlobString(image,buffer);
776 GetPixelInfo(image,&pixel);
777 for (i=0; i < (ssize_t) colors; i++)
782 pixel=picon->colormap[i];
783 pixel.colorspace=sRGBColorspace;
785 pixel.alpha=(double) OpaqueAlpha;
786 (void) QueryColorname(image,&pixel,XPMCompliance,name,exception);
787 if (transparent != MagickFalse)
789 if (i == (ssize_t) (colors-1))
790 (void) CopyMagickString(name,"grey75",MagickPathExtent);
797 for (j=1; j < (ssize_t) characters_per_pixel; j++)
799 k=((i-k)/MaxCixels) % MaxCixels;
803 (void) FormatLocaleString(buffer,MagickPathExtent,"\"%s c %s\",\n",
805 (void) WriteBlobString(image,buffer);
810 (void) WriteBlobString(image,"/* pixels */\n");
811 for (y=0; y < (ssize_t) picon->rows; y++)
813 p=GetVirtualPixels(picon,0,y,picon->columns,1,exception);
814 if (p == (const Quantum *) NULL)
816 (void) WriteBlobString(image,"\"");
817 for (x=0; x < (ssize_t) picon->columns; x++)
819 k=((ssize_t) GetPixelIndex(picon,p) % MaxCixels);
821 for (j=1; j < (ssize_t) characters_per_pixel; j++)
823 k=(((int) GetPixelIndex(picon,p)-k)/MaxCixels) % MaxCixels;
827 (void) CopyMagickString(buffer,symbol,MagickPathExtent);
828 (void) WriteBlobString(image,buffer);
829 p+=GetPixelChannels(image);
831 (void) FormatLocaleString(buffer,MagickPathExtent,"\"%s\n",
832 y == (ssize_t) (picon->rows-1) ? "" : ",");
833 (void) WriteBlobString(image,buffer);
834 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
836 if (status == MagickFalse)
839 picon=DestroyImage(picon);
840 (void) WriteBlobString(image,"};\n");
841 (void) CloseBlob(image);
846 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
850 % W r i t e X P M I m a g e %
854 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
856 % WriteXPMImage() writes an image to a file in the X pixmap format.
858 % The format of the WriteXPMImage method is:
860 % MagickBooleanType WriteXPMImage(const ImageInfo *image_info,
861 % Image *image,ExceptionInfo *exception)
863 % A description of each parameter follows.
865 % o image_info: the image info.
867 % o image: The image.
869 % o exception: return any errors or warnings in this structure.
872 static MagickBooleanType WriteXPMImage(const ImageInfo *image_info,Image *image,
873 ExceptionInfo *exception)
878 Cixel[MaxCixels+1] = " .XoO+@#$%&*=-;:>,<1234567890qwertyuipasdfghjk"
879 "lzxcvbnmMNBVCZASDFGHJKLPIUYTREWQ!~^/()_`'][{}|";
882 buffer[MagickPathExtent],
883 basename[MagickPathExtent],
884 name[MagickPathExtent],
885 symbol[MagickPathExtent];
893 register const Quantum
901 characters_per_pixel;
910 Open output image file.
912 assert(image_info != (const ImageInfo *) NULL);
913 assert(image_info->signature == MagickCoreSignature);
914 assert(image != (Image *) NULL);
915 assert(image->signature == MagickCoreSignature);
916 if (image->debug != MagickFalse)
917 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
918 assert(exception != (ExceptionInfo *) NULL);
919 assert(exception->signature == MagickCoreSignature);
920 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
921 if (status == MagickFalse)
923 if (IssRGBCompatibleColorspace(image->colorspace) == MagickFalse)
924 (void) TransformImageColorspace(image,sRGBColorspace,exception);
926 if (image->alpha_trait == UndefinedPixelTrait)
928 if ((image->storage_class == DirectClass) || (image->colors > 256))
929 (void) SetImageType(image,PaletteType,exception);
938 Identify transparent colormap index.
940 if ((image->storage_class == DirectClass) || (image->colors > 256))
941 (void) SetImageType(image,PaletteBilevelAlphaType,exception);
942 for (i=0; i < (ssize_t) image->colors; i++)
943 if (image->colormap[i].alpha != OpaqueAlpha)
950 alpha=(double) TransparentAlpha-(double)
951 image->colormap[i].alpha;
952 beta=(double) TransparentAlpha-(double)
953 image->colormap[opacity].alpha;
959 (void) SetImageType(image,PaletteBilevelAlphaType,exception);
960 for (i=0; i < (ssize_t) image->colors; i++)
961 if (image->colormap[i].alpha != OpaqueAlpha)
968 alpha=(Quantum) TransparentAlpha-(double)
969 image->colormap[i].alpha;
970 beta=(Quantum) TransparentAlpha-(double)
971 image->colormap[opacity].alpha;
978 image->colormap[opacity].red=image->transparent_color.red;
979 image->colormap[opacity].green=image->transparent_color.green;
980 image->colormap[opacity].blue=image->transparent_color.blue;
984 Compute the character per pixel.
986 characters_per_pixel=1;
987 for (k=MaxCixels; (ssize_t) image->colors > k; k*=MaxCixels)
988 characters_per_pixel++;
992 (void) WriteBlobString(image,"/* XPM */\n");
993 GetPathComponent(image->filename,BasePath,basename);
994 if (isalnum((int) ((unsigned char) *basename)) == 0)
996 (void) FormatLocaleString(buffer,MagickPathExtent,"xpm_%s",basename);
997 (void) CopyMagickString(basename,buffer,MagickPathExtent);
999 if (isalpha((int) ((unsigned char) basename[0])) == 0)
1001 for (i=1; basename[i] != '\0'; i++)
1002 if (isalnum((int) ((unsigned char) basename[i])) == 0)
1004 (void) FormatLocaleString(buffer,MagickPathExtent,
1005 "static char *%s[] = {\n",basename);
1006 (void) WriteBlobString(image,buffer);
1007 (void) WriteBlobString(image,"/* columns rows colors chars-per-pixel */\n");
1008 (void) FormatLocaleString(buffer,MagickPathExtent,
1009 "\"%.20g %.20g %.20g %.20g \",\n",(double) image->columns,(double)
1010 image->rows,(double) image->colors,(double) characters_per_pixel);
1011 (void) WriteBlobString(image,buffer);
1012 GetPixelInfo(image,&pixel);
1013 for (i=0; i < (ssize_t) image->colors; i++)
1018 pixel=image->colormap[i];
1019 pixel.colorspace=sRGBColorspace;
1021 pixel.alpha=(double) OpaqueAlpha;
1022 (void) QueryColorname(image,&pixel,XPMCompliance,name,exception);
1024 (void) CopyMagickString(name,"None",MagickPathExtent);
1030 for (j=1; j < (ssize_t) characters_per_pixel; j++)
1032 k=((i-k)/MaxCixels) % MaxCixels;
1036 (void) FormatLocaleString(buffer,MagickPathExtent,"\"%s c %s\",\n",symbol,
1038 (void) WriteBlobString(image,buffer);
1043 (void) WriteBlobString(image,"/* pixels */\n");
1044 for (y=0; y < (ssize_t) image->rows; y++)
1046 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
1047 if (p == (const Quantum *) NULL)
1049 (void) WriteBlobString(image,"\"");
1050 for (x=0; x < (ssize_t) image->columns; x++)
1052 k=((ssize_t) GetPixelIndex(image,p) % MaxCixels);
1054 for (j=1; j < (ssize_t) characters_per_pixel; j++)
1056 k=(((int) GetPixelIndex(image,p)-k)/MaxCixels) % MaxCixels;
1060 (void) CopyMagickString(buffer,symbol,MagickPathExtent);
1061 (void) WriteBlobString(image,buffer);
1062 p+=GetPixelChannels(image);
1064 (void) FormatLocaleString(buffer,MagickPathExtent,"\"%s\n",
1065 (y == (ssize_t) (image->rows-1) ? "" : ","));
1066 (void) WriteBlobString(image,buffer);
1067 if (image->previous == (Image *) NULL)
1069 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
1071 if (status == MagickFalse)
1075 (void) WriteBlobString(image,"};\n");
1076 (void) CloseBlob(image);