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) != 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 if (next != (char *) NULL)
402 (void) CopyXPMColor(target,q,MagickMin((size_t) (next-q),
403 MagickPathExtent-1));
405 (void) CopyMagickString(target,q,MagickPathExtent);
406 q=ParseXPMColor(target,MagickFalse);
407 if (q != (char *) NULL)
411 grey=strstr(target,"grey");
412 if (grey != (char *) NULL)
414 if (LocaleCompare(target,"none") == 0)
416 image->storage_class=DirectClass;
417 image->alpha_trait=BlendPixelTrait;
419 status=QueryColorCompliance(target,XPMCompliance,&image->colormap[j],
421 if (status == MagickFalse)
423 if (image->depth < image->colormap[j].depth)
424 image->depth=image->colormap[j].depth;
426 if (j < (ssize_t) image->colors)
428 xpm_colors=DestroySplayTree(xpm_colors);
429 xpm_buffer=DestroyString(xpm_buffer);
430 ThrowReaderException(CorruptImageError,"CorruptImage");
433 if (image_info->ping == MagickFalse)
438 status=SetImageExtent(image,image->columns,image->rows,exception);
439 if (status == MagickFalse)
441 xpm_colors=DestroySplayTree(xpm_colors);
442 xpm_buffer=DestroyString(xpm_buffer);
443 return(DestroyImageList(image));
445 for (y=0; y < (ssize_t) image->rows; y++)
448 if (p == (char *) NULL)
450 r=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
451 if (r == (Quantum *) NULL)
453 for (x=0; x < (ssize_t) image->columns; x++)
455 ssize_t count=CopyXPMColor(key,p,MagickMin(width,MagickPathExtent-1));
456 if (count != (ssize_t) width)
458 j=(ssize_t) GetValueFromSplayTree(xpm_colors,key);
459 if (image->storage_class == PseudoClass)
460 SetPixelIndex(image,(Quantum) j,r);
461 SetPixelViaPixelInfo(image,image->colormap+j,r);
463 r+=GetPixelChannels(image);
465 if (x < (ssize_t) image->columns)
467 if (SyncAuthenticPixels(image,exception) == MagickFalse)
470 if (y < (ssize_t) image->rows)
472 xpm_colors=DestroySplayTree(xpm_colors);
473 xpm_buffer=DestroyString(xpm_buffer);
474 ThrowReaderException(CorruptImageError,"NotEnoughPixelData");
478 Relinquish resources.
480 xpm_buffer=DestroyString(xpm_buffer);
481 xpm_colors=DestroySplayTree(xpm_colors);
482 (void) CloseBlob(image);
483 return(GetFirstImageInList(image));
487 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
491 % R e g i s t e r X P M I m a g e %
495 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
497 % RegisterXPMImage() adds attributes for the XPM image format to
498 % the list of supported formats. The attributes include the image format
499 % tag, a method to read and/or write the format, whether the format
500 % supports the saving of more than one frame to the same file or blob,
501 % whether the format supports native in-memory I/O, and a brief
502 % description of the format.
504 % The format of the RegisterXPMImage method is:
506 % size_t RegisterXPMImage(void)
509 ModuleExport size_t RegisterXPMImage(void)
514 entry=AcquireMagickInfo("XPM","PICON","Personal Icon");
515 entry->decoder=(DecodeImageHandler *) ReadXPMImage;
516 entry->encoder=(EncodeImageHandler *) WritePICONImage;
517 entry->flags^=CoderAdjoinFlag;
518 (void) RegisterMagickInfo(entry);
519 entry=AcquireMagickInfo("XPM","PM","X Windows system pixmap (color)");
520 entry->decoder=(DecodeImageHandler *) ReadXPMImage;
521 entry->encoder=(EncodeImageHandler *) WriteXPMImage;
522 entry->flags^=CoderAdjoinFlag;
523 entry->flags|=CoderStealthFlag;
524 (void) RegisterMagickInfo(entry);
525 entry=AcquireMagickInfo("XPM","XPM","X Windows system pixmap (color)");
526 entry->decoder=(DecodeImageHandler *) ReadXPMImage;
527 entry->encoder=(EncodeImageHandler *) WriteXPMImage;
528 entry->magick=(IsImageFormatHandler *) IsXPM;
529 entry->flags^=CoderAdjoinFlag;
530 (void) RegisterMagickInfo(entry);
531 return(MagickImageCoderSignature);
535 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
539 % U n r e g i s t e r X P M I m a g e %
543 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
545 % UnregisterXPMImage() removes format registrations made by the
546 % XPM module from the list of supported formats.
548 % The format of the UnregisterXPMImage method is:
550 % UnregisterXPMImage(void)
553 ModuleExport void UnregisterXPMImage(void)
555 (void) UnregisterMagickInfo("PICON");
556 (void) UnregisterMagickInfo("PM");
557 (void) UnregisterMagickInfo("XPM");
561 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
565 % W r i t e P I C O N I m a g e %
569 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
571 % WritePICONImage() writes an image to a file in the Personal Icon format.
573 % The format of the WritePICONImage method is:
575 % MagickBooleanType WritePICONImage(const ImageInfo *image_info,
576 % Image *image,ExceptionInfo *exception)
578 % A description of each parameter follows.
580 % o image_info: the image info.
582 % o image: The image.
584 % o exception: return any errors or warnings in this structure.
587 static MagickBooleanType WritePICONImage(const ImageInfo *image_info,
588 Image *image,ExceptionInfo *exception)
590 #define ColormapExtent 155
591 #define GraymapExtent 95
592 #define PiconGeometry "48x48>"
597 0x47, 0x49, 0x46, 0x38, 0x37, 0x61, 0x06, 0x00, 0x05, 0x00, 0xf4, 0x05,
598 0x00, 0x00, 0x00, 0x00, 0x2f, 0x4f, 0x4f, 0x70, 0x80, 0x90, 0x7e, 0x7e,
599 0x7e, 0xdc, 0xdc, 0xdc, 0xff, 0xff, 0xff, 0x00, 0x00, 0x80, 0x00, 0x00,
600 0xff, 0x1e, 0x90, 0xff, 0x87, 0xce, 0xeb, 0xe6, 0xe6, 0xfa, 0x00, 0xff,
601 0xff, 0x80, 0x00, 0x80, 0xb2, 0x22, 0x22, 0x2e, 0x8b, 0x57, 0x32, 0xcd,
602 0x32, 0x00, 0xff, 0x00, 0x98, 0xfb, 0x98, 0xff, 0x00, 0xff, 0xff, 0x00,
603 0x00, 0xff, 0x63, 0x47, 0xff, 0xa5, 0x00, 0xff, 0xd7, 0x00, 0xff, 0xff,
604 0x00, 0xee, 0x82, 0xee, 0xa0, 0x52, 0x2d, 0xcd, 0x85, 0x3f, 0xd2, 0xb4,
605 0x8c, 0xf5, 0xde, 0xb3, 0xff, 0xfa, 0xcd, 0x00, 0x00, 0x00, 0x00, 0x00,
606 0x00, 0x21, 0xf9, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00,
607 0x00, 0x00, 0x06, 0x00, 0x05, 0x00, 0x00, 0x05, 0x18, 0x20, 0x10, 0x08,
608 0x03, 0x51, 0x18, 0x07, 0x92, 0x28, 0x0b, 0xd3, 0x38, 0x0f, 0x14, 0x49,
609 0x13, 0x55, 0x59, 0x17, 0x96, 0x69, 0x1b, 0xd7, 0x85, 0x00, 0x3b,
613 0x47, 0x49, 0x46, 0x38, 0x37, 0x61, 0x04, 0x00, 0x04, 0x00, 0xf3, 0x0f,
614 0x00, 0x00, 0x00, 0x00, 0x12, 0x12, 0x12, 0x21, 0x21, 0x21, 0x33, 0x33,
615 0x33, 0x45, 0x45, 0x45, 0x54, 0x54, 0x54, 0x66, 0x66, 0x66, 0x78, 0x78,
616 0x78, 0x87, 0x87, 0x87, 0x99, 0x99, 0x99, 0xab, 0xab, 0xab, 0xba, 0xba,
617 0xba, 0xcc, 0xcc, 0xcc, 0xde, 0xde, 0xde, 0xed, 0xed, 0xed, 0xff, 0xff,
618 0xff, 0x21, 0xf9, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00,
619 0x00, 0x00, 0x04, 0x00, 0x04, 0x00, 0x00, 0x04, 0x0c, 0x10, 0x04, 0x31,
620 0x48, 0x31, 0x07, 0x25, 0xb5, 0x58, 0x73, 0x4f, 0x04, 0x00, 0x3b,
626 Cixel[MaxCixels+1] = " .XoO+@#$%&*=-;:>,<1234567890qwertyuipasdfghjk"
627 "lzxcvbnmMNBVCZASDFGHJKLPIUYTREWQ!~^/()_`'][{}|";
630 buffer[MagickPathExtent],
631 basename[MagickPathExtent],
632 name[MagickPathExtent],
633 symbol[MagickPathExtent];
655 register const Quantum
666 characters_per_pixel,
675 Open output image file.
677 assert(image_info != (const ImageInfo *) NULL);
678 assert(image_info->signature == MagickCoreSignature);
679 assert(image != (Image *) NULL);
680 assert(image->signature == MagickCoreSignature);
681 if (image->debug != MagickFalse)
682 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
683 assert(exception != (ExceptionInfo *) NULL);
684 assert(exception->signature == MagickCoreSignature);
685 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
686 if (status == MagickFalse)
688 (void) TransformImageColorspace(image,sRGBColorspace,exception);
689 SetGeometry(image,&geometry);
690 (void) ParseMetaGeometry(PiconGeometry,&geometry.x,&geometry.y,
691 &geometry.width,&geometry.height);
692 picon=ResizeImage(image,geometry.width,geometry.height,TriangleFilter,
694 blob_info=CloneImageInfo(image_info);
695 (void) AcquireUniqueFilename(blob_info->filename);
696 if ((image_info->type != TrueColorType) &&
697 (SetImageGray(image,exception) != MagickFalse))
698 affinity_image=BlobToImage(blob_info,Graymap,GraymapExtent,exception);
700 affinity_image=BlobToImage(blob_info,Colormap,ColormapExtent,exception);
701 (void) RelinquishUniqueFileResource(blob_info->filename);
702 blob_info=DestroyImageInfo(blob_info);
703 if ((picon == (Image *) NULL) || (affinity_image == (Image *) NULL))
705 if (affinity_image != (Image *) NULL)
706 affinity_image=DestroyImage(affinity_image);
707 if (picon != (Image *) NULL)
708 picon=DestroyImage(picon);
711 quantize_info=AcquireQuantizeInfo(image_info);
712 status=RemapImage(quantize_info,picon,affinity_image,exception);
713 quantize_info=DestroyQuantizeInfo(quantize_info);
714 affinity_image=DestroyImage(affinity_image);
715 transparent=MagickFalse;
716 if (picon->storage_class == PseudoClass)
718 (void) CompressImageColormap(picon,exception);
719 if (picon->alpha_trait != UndefinedPixelTrait)
720 transparent=MagickTrue;
725 Convert DirectClass to PseudoClass picon.
727 if (picon->alpha_trait != UndefinedPixelTrait)
730 Map all the transparent pixels.
732 for (y=0; y < (ssize_t) picon->rows; y++)
734 q=GetAuthenticPixels(picon,0,y,picon->columns,1,exception);
735 if (q == (Quantum *) NULL)
737 for (x=0; x < (ssize_t) picon->columns; x++)
739 if (GetPixelAlpha(image,q) == (Quantum) TransparentAlpha)
740 transparent=MagickTrue;
742 SetPixelAlpha(picon,OpaqueAlpha,q);
743 q+=GetPixelChannels(picon);
745 if (SyncAuthenticPixels(picon,exception) == MagickFalse)
749 (void) SetImageType(picon,PaletteType,exception);
751 colors=picon->colors;
752 if (transparent != MagickFalse)
755 picon->colormap=(PixelInfo *) ResizeQuantumMemory((void **)
756 picon->colormap,(size_t) colors,sizeof(*picon->colormap));
757 if (picon->colormap == (PixelInfo *) NULL)
758 ThrowWriterException(ResourceLimitError,"MemoryAllocationError");
759 for (y=0; y < (ssize_t) picon->rows; y++)
761 q=GetAuthenticPixels(picon,0,y,picon->columns,1,exception);
762 if (q == (Quantum *) NULL)
764 for (x=0; x < (ssize_t) picon->columns; x++)
766 if (GetPixelAlpha(image,q) == (Quantum) TransparentAlpha)
767 SetPixelIndex(picon,(Quantum) picon->colors,q);
768 q+=GetPixelChannels(picon);
770 if (SyncAuthenticPixels(picon,exception) == MagickFalse)
775 Compute the character per pixel.
777 characters_per_pixel=1;
778 for (k=MaxCixels; (ssize_t) colors > k; k*=MaxCixels)
779 characters_per_pixel++;
783 (void) WriteBlobString(image,"/* XPM */\n");
784 GetPathComponent(picon->filename,BasePath,basename);
785 (void) FormatLocaleString(buffer,MagickPathExtent,
786 "static char *%.1024s[] = {\n",basename);
787 (void) WriteBlobString(image,buffer);
788 (void) WriteBlobString(image,"/* columns rows colors chars-per-pixel */\n");
789 (void) FormatLocaleString(buffer,MagickPathExtent,
790 "\"%.20g %.20g %.20g %.20g\",\n",(double) picon->columns,(double)
791 picon->rows,(double) colors,(double) characters_per_pixel);
792 (void) WriteBlobString(image,buffer);
793 GetPixelInfo(image,&pixel);
794 for (i=0; i < (ssize_t) colors; i++)
799 pixel=picon->colormap[i];
800 pixel.colorspace=sRGBColorspace;
802 pixel.alpha=(double) OpaqueAlpha;
803 (void) QueryColorname(image,&pixel,XPMCompliance,name,exception);
804 if (transparent != MagickFalse)
806 if (i == (ssize_t) (colors-1))
807 (void) CopyMagickString(name,"grey75",MagickPathExtent);
814 for (j=1; j < (ssize_t) characters_per_pixel; j++)
816 k=((i-k)/MaxCixels) % MaxCixels;
820 (void) FormatLocaleString(buffer,MagickPathExtent,
821 "\"%.1024s c %.1024s\",\n",symbol,name);
822 (void) WriteBlobString(image,buffer);
827 (void) WriteBlobString(image,"/* pixels */\n");
828 for (y=0; y < (ssize_t) picon->rows; y++)
830 p=GetVirtualPixels(picon,0,y,picon->columns,1,exception);
831 if (p == (const Quantum *) NULL)
833 (void) WriteBlobString(image,"\"");
834 for (x=0; x < (ssize_t) picon->columns; x++)
836 k=((ssize_t) GetPixelIndex(picon,p) % MaxCixels);
838 for (j=1; j < (ssize_t) characters_per_pixel; j++)
840 k=(((int) GetPixelIndex(picon,p)-k)/MaxCixels) % MaxCixels;
844 (void) CopyMagickString(buffer,symbol,MagickPathExtent);
845 (void) WriteBlobString(image,buffer);
846 p+=GetPixelChannels(picon);
848 (void) FormatLocaleString(buffer,MagickPathExtent,"\"%.1024s\n",
849 y == (ssize_t) (picon->rows-1) ? "" : ",");
850 (void) WriteBlobString(image,buffer);
851 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
853 if (status == MagickFalse)
856 picon=DestroyImage(picon);
857 (void) WriteBlobString(image,"};\n");
858 (void) CloseBlob(image);
863 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
867 % W r i t e X P M I m a g e %
871 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
873 % WriteXPMImage() writes an image to a file in the X pixmap format.
875 % The format of the WriteXPMImage method is:
877 % MagickBooleanType WriteXPMImage(const ImageInfo *image_info,
878 % Image *image,ExceptionInfo *exception)
880 % A description of each parameter follows.
882 % o image_info: the image info.
884 % o image: The image.
886 % o exception: return any errors or warnings in this structure.
889 static MagickBooleanType WriteXPMImage(const ImageInfo *image_info,Image *image,
890 ExceptionInfo *exception)
895 Cixel[MaxCixels+1] = " .XoO+@#$%&*=-;:>,<1234567890qwertyuipasdfghjk"
896 "lzxcvbnmMNBVCZASDFGHJKLPIUYTREWQ!~^/()_`'][{}|";
899 buffer[MagickPathExtent],
900 basename[MagickPathExtent],
901 name[MagickPathExtent],
902 symbol[MagickPathExtent];
910 register const Quantum
918 characters_per_pixel;
927 Open output image file.
929 assert(image_info != (const ImageInfo *) NULL);
930 assert(image_info->signature == MagickCoreSignature);
931 assert(image != (Image *) NULL);
932 assert(image->signature == MagickCoreSignature);
933 if (image->debug != MagickFalse)
934 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
935 assert(exception != (ExceptionInfo *) NULL);
936 assert(exception->signature == MagickCoreSignature);
937 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
938 if (status == MagickFalse)
940 if (IssRGBCompatibleColorspace(image->colorspace) == MagickFalse)
941 (void) TransformImageColorspace(image,sRGBColorspace,exception);
943 if (image->alpha_trait == UndefinedPixelTrait)
945 if ((image->storage_class == DirectClass) || (image->colors > 256))
946 (void) SetImageType(image,PaletteType,exception);
955 Identify transparent colormap index.
957 if ((image->storage_class == DirectClass) || (image->colors > 256))
958 (void) SetImageType(image,PaletteBilevelAlphaType,exception);
959 for (i=0; i < (ssize_t) image->colors; i++)
960 if (image->colormap[i].alpha != OpaqueAlpha)
967 alpha=(double) TransparentAlpha-(double)
968 image->colormap[i].alpha;
969 beta=(double) TransparentAlpha-(double)
970 image->colormap[opacity].alpha;
976 (void) SetImageType(image,PaletteBilevelAlphaType,exception);
977 for (i=0; i < (ssize_t) image->colors; i++)
978 if (image->colormap[i].alpha != OpaqueAlpha)
985 alpha=(Quantum) TransparentAlpha-(double)
986 image->colormap[i].alpha;
987 beta=(Quantum) TransparentAlpha-(double)
988 image->colormap[opacity].alpha;
995 image->colormap[opacity].red=image->transparent_color.red;
996 image->colormap[opacity].green=image->transparent_color.green;
997 image->colormap[opacity].blue=image->transparent_color.blue;
1001 Compute the character per pixel.
1003 characters_per_pixel=1;
1004 for (k=MaxCixels; (ssize_t) image->colors > k; k*=MaxCixels)
1005 characters_per_pixel++;
1009 (void) WriteBlobString(image,"/* XPM */\n");
1010 GetPathComponent(image->filename,BasePath,basename);
1011 if (isalnum((int) ((unsigned char) *basename)) == 0)
1013 (void) FormatLocaleString(buffer,MagickPathExtent,"xpm_%.1024s",basename);
1014 (void) CopyMagickString(basename,buffer,MagickPathExtent);
1016 if (isalpha((int) ((unsigned char) basename[0])) == 0)
1018 for (i=1; basename[i] != '\0'; i++)
1019 if (isalnum((int) ((unsigned char) basename[i])) == 0)
1021 (void) FormatLocaleString(buffer,MagickPathExtent,
1022 "static char *%.1024s[] = {\n",basename);
1023 (void) WriteBlobString(image,buffer);
1024 (void) WriteBlobString(image,"/* columns rows colors chars-per-pixel */\n");
1025 (void) FormatLocaleString(buffer,MagickPathExtent,
1026 "\"%.20g %.20g %.20g %.20g \",\n",(double) image->columns,(double)
1027 image->rows,(double) image->colors,(double) characters_per_pixel);
1028 (void) WriteBlobString(image,buffer);
1029 GetPixelInfo(image,&pixel);
1030 for (i=0; i < (ssize_t) image->colors; i++)
1035 pixel=image->colormap[i];
1036 pixel.colorspace=sRGBColorspace;
1038 pixel.alpha=(double) OpaqueAlpha;
1039 (void) QueryColorname(image,&pixel,XPMCompliance,name,exception);
1041 (void) CopyMagickString(name,"None",MagickPathExtent);
1047 for (j=1; j < (ssize_t) characters_per_pixel; j++)
1049 k=((i-k)/MaxCixels) % MaxCixels;
1053 (void) FormatLocaleString(buffer,MagickPathExtent,
1054 "\"%.1024s c %.1024s\",\n",symbol,name);
1055 (void) WriteBlobString(image,buffer);
1060 (void) WriteBlobString(image,"/* pixels */\n");
1061 for (y=0; y < (ssize_t) image->rows; y++)
1063 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
1064 if (p == (const Quantum *) NULL)
1066 (void) WriteBlobString(image,"\"");
1067 for (x=0; x < (ssize_t) image->columns; x++)
1069 k=((ssize_t) GetPixelIndex(image,p) % MaxCixels);
1071 for (j=1; j < (ssize_t) characters_per_pixel; j++)
1073 k=(((int) GetPixelIndex(image,p)-k)/MaxCixels) % MaxCixels;
1077 (void) CopyMagickString(buffer,symbol,MagickPathExtent);
1078 (void) WriteBlobString(image,buffer);
1079 p+=GetPixelChannels(image);
1081 (void) FormatLocaleString(buffer,MagickPathExtent,"\"%.1024s\n",
1082 (y == (ssize_t) (image->rows-1) ? "" : ","));
1083 (void) WriteBlobString(image,buffer);
1084 if (image->previous == (Image *) NULL)
1086 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
1088 if (status == MagickFalse)
1092 (void) WriteBlobString(image,"};\n");
1093 (void) CloseBlob(image);