2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13 % Read/Write X Windows system Pixmap Format %
20 % Copyright 1999-2011 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 *),
79 WriteXPMImage(const ImageInfo *,Image *);
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 char *CopyXPMColor(char *destination,const char *source,size_t length)
156 while (length-- && (*source != '\0'))
157 *destination++=(*source++);
159 return(destination-length);
162 static char *NextXPMLine(char *p)
164 assert(p != (char*)NULL);
166 if (p != (char *) NULL)
171 static inline size_t MagickMin(const size_t x,const size_t y)
178 static char *ParseXPMColor(char *color)
180 #define NumberTargets 6
193 *targets[NumberTargets] = { "c ", "g ", "g4 ", "m ", "b ", "s " };
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);
220 static Image *ReadXPMImage(const ImageInfo *image_info,ExceptionInfo *exception)
224 target[MaxTextExtent],
265 assert(image_info != (const ImageInfo *) NULL);
266 assert(image_info->signature == MagickSignature);
267 if (image_info->debug != MagickFalse)
268 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
269 image_info->filename);
270 assert(exception != (ExceptionInfo *) NULL);
271 assert(exception->signature == MagickSignature);
272 image=AcquireImage(image_info);
273 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
274 if (status == MagickFalse)
276 image=DestroyImageList(image);
277 return((Image *) NULL);
282 length=MaxTextExtent;
283 xpm_buffer=(char *) AcquireQuantumMemory((size_t) length,sizeof(*xpm_buffer));
285 if (xpm_buffer != (char *) NULL)
286 while (ReadBlobString(image,p) != (char *) NULL)
288 if ((*p == '#') && ((p == xpm_buffer) || (*(p-1) == '\n')))
290 if ((*p == '}') && (*(p+1) == ';'))
293 if ((size_t) (p-xpm_buffer+MaxTextExtent) < length)
296 xpm_buffer=(char *) ResizeQuantumMemory(xpm_buffer,length+MaxTextExtent,
297 sizeof(*xpm_buffer));
298 if (xpm_buffer == (char *) NULL)
300 p=xpm_buffer+strlen(xpm_buffer);
302 if (xpm_buffer == (char *) NULL)
303 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
308 for (p=xpm_buffer; *p != '\0'; p++)
312 count=(ssize_t) sscanf(p+1,"%lu %lu %lu %lu",&columns,&rows,&colors,&width);
313 image->columns=columns;
315 image->colors=colors;
319 if ((count != 4) || (width > 10) || (image->columns == 0) ||
320 (image->rows == 0) || (image->colors == 0))
321 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
324 Remove unquoted characters.
332 if (active != MagickFalse)
334 active=active != MagickFalse ? MagickFalse : MagickTrue;
336 if (active != MagickFalse)
341 Initialize image structure.
343 xpm_colors=NewSplayTree(CompareXPMColor,RelinquishMagickMemory,
344 (void *(*)(void *)) NULL);
345 if (AcquireImageColormap(image,image->colors) == MagickFalse)
346 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
350 next=NextXPMLine(xpm_buffer);
351 for (j=0; (j < (ssize_t) image->colors) && (next != (char*) NULL); j++)
355 (void) CopyXPMColor(key,p,MagickMin((size_t) width,MaxTextExtent));
356 status=AddValueToSplayTree(xpm_colors,ConstantString(key),(void *) j);
360 (void) CopyMagickString(target,"gray",MaxTextExtent);
361 q=ParseXPMColor(p+width);
362 if (q != (char *) NULL)
364 while ((isspace((int) ((unsigned char) *q)) == 0) && (*q != '\0'))
366 if (next != (char *) NULL)
367 (void) CopyXPMColor(target,q,MagickMin((size_t) (next-q),
370 (void) CopyMagickString(target,q,MaxTextExtent);
371 q=ParseXPMColor(target);
372 if (q != (char *) NULL)
376 if (LocaleCompare(target,"none") == 0)
378 image->storage_class=DirectClass;
379 image->matte=MagickTrue;
381 status=QueryColorCompliance(target,AllCompliance,&image->colormap[j],
383 if (status == MagickFalse)
386 if (j < (ssize_t) image->colors)
387 ThrowReaderException(CorruptImageError,"CorruptImage");
389 if (image_info->ping == MagickFalse)
394 for (y=0; y < (ssize_t) image->rows; y++)
397 if (p == (char *) NULL)
399 r=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
400 if (r == (Quantum *) NULL)
402 for (x=0; x < (ssize_t) image->columns; x++)
404 (void) CopyXPMColor(key,p,(size_t) width);
405 j=(ssize_t) GetValueFromSplayTree(xpm_colors,key);
406 if (image->storage_class == PseudoClass)
407 SetPixelIndex(image,j,r);
408 SetPixelPacket(image,image->colormap+j,r);
410 r+=GetPixelChannels(image);
412 if (SyncAuthenticPixels(image,exception) == MagickFalse)
415 if (y < (ssize_t) image->rows)
416 ThrowReaderException(CorruptImageError,"NotEnoughPixelData");
419 Relinquish resources.
421 xpm_colors=DestroySplayTree(xpm_colors);
422 (void) CloseBlob(image);
423 return(GetFirstImageInList(image));
427 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
431 % R e g i s t e r X P M I m a g e %
435 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
437 % RegisterXPMImage() adds attributes for the XPM image format to
438 % the list of supported formats. The attributes include the image format
439 % tag, a method to read and/or write the format, whether the format
440 % supports the saving of more than one frame to the same file or blob,
441 % whether the format supports native in-memory I/O, and a brief
442 % description of the format.
444 % The format of the RegisterXPMImage method is:
446 % size_t RegisterXPMImage(void)
449 ModuleExport size_t RegisterXPMImage(void)
454 entry=SetMagickInfo("PICON");
455 entry->decoder=(DecodeImageHandler *) ReadXPMImage;
456 entry->encoder=(EncodeImageHandler *) WritePICONImage;
457 entry->adjoin=MagickFalse;
458 entry->description=ConstantString("Personal Icon");
459 entry->module=ConstantString("XPM");
460 (void) RegisterMagickInfo(entry);
461 entry=SetMagickInfo("PM");
462 entry->decoder=(DecodeImageHandler *) ReadXPMImage;
463 entry->encoder=(EncodeImageHandler *) WriteXPMImage;
464 entry->adjoin=MagickFalse;
465 entry->stealth=MagickTrue;
466 entry->description=ConstantString("X Windows system pixmap (color)");
467 entry->module=ConstantString("XPM");
468 (void) RegisterMagickInfo(entry);
469 entry=SetMagickInfo("XPM");
470 entry->decoder=(DecodeImageHandler *) ReadXPMImage;
471 entry->encoder=(EncodeImageHandler *) WriteXPMImage;
472 entry->magick=(IsImageFormatHandler *) IsXPM;
473 entry->adjoin=MagickFalse;
474 entry->description=ConstantString("X Windows system pixmap (color)");
475 entry->module=ConstantString("XPM");
476 (void) RegisterMagickInfo(entry);
477 return(MagickImageCoderSignature);
481 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
485 % U n r e g i s t e r X P M I m a g e %
489 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
491 % UnregisterXPMImage() removes format registrations made by the
492 % XPM module from the list of supported formats.
494 % The format of the UnregisterXPMImage method is:
496 % UnregisterXPMImage(void)
499 ModuleExport void UnregisterXPMImage(void)
501 (void) UnregisterMagickInfo("PICON");
502 (void) UnregisterMagickInfo("PM");
503 (void) UnregisterMagickInfo("XPM");
507 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
511 % W r i t e P I C O N I m a g e %
515 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
517 % WritePICONImage() writes an image to a file in the Personal Icon format.
519 % The format of the WritePICONImage method is:
521 % MagickBooleanType WritePICONImage(const ImageInfo *image_info,
524 % A description of each parameter follows.
526 % o image_info: the image info.
528 % o image: The image.
531 static MagickBooleanType WritePICONImage(const ImageInfo *image_info,
534 #define ColormapExtent 155
535 #define GraymapExtent 95
536 #define PiconGeometry "48x48>"
541 0x47, 0x49, 0x46, 0x38, 0x37, 0x61, 0x06, 0x00, 0x05, 0x00, 0xf4, 0x05,
542 0x00, 0x00, 0x00, 0x00, 0x2f, 0x4f, 0x4f, 0x70, 0x80, 0x90, 0x7e, 0x7e,
543 0x7e, 0xdc, 0xdc, 0xdc, 0xff, 0xff, 0xff, 0x00, 0x00, 0x80, 0x00, 0x00,
544 0xff, 0x1e, 0x90, 0xff, 0x87, 0xce, 0xeb, 0xe6, 0xe6, 0xfa, 0x00, 0xff,
545 0xff, 0x80, 0x00, 0x80, 0xb2, 0x22, 0x22, 0x2e, 0x8b, 0x57, 0x32, 0xcd,
546 0x32, 0x00, 0xff, 0x00, 0x98, 0xfb, 0x98, 0xff, 0x00, 0xff, 0xff, 0x00,
547 0x00, 0xff, 0x63, 0x47, 0xff, 0xa5, 0x00, 0xff, 0xd7, 0x00, 0xff, 0xff,
548 0x00, 0xee, 0x82, 0xee, 0xa0, 0x52, 0x2d, 0xcd, 0x85, 0x3f, 0xd2, 0xb4,
549 0x8c, 0xf5, 0xde, 0xb3, 0xff, 0xfa, 0xcd, 0x00, 0x00, 0x00, 0x00, 0x00,
550 0x00, 0x21, 0xf9, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00,
551 0x00, 0x00, 0x06, 0x00, 0x05, 0x00, 0x00, 0x05, 0x18, 0x20, 0x10, 0x08,
552 0x03, 0x51, 0x18, 0x07, 0x92, 0x28, 0x0b, 0xd3, 0x38, 0x0f, 0x14, 0x49,
553 0x13, 0x55, 0x59, 0x17, 0x96, 0x69, 0x1b, 0xd7, 0x85, 0x00, 0x3b,
557 0x47, 0x49, 0x46, 0x38, 0x37, 0x61, 0x04, 0x00, 0x04, 0x00, 0xf3, 0x0f,
558 0x00, 0x00, 0x00, 0x00, 0x12, 0x12, 0x12, 0x21, 0x21, 0x21, 0x33, 0x33,
559 0x33, 0x45, 0x45, 0x45, 0x54, 0x54, 0x54, 0x66, 0x66, 0x66, 0x78, 0x78,
560 0x78, 0x87, 0x87, 0x87, 0x99, 0x99, 0x99, 0xab, 0xab, 0xab, 0xba, 0xba,
561 0xba, 0xcc, 0xcc, 0xcc, 0xde, 0xde, 0xde, 0xed, 0xed, 0xed, 0xff, 0xff,
562 0xff, 0x21, 0xf9, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00,
563 0x00, 0x00, 0x04, 0x00, 0x04, 0x00, 0x00, 0x04, 0x0c, 0x10, 0x04, 0x31,
564 0x48, 0x31, 0x07, 0x25, 0xb5, 0x58, 0x73, 0x4f, 0x04, 0x00, 0x3b,
570 Cixel[MaxCixels+1] = " .XoO+@#$%&*=-;:>,<1234567890qwertyuipasdfghjk"
571 "lzxcvbnmMNBVCZASDFGHJKLPIUYTREWQ!~^/()_`'][{}|";
574 buffer[MaxTextExtent],
575 basename[MaxTextExtent],
577 symbol[MaxTextExtent];
602 register const Quantum
613 characters_per_pixel,
622 Open output image file.
624 assert(image_info != (const ImageInfo *) NULL);
625 assert(image_info->signature == MagickSignature);
626 assert(image != (Image *) NULL);
627 assert(image->signature == MagickSignature);
628 if (image->debug != MagickFalse)
629 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
630 status=OpenBlob(image_info,image,WriteBinaryBlobMode,&image->exception);
631 if (status == MagickFalse)
633 if (IsRGBColorspace(image->colorspace) == MagickFalse)
634 (void) TransformImageColorspace(image,RGBColorspace);
635 SetGeometry(image,&geometry);
636 (void) ParseMetaGeometry(PiconGeometry,&geometry.x,&geometry.y,
637 &geometry.width,&geometry.height);
638 picon=ResizeImage(image,geometry.width,geometry.height,TriangleFilter,1.0,
640 blob_info=CloneImageInfo(image_info);
641 (void) AcquireUniqueFilename(blob_info->filename);
642 if ((image_info->type != TrueColorType) &&
643 (IsImageGray(image,&image->exception) != MagickFalse))
644 affinity_image=BlobToImage(blob_info,Graymap,GraymapExtent,
647 affinity_image=BlobToImage(blob_info,Colormap,ColormapExtent,
649 (void) RelinquishUniqueFileResource(blob_info->filename);
650 blob_info=DestroyImageInfo(blob_info);
651 if ((picon == (Image *) NULL) || (affinity_image == (Image *) NULL))
653 quantize_info=AcquireQuantizeInfo(image_info);
654 status=RemapImage(quantize_info,picon,affinity_image);
655 quantize_info=DestroyQuantizeInfo(quantize_info);
656 affinity_image=DestroyImage(affinity_image);
657 transparent=MagickFalse;
658 exception=(&image->exception);
659 if (picon->storage_class == PseudoClass)
661 (void) CompressImageColormap(picon);
662 if (picon->matte != MagickFalse)
663 transparent=MagickTrue;
668 Convert DirectClass to PseudoClass picon.
670 if (picon->matte != MagickFalse)
673 Map all the transparent pixels.
675 for (y=0; y < (ssize_t) picon->rows; y++)
677 q=GetAuthenticPixels(picon,0,y,picon->columns,1,exception);
678 if (q == (const Quantum *) NULL)
680 for (x=0; x < (ssize_t) picon->columns; x++)
682 if (GetPixelAlpha(image,q) == (Quantum) TransparentAlpha)
683 transparent=MagickTrue;
685 SetPixelAlpha(picon,OpaqueAlpha,q);
686 q+=GetPixelChannels(picon);
688 if (SyncAuthenticPixels(picon,exception) == MagickFalse)
692 (void) SetImageType(picon,PaletteType);
694 colors=picon->colors;
695 if (transparent != MagickFalse)
698 picon->colormap=(PixelPacket *) ResizeQuantumMemory((void **)
699 picon->colormap,(size_t) colors,sizeof(*picon->colormap));
700 if (picon->colormap == (PixelPacket *) NULL)
701 ThrowWriterException(ResourceLimitError,"MemoryAllocationError");
702 for (y=0; y < (ssize_t) picon->rows; y++)
704 q=GetAuthenticPixels(picon,0,y,picon->columns,1,exception);
705 if (q == (const Quantum *) NULL)
707 for (x=0; x < (ssize_t) picon->columns; x++)
709 if (GetPixelAlpha(image,q) == (Quantum) TransparentAlpha)
710 SetPixelIndex(picon,picon->colors,q);
711 q+=GetPixelChannels(picon);
713 if (SyncAuthenticPixels(picon,exception) == MagickFalse)
718 Compute the character per pixel.
720 characters_per_pixel=1;
721 for (k=MaxCixels; (ssize_t) colors > k; k*=MaxCixels)
722 characters_per_pixel++;
726 (void) WriteBlobString(image,"/* XPM */\n");
727 GetPathComponent(picon->filename,BasePath,basename);
728 (void) FormatLocaleString(buffer,MaxTextExtent,
729 "static char *%s[] = {\n",basename);
730 (void) WriteBlobString(image,buffer);
731 (void) WriteBlobString(image,"/* columns rows colors chars-per-pixel */\n");
732 (void) FormatLocaleString(buffer,MaxTextExtent,
733 "\"%.20g %.20g %.20g %.20g\",\n",(double) picon->columns,(double)
734 picon->rows,(double) colors,(double) characters_per_pixel);
735 (void) WriteBlobString(image,buffer);
736 GetPixelInfo(image,&pixel);
737 for (i=0; i < (ssize_t) colors; i++)
742 SetPixelInfoPacket(image,picon->colormap+i,&pixel);
743 pixel.colorspace=RGBColorspace;
745 pixel.alpha=(MagickRealType) OpaqueAlpha;
746 (void) QueryMagickColorname(image,&pixel,XPMCompliance,name,
748 if (transparent != MagickFalse)
750 if (i == (ssize_t) (colors-1))
751 (void) CopyMagickString(name,"grey75",MaxTextExtent);
758 for (j=1; j < (ssize_t) characters_per_pixel; j++)
760 k=((i-k)/MaxCixels) % MaxCixels;
764 (void) FormatLocaleString(buffer,MaxTextExtent,"\"%s c %s\",\n",
766 (void) WriteBlobString(image,buffer);
771 (void) WriteBlobString(image,"/* pixels */\n");
772 for (y=0; y < (ssize_t) picon->rows; y++)
774 p=GetVirtualPixels(picon,0,y,picon->columns,1,&picon->exception);
775 if (p == (const Quantum *) NULL)
777 (void) WriteBlobString(image,"\"");
778 for (x=0; x < (ssize_t) picon->columns; x++)
780 k=((ssize_t) GetPixelIndex(picon,p) % MaxCixels);
782 for (j=1; j < (ssize_t) characters_per_pixel; j++)
784 k=(((int) GetPixelIndex(picon,p)-k)/MaxCixels) % MaxCixels;
788 (void) CopyMagickString(buffer,symbol,MaxTextExtent);
789 (void) WriteBlobString(image,buffer);
790 p+=GetPixelChannels(image);
792 (void) FormatLocaleString(buffer,MaxTextExtent,"\"%s\n",
793 y == (ssize_t) (picon->rows-1) ? "" : ",");
794 (void) WriteBlobString(image,buffer);
795 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
797 if (status == MagickFalse)
800 picon=DestroyImage(picon);
801 (void) WriteBlobString(image,"};\n");
802 (void) CloseBlob(image);
807 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
811 % W r i t e X P M I m a g e %
815 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
817 % WriteXPMImage() writes an image to a file in the X pixmap format.
819 % The format of the WriteXPMImage method is:
821 % MagickBooleanType WriteXPMImage(const ImageInfo *image_info,Image *image)
823 % A description of each parameter follows.
825 % o image_info: the image info.
827 % o image: The image.
830 static MagickBooleanType WriteXPMImage(const ImageInfo *image_info,Image *image)
835 Cixel[MaxCixels+1] = " .XoO+@#$%&*=-;:>,<1234567890qwertyuipasdfghjk"
836 "lzxcvbnmMNBVCZASDFGHJKLPIUYTREWQ!~^/()_`'][{}|";
839 buffer[MaxTextExtent],
840 basename[MaxTextExtent],
842 symbol[MaxTextExtent];
850 register const Quantum
858 characters_per_pixel;
867 Open output image file.
869 assert(image_info != (const ImageInfo *) NULL);
870 assert(image_info->signature == MagickSignature);
871 assert(image != (Image *) NULL);
872 assert(image->signature == MagickSignature);
873 if (image->debug != MagickFalse)
874 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
875 status=OpenBlob(image_info,image,WriteBinaryBlobMode,&image->exception);
876 if (status == MagickFalse)
878 if (IsRGBColorspace(image->colorspace) == MagickFalse)
879 (void) TransformImageColorspace(image,RGBColorspace);
881 if (image->matte == MagickFalse)
883 if ((image->storage_class == DirectClass) || (image->colors > 256))
884 (void) SetImageType(image,PaletteType);
893 Identify transparent colormap index.
895 if ((image->storage_class == DirectClass) || (image->colors > 256))
896 (void) SetImageType(image,PaletteBilevelMatteType);
897 for (i=0; i < (ssize_t) image->colors; i++)
898 if (image->colormap[i].alpha != OpaqueAlpha)
905 alpha=(MagickRealType) TransparentAlpha-(MagickRealType)
906 image->colormap[i].alpha;
907 beta=(MagickRealType) TransparentAlpha-(MagickRealType)
908 image->colormap[opacity].alpha;
914 (void) SetImageType(image,PaletteBilevelMatteType);
915 for (i=0; i < (ssize_t) image->colors; i++)
916 if (image->colormap[i].alpha != OpaqueAlpha)
923 alpha=(Quantum) TransparentAlpha-(MagickRealType)
924 image->colormap[i].alpha;
925 beta=(Quantum) TransparentAlpha-(MagickRealType)
926 image->colormap[opacity].alpha;
933 image->colormap[opacity].red=image->transparent_color.red;
934 image->colormap[opacity].green=image->transparent_color.green;
935 image->colormap[opacity].blue=image->transparent_color.blue;
939 Compute the character per pixel.
941 characters_per_pixel=1;
942 for (k=MaxCixels; (ssize_t) image->colors > k; k*=MaxCixels)
943 characters_per_pixel++;
947 (void) WriteBlobString(image,"/* XPM */\n");
948 GetPathComponent(image->filename,BasePath,basename);
949 if (isalnum((int) ((unsigned char) *basename)) == 0)
951 (void) FormatLocaleString(buffer,MaxTextExtent,"xpm_%s",basename);
952 (void) CopyMagickString(basename,buffer,MaxTextExtent);
954 if (isalpha((int) ((unsigned char) basename[0])) == 0)
956 for (i=1; basename[i] != '\0'; i++)
957 if (isalnum((int) ((unsigned char) basename[i])) == 0)
959 (void) FormatLocaleString(buffer,MaxTextExtent,
960 "static char *%s[] = {\n",basename);
961 (void) WriteBlobString(image,buffer);
962 (void) WriteBlobString(image,"/* columns rows colors chars-per-pixel */\n");
963 (void) FormatLocaleString(buffer,MaxTextExtent,
964 "\"%.20g %.20g %.20g %.20g \",\n",(double) image->columns,(double)
965 image->rows,(double) image->colors,(double) characters_per_pixel);
966 (void) WriteBlobString(image,buffer);
967 GetPixelInfo(image,&pixel);
968 for (i=0; i < (ssize_t) image->colors; i++)
973 SetPixelInfoPacket(image,image->colormap+i,&pixel);
974 pixel.colorspace=RGBColorspace;
976 pixel.alpha=(MagickRealType) OpaqueAlpha;
977 (void) QueryMagickColorname(image,&pixel,XPMCompliance,name,
980 (void) CopyMagickString(name,"None",MaxTextExtent);
986 for (j=1; j < (ssize_t) characters_per_pixel; j++)
988 k=((i-k)/MaxCixels) % MaxCixels;
992 (void) FormatLocaleString(buffer,MaxTextExtent,"\"%s c %s\",\n",symbol,
994 (void) WriteBlobString(image,buffer);
999 (void) WriteBlobString(image,"/* pixels */\n");
1000 for (y=0; y < (ssize_t) image->rows; y++)
1002 p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception);
1003 if (p == (const Quantum *) NULL)
1005 (void) WriteBlobString(image,"\"");
1006 for (x=0; x < (ssize_t) image->columns; x++)
1008 k=((ssize_t) GetPixelIndex(image,p) % MaxCixels);
1010 for (j=1; j < (ssize_t) characters_per_pixel; j++)
1012 k=(((int) GetPixelIndex(image,p)-k)/MaxCixels) % MaxCixels;
1016 (void) CopyMagickString(buffer,symbol,MaxTextExtent);
1017 (void) WriteBlobString(image,buffer);
1018 p+=GetPixelChannels(image);
1020 (void) FormatLocaleString(buffer,MaxTextExtent,"\"%s\n",
1021 (y == (ssize_t) (image->rows-1) ? "" : ","));
1022 (void) WriteBlobString(image,buffer);
1023 if (image->previous == (Image *) NULL)
1025 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
1027 if (status == MagickFalse)
1031 (void) WriteBlobString(image,"};\n");
1032 (void) CloseBlob(image);