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)
434 xpm_colors=DestroySplayTree(xpm_colors);
435 xpm_buffer=DestroyString(xpm_buffer);
436 return(DestroyImageList(image));
438 for (y=0; y < (ssize_t) image->rows; y++)
441 if (p == (char *) NULL)
443 r=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
444 if (r == (Quantum *) NULL)
446 for (x=0; x < (ssize_t) image->columns; x++)
448 ssize_t count=CopyXPMColor(key,p,MagickMin(width,MagickPathExtent-1));
449 if (count != (ssize_t) width)
451 j=(ssize_t) GetValueFromSplayTree(xpm_colors,key);
452 if (image->storage_class == PseudoClass)
453 SetPixelIndex(image,(Quantum) j,r);
454 SetPixelViaPixelInfo(image,image->colormap+j,r);
456 r+=GetPixelChannels(image);
458 if (x < (ssize_t) image->columns)
460 if (SyncAuthenticPixels(image,exception) == MagickFalse)
463 if (y < (ssize_t) image->rows)
465 xpm_colors=DestroySplayTree(xpm_colors);
466 xpm_buffer=DestroyString(xpm_buffer);
467 ThrowReaderException(CorruptImageError,"NotEnoughPixelData");
471 Relinquish resources.
473 xpm_buffer=DestroyString(xpm_buffer);
474 xpm_colors=DestroySplayTree(xpm_colors);
475 (void) CloseBlob(image);
476 return(GetFirstImageInList(image));
480 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
484 % R e g i s t e r X P M I m a g e %
488 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
490 % RegisterXPMImage() adds attributes for the XPM image format to
491 % the list of supported formats. The attributes include the image format
492 % tag, a method to read and/or write the format, whether the format
493 % supports the saving of more than one frame to the same file or blob,
494 % whether the format supports native in-memory I/O, and a brief
495 % description of the format.
497 % The format of the RegisterXPMImage method is:
499 % size_t RegisterXPMImage(void)
502 ModuleExport size_t RegisterXPMImage(void)
507 entry=AcquireMagickInfo("XPM","PICON","Personal Icon");
508 entry->decoder=(DecodeImageHandler *) ReadXPMImage;
509 entry->encoder=(EncodeImageHandler *) WritePICONImage;
510 entry->flags^=CoderAdjoinFlag;
511 (void) RegisterMagickInfo(entry);
512 entry=AcquireMagickInfo("XPM","PM","X Windows system pixmap (color)");
513 entry->decoder=(DecodeImageHandler *) ReadXPMImage;
514 entry->encoder=(EncodeImageHandler *) WriteXPMImage;
515 entry->flags^=CoderAdjoinFlag;
516 entry->flags|=CoderStealthFlag;
517 (void) RegisterMagickInfo(entry);
518 entry=AcquireMagickInfo("XPM","XPM","X Windows system pixmap (color)");
519 entry->decoder=(DecodeImageHandler *) ReadXPMImage;
520 entry->encoder=(EncodeImageHandler *) WriteXPMImage;
521 entry->magick=(IsImageFormatHandler *) IsXPM;
522 entry->flags^=CoderAdjoinFlag;
523 (void) RegisterMagickInfo(entry);
524 return(MagickImageCoderSignature);
528 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
532 % U n r e g i s t e r X P M I m a g e %
536 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
538 % UnregisterXPMImage() removes format registrations made by the
539 % XPM module from the list of supported formats.
541 % The format of the UnregisterXPMImage method is:
543 % UnregisterXPMImage(void)
546 ModuleExport void UnregisterXPMImage(void)
548 (void) UnregisterMagickInfo("PICON");
549 (void) UnregisterMagickInfo("PM");
550 (void) UnregisterMagickInfo("XPM");
554 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
558 % W r i t e P I C O N I m a g e %
562 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
564 % WritePICONImage() writes an image to a file in the Personal Icon format.
566 % The format of the WritePICONImage method is:
568 % MagickBooleanType WritePICONImage(const ImageInfo *image_info,
569 % Image *image,ExceptionInfo *exception)
571 % A description of each parameter follows.
573 % o image_info: the image info.
575 % o image: The image.
577 % o exception: return any errors or warnings in this structure.
580 static MagickBooleanType WritePICONImage(const ImageInfo *image_info,
581 Image *image,ExceptionInfo *exception)
583 #define ColormapExtent 155
584 #define GraymapExtent 95
585 #define PiconGeometry "48x48>"
590 0x47, 0x49, 0x46, 0x38, 0x37, 0x61, 0x06, 0x00, 0x05, 0x00, 0xf4, 0x05,
591 0x00, 0x00, 0x00, 0x00, 0x2f, 0x4f, 0x4f, 0x70, 0x80, 0x90, 0x7e, 0x7e,
592 0x7e, 0xdc, 0xdc, 0xdc, 0xff, 0xff, 0xff, 0x00, 0x00, 0x80, 0x00, 0x00,
593 0xff, 0x1e, 0x90, 0xff, 0x87, 0xce, 0xeb, 0xe6, 0xe6, 0xfa, 0x00, 0xff,
594 0xff, 0x80, 0x00, 0x80, 0xb2, 0x22, 0x22, 0x2e, 0x8b, 0x57, 0x32, 0xcd,
595 0x32, 0x00, 0xff, 0x00, 0x98, 0xfb, 0x98, 0xff, 0x00, 0xff, 0xff, 0x00,
596 0x00, 0xff, 0x63, 0x47, 0xff, 0xa5, 0x00, 0xff, 0xd7, 0x00, 0xff, 0xff,
597 0x00, 0xee, 0x82, 0xee, 0xa0, 0x52, 0x2d, 0xcd, 0x85, 0x3f, 0xd2, 0xb4,
598 0x8c, 0xf5, 0xde, 0xb3, 0xff, 0xfa, 0xcd, 0x00, 0x00, 0x00, 0x00, 0x00,
599 0x00, 0x21, 0xf9, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00,
600 0x00, 0x00, 0x06, 0x00, 0x05, 0x00, 0x00, 0x05, 0x18, 0x20, 0x10, 0x08,
601 0x03, 0x51, 0x18, 0x07, 0x92, 0x28, 0x0b, 0xd3, 0x38, 0x0f, 0x14, 0x49,
602 0x13, 0x55, 0x59, 0x17, 0x96, 0x69, 0x1b, 0xd7, 0x85, 0x00, 0x3b,
606 0x47, 0x49, 0x46, 0x38, 0x37, 0x61, 0x04, 0x00, 0x04, 0x00, 0xf3, 0x0f,
607 0x00, 0x00, 0x00, 0x00, 0x12, 0x12, 0x12, 0x21, 0x21, 0x21, 0x33, 0x33,
608 0x33, 0x45, 0x45, 0x45, 0x54, 0x54, 0x54, 0x66, 0x66, 0x66, 0x78, 0x78,
609 0x78, 0x87, 0x87, 0x87, 0x99, 0x99, 0x99, 0xab, 0xab, 0xab, 0xba, 0xba,
610 0xba, 0xcc, 0xcc, 0xcc, 0xde, 0xde, 0xde, 0xed, 0xed, 0xed, 0xff, 0xff,
611 0xff, 0x21, 0xf9, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00,
612 0x00, 0x00, 0x04, 0x00, 0x04, 0x00, 0x00, 0x04, 0x0c, 0x10, 0x04, 0x31,
613 0x48, 0x31, 0x07, 0x25, 0xb5, 0x58, 0x73, 0x4f, 0x04, 0x00, 0x3b,
619 Cixel[MaxCixels+1] = " .XoO+@#$%&*=-;:>,<1234567890qwertyuipasdfghjk"
620 "lzxcvbnmMNBVCZASDFGHJKLPIUYTREWQ!~^/()_`'][{}|";
623 buffer[MagickPathExtent],
624 basename[MagickPathExtent],
625 name[MagickPathExtent],
626 symbol[MagickPathExtent];
648 register const Quantum
659 characters_per_pixel,
668 Open output image file.
670 assert(image_info != (const ImageInfo *) NULL);
671 assert(image_info->signature == MagickCoreSignature);
672 assert(image != (Image *) NULL);
673 assert(image->signature == MagickCoreSignature);
674 if (image->debug != MagickFalse)
675 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
676 assert(exception != (ExceptionInfo *) NULL);
677 assert(exception->signature == MagickCoreSignature);
678 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
679 if (status == MagickFalse)
681 (void) TransformImageColorspace(image,sRGBColorspace,exception);
682 SetGeometry(image,&geometry);
683 (void) ParseMetaGeometry(PiconGeometry,&geometry.x,&geometry.y,
684 &geometry.width,&geometry.height);
685 picon=ResizeImage(image,geometry.width,geometry.height,TriangleFilter,
687 blob_info=CloneImageInfo(image_info);
688 (void) AcquireUniqueFilename(blob_info->filename);
689 if ((image_info->type != TrueColorType) &&
690 (SetImageGray(image,exception) != MagickFalse))
691 affinity_image=BlobToImage(blob_info,Graymap,GraymapExtent,exception);
693 affinity_image=BlobToImage(blob_info,Colormap,ColormapExtent,exception);
694 (void) RelinquishUniqueFileResource(blob_info->filename);
695 blob_info=DestroyImageInfo(blob_info);
696 if ((picon == (Image *) NULL) || (affinity_image == (Image *) NULL))
698 if (affinity_image != (Image *) NULL)
699 affinity_image=DestroyImage(affinity_image);
700 if (picon != (Image *) NULL)
701 picon=DestroyImage(picon);
704 quantize_info=AcquireQuantizeInfo(image_info);
705 status=RemapImage(quantize_info,picon,affinity_image,exception);
706 quantize_info=DestroyQuantizeInfo(quantize_info);
707 affinity_image=DestroyImage(affinity_image);
708 transparent=MagickFalse;
709 if (picon->storage_class == PseudoClass)
711 (void) CompressImageColormap(picon,exception);
712 if (picon->alpha_trait != UndefinedPixelTrait)
713 transparent=MagickTrue;
718 Convert DirectClass to PseudoClass picon.
720 if (picon->alpha_trait != UndefinedPixelTrait)
723 Map all the transparent pixels.
725 for (y=0; y < (ssize_t) picon->rows; y++)
727 q=GetAuthenticPixels(picon,0,y,picon->columns,1,exception);
728 if (q == (Quantum *) NULL)
730 for (x=0; x < (ssize_t) picon->columns; x++)
732 if (GetPixelAlpha(image,q) == (Quantum) TransparentAlpha)
733 transparent=MagickTrue;
735 SetPixelAlpha(picon,OpaqueAlpha,q);
736 q+=GetPixelChannels(picon);
738 if (SyncAuthenticPixels(picon,exception) == MagickFalse)
742 (void) SetImageType(picon,PaletteType,exception);
744 colors=picon->colors;
745 if (transparent != MagickFalse)
748 picon->colormap=(PixelInfo *) ResizeQuantumMemory((void **)
749 picon->colormap,(size_t) colors,sizeof(*picon->colormap));
750 if (picon->colormap == (PixelInfo *) NULL)
751 ThrowWriterException(ResourceLimitError,"MemoryAllocationError");
752 for (y=0; y < (ssize_t) picon->rows; y++)
754 q=GetAuthenticPixels(picon,0,y,picon->columns,1,exception);
755 if (q == (Quantum *) NULL)
757 for (x=0; x < (ssize_t) picon->columns; x++)
759 if (GetPixelAlpha(image,q) == (Quantum) TransparentAlpha)
760 SetPixelIndex(picon,(Quantum) picon->colors,q);
761 q+=GetPixelChannels(picon);
763 if (SyncAuthenticPixels(picon,exception) == MagickFalse)
768 Compute the character per pixel.
770 characters_per_pixel=1;
771 for (k=MaxCixels; (ssize_t) colors > k; k*=MaxCixels)
772 characters_per_pixel++;
776 (void) WriteBlobString(image,"/* XPM */\n");
777 GetPathComponent(picon->filename,BasePath,basename);
778 (void) FormatLocaleString(buffer,MagickPathExtent,
779 "static char *%s[] = {\n",basename);
780 (void) WriteBlobString(image,buffer);
781 (void) WriteBlobString(image,"/* columns rows colors chars-per-pixel */\n");
782 (void) FormatLocaleString(buffer,MagickPathExtent,
783 "\"%.20g %.20g %.20g %.20g\",\n",(double) picon->columns,(double)
784 picon->rows,(double) colors,(double) characters_per_pixel);
785 (void) WriteBlobString(image,buffer);
786 GetPixelInfo(image,&pixel);
787 for (i=0; i < (ssize_t) colors; i++)
792 pixel=picon->colormap[i];
793 pixel.colorspace=sRGBColorspace;
795 pixel.alpha=(double) OpaqueAlpha;
796 (void) QueryColorname(image,&pixel,XPMCompliance,name,exception);
797 if (transparent != MagickFalse)
799 if (i == (ssize_t) (colors-1))
800 (void) CopyMagickString(name,"grey75",MagickPathExtent);
807 for (j=1; j < (ssize_t) characters_per_pixel; j++)
809 k=((i-k)/MaxCixels) % MaxCixels;
813 (void) FormatLocaleString(buffer,MagickPathExtent,"\"%s c %s\",\n",
815 (void) WriteBlobString(image,buffer);
820 (void) WriteBlobString(image,"/* pixels */\n");
821 for (y=0; y < (ssize_t) picon->rows; y++)
823 p=GetVirtualPixels(picon,0,y,picon->columns,1,exception);
824 if (p == (const Quantum *) NULL)
826 (void) WriteBlobString(image,"\"");
827 for (x=0; x < (ssize_t) picon->columns; x++)
829 k=((ssize_t) GetPixelIndex(picon,p) % MaxCixels);
831 for (j=1; j < (ssize_t) characters_per_pixel; j++)
833 k=(((int) GetPixelIndex(picon,p)-k)/MaxCixels) % MaxCixels;
837 (void) CopyMagickString(buffer,symbol,MagickPathExtent);
838 (void) WriteBlobString(image,buffer);
839 p+=GetPixelChannels(picon);
841 (void) FormatLocaleString(buffer,MagickPathExtent,"\"%s\n",
842 y == (ssize_t) (picon->rows-1) ? "" : ",");
843 (void) WriteBlobString(image,buffer);
844 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
846 if (status == MagickFalse)
849 picon=DestroyImage(picon);
850 (void) WriteBlobString(image,"};\n");
851 (void) CloseBlob(image);
856 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
860 % W r i t e X P M I m a g e %
864 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
866 % WriteXPMImage() writes an image to a file in the X pixmap format.
868 % The format of the WriteXPMImage method is:
870 % MagickBooleanType WriteXPMImage(const ImageInfo *image_info,
871 % Image *image,ExceptionInfo *exception)
873 % A description of each parameter follows.
875 % o image_info: the image info.
877 % o image: The image.
879 % o exception: return any errors or warnings in this structure.
882 static MagickBooleanType WriteXPMImage(const ImageInfo *image_info,Image *image,
883 ExceptionInfo *exception)
888 Cixel[MaxCixels+1] = " .XoO+@#$%&*=-;:>,<1234567890qwertyuipasdfghjk"
889 "lzxcvbnmMNBVCZASDFGHJKLPIUYTREWQ!~^/()_`'][{}|";
892 buffer[MagickPathExtent],
893 basename[MagickPathExtent],
894 name[MagickPathExtent],
895 symbol[MagickPathExtent];
903 register const Quantum
911 characters_per_pixel;
920 Open output image file.
922 assert(image_info != (const ImageInfo *) NULL);
923 assert(image_info->signature == MagickCoreSignature);
924 assert(image != (Image *) NULL);
925 assert(image->signature == MagickCoreSignature);
926 if (image->debug != MagickFalse)
927 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
928 assert(exception != (ExceptionInfo *) NULL);
929 assert(exception->signature == MagickCoreSignature);
930 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
931 if (status == MagickFalse)
933 if (IssRGBCompatibleColorspace(image->colorspace) == MagickFalse)
934 (void) TransformImageColorspace(image,sRGBColorspace,exception);
936 if (image->alpha_trait == UndefinedPixelTrait)
938 if ((image->storage_class == DirectClass) || (image->colors > 256))
939 (void) SetImageType(image,PaletteType,exception);
948 Identify transparent colormap index.
950 if ((image->storage_class == DirectClass) || (image->colors > 256))
951 (void) SetImageType(image,PaletteBilevelAlphaType,exception);
952 for (i=0; i < (ssize_t) image->colors; i++)
953 if (image->colormap[i].alpha != OpaqueAlpha)
960 alpha=(double) TransparentAlpha-(double)
961 image->colormap[i].alpha;
962 beta=(double) TransparentAlpha-(double)
963 image->colormap[opacity].alpha;
969 (void) SetImageType(image,PaletteBilevelAlphaType,exception);
970 for (i=0; i < (ssize_t) image->colors; i++)
971 if (image->colormap[i].alpha != OpaqueAlpha)
978 alpha=(Quantum) TransparentAlpha-(double)
979 image->colormap[i].alpha;
980 beta=(Quantum) TransparentAlpha-(double)
981 image->colormap[opacity].alpha;
988 image->colormap[opacity].red=image->transparent_color.red;
989 image->colormap[opacity].green=image->transparent_color.green;
990 image->colormap[opacity].blue=image->transparent_color.blue;
994 Compute the character per pixel.
996 characters_per_pixel=1;
997 for (k=MaxCixels; (ssize_t) image->colors > k; k*=MaxCixels)
998 characters_per_pixel++;
1002 (void) WriteBlobString(image,"/* XPM */\n");
1003 GetPathComponent(image->filename,BasePath,basename);
1004 if (isalnum((int) ((unsigned char) *basename)) == 0)
1006 (void) FormatLocaleString(buffer,MagickPathExtent,"xpm_%s",basename);
1007 (void) CopyMagickString(basename,buffer,MagickPathExtent);
1009 if (isalpha((int) ((unsigned char) basename[0])) == 0)
1011 for (i=1; basename[i] != '\0'; i++)
1012 if (isalnum((int) ((unsigned char) basename[i])) == 0)
1014 (void) FormatLocaleString(buffer,MagickPathExtent,
1015 "static char *%s[] = {\n",basename);
1016 (void) WriteBlobString(image,buffer);
1017 (void) WriteBlobString(image,"/* columns rows colors chars-per-pixel */\n");
1018 (void) FormatLocaleString(buffer,MagickPathExtent,
1019 "\"%.20g %.20g %.20g %.20g \",\n",(double) image->columns,(double)
1020 image->rows,(double) image->colors,(double) characters_per_pixel);
1021 (void) WriteBlobString(image,buffer);
1022 GetPixelInfo(image,&pixel);
1023 for (i=0; i < (ssize_t) image->colors; i++)
1028 pixel=image->colormap[i];
1029 pixel.colorspace=sRGBColorspace;
1031 pixel.alpha=(double) OpaqueAlpha;
1032 (void) QueryColorname(image,&pixel,XPMCompliance,name,exception);
1034 (void) CopyMagickString(name,"None",MagickPathExtent);
1040 for (j=1; j < (ssize_t) characters_per_pixel; j++)
1042 k=((i-k)/MaxCixels) % MaxCixels;
1046 (void) FormatLocaleString(buffer,MagickPathExtent,"\"%s c %s\",\n",symbol,
1048 (void) WriteBlobString(image,buffer);
1053 (void) WriteBlobString(image,"/* pixels */\n");
1054 for (y=0; y < (ssize_t) image->rows; y++)
1056 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
1057 if (p == (const Quantum *) NULL)
1059 (void) WriteBlobString(image,"\"");
1060 for (x=0; x < (ssize_t) image->columns; x++)
1062 k=((ssize_t) GetPixelIndex(image,p) % MaxCixels);
1064 for (j=1; j < (ssize_t) characters_per_pixel; j++)
1066 k=(((int) GetPixelIndex(image,p)-k)/MaxCixels) % MaxCixels;
1070 (void) CopyMagickString(buffer,symbol,MagickPathExtent);
1071 (void) WriteBlobString(image,buffer);
1072 p+=GetPixelChannels(image);
1074 (void) FormatLocaleString(buffer,MagickPathExtent,"\"%s\n",
1075 (y == (ssize_t) (image->rows-1) ? "" : ","));
1076 (void) WriteBlobString(image,buffer);
1077 if (image->previous == (Image *) NULL)
1079 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
1081 if (status == MagickFalse)
1085 (void) WriteBlobString(image,"};\n");
1086 (void) CloseBlob(image);