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 "magick/studio.h"
43 #include "magick/blob.h"
44 #include "magick/blob-private.h"
45 #include "magick/cache.h"
46 #include "magick/color.h"
47 #include "magick/color-private.h"
48 #include "magick/colormap.h"
49 #include "magick/colorspace.h"
50 #include "magick/exception.h"
51 #include "magick/exception-private.h"
52 #include "magick/geometry.h"
53 #include "magick/image.h"
54 #include "magick/image-private.h"
55 #include "magick/list.h"
56 #include "magick/magick.h"
57 #include "magick/memory_.h"
58 #include "magick/monitor.h"
59 #include "magick/monitor-private.h"
60 #include "magick/pixel-private.h"
61 #include "magick/quantize.h"
62 #include "magick/quantum-private.h"
63 #include "magick/resize.h"
64 #include "magick/resource_.h"
65 #include "magick/splay-tree.h"
66 #include "magick/static.h"
67 #include "magick/string_.h"
68 #include "magick/module.h"
69 #include "magick/threshold.h"
70 #include "magick/utility.h"
75 static MagickBooleanType
76 WritePICONImage(const ImageInfo *,Image *),
77 WriteXPMImage(const ImageInfo *,Image *);
80 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
88 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
90 % IsXPM() returns MagickTrue if the image format type, identified by the
91 % magick string, is XPM.
93 % The format of the IsXPM method is:
95 % MagickBooleanType IsXPM(const unsigned char *magick,const size_t length)
97 % A description of each parameter follows:
99 % o magick: compare image format pattern against these bytes. or
102 % o length: Specifies the length of the magick string.
105 static MagickBooleanType IsXPM(const unsigned char *magick,const size_t length)
109 if (LocaleNCompare((char *) magick+1,"* XPM *",7) == 0)
115 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
119 % R e a d X P M I m a g e %
123 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
125 % ReadXPMImage() reads an X11 pixmap image file and returns it. It
126 % allocates the memory necessary for the new Image structure and returns a
127 % pointer to the new image.
129 % The format of the ReadXPMImage method is:
131 % Image *ReadXPMImage(const ImageInfo *image_info,ExceptionInfo *exception)
133 % A description of each parameter follows:
135 % o image_info: the image info.
137 % o exception: return any errors or warnings in this structure.
141 static int CompareXPMColor(const void *target,const void *source)
147 p=(const char *) target;
148 q=(const char *) source;
152 static char *CopyXPMColor(char *destination,const char *source,size_t length)
154 while (length-- && (*source != '\0'))
155 *destination++=(*source++);
157 return(destination-length);
160 static char *NextXPMLine(char *p)
162 assert(p != (char*)NULL);
164 if (p != (char *) NULL)
169 static inline size_t MagickMin(const size_t x,const size_t y)
176 static char *ParseXPMColor(char *color)
178 #define NumberTargets 6
191 *targets[NumberTargets] = { "c ", "g ", "g4 ", "m ", "b ", "s " };
193 for (i=0; i < NumberTargets; i++)
196 for (q=targets[i]; *p != '\0'; p++)
202 if (isspace((int) ((unsigned char) (*(p-1)))) == 0)
215 return((char *) NULL);
218 static Image *ReadXPMImage(const ImageInfo *image_info,ExceptionInfo *exception)
222 target[MaxTextExtent],
268 assert(image_info != (const ImageInfo *) NULL);
269 assert(image_info->signature == MagickSignature);
270 if (image_info->debug != MagickFalse)
271 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
272 image_info->filename);
273 assert(exception != (ExceptionInfo *) NULL);
274 assert(exception->signature == MagickSignature);
275 image=AcquireImage(image_info);
276 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
277 if (status == MagickFalse)
279 image=DestroyImageList(image);
280 return((Image *) NULL);
285 length=MaxTextExtent;
286 xpm_buffer=(char *) AcquireQuantumMemory((size_t) length,sizeof(*xpm_buffer));
288 if (xpm_buffer != (char *) NULL)
289 while (ReadBlobString(image,p) != (char *) NULL)
291 if ((*p == '#') && ((p == xpm_buffer) || (*(p-1) == '\n')))
293 if ((*p == '}') && (*(p+1) == ';'))
296 if ((size_t) (p-xpm_buffer+MaxTextExtent) < length)
299 xpm_buffer=(char *) ResizeQuantumMemory(xpm_buffer,length+MaxTextExtent,
300 sizeof(*xpm_buffer));
301 if (xpm_buffer == (char *) NULL)
303 p=xpm_buffer+strlen(xpm_buffer);
305 if (xpm_buffer == (char *) NULL)
306 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
311 for (p=xpm_buffer; *p != '\0'; p++)
315 count=(ssize_t) sscanf(p+1,"%lu %lu %lu %lu",&columns,&rows,&colors,&width);
316 image->columns=columns;
318 image->colors=colors;
322 if ((count != 4) || (width > 10) || (image->columns == 0) ||
323 (image->rows == 0) || (image->colors == 0))
324 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
327 Remove unquoted characters.
335 if (active != MagickFalse)
337 active=active != MagickFalse ? MagickFalse : MagickTrue;
339 if (active != MagickFalse)
344 Initialize image structure.
346 xpm_colors=NewSplayTree(CompareXPMColor,RelinquishMagickMemory,
347 (void *(*)(void *)) NULL);
348 if (AcquireImageColormap(image,image->colors) == MagickFalse)
349 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
353 next=NextXPMLine(xpm_buffer);
354 for (j=0; (j < (ssize_t) image->colors) && (next != (char*) NULL); j++)
358 (void) CopyXPMColor(key,p,MagickMin((size_t) width,MaxTextExtent));
359 status=AddValueToSplayTree(xpm_colors,ConstantString(key),(void *) j);
363 (void) CopyMagickString(target,"gray",MaxTextExtent);
364 q=ParseXPMColor(p+width);
365 if (q != (char *) NULL)
367 while ((isspace((int) ((unsigned char) *q)) == 0) && (*q != '\0'))
369 if (next != (char *) NULL)
370 (void) CopyXPMColor(target,q,MagickMin((size_t) (next-q),
373 (void) CopyMagickString(target,q,MaxTextExtent);
374 q=ParseXPMColor(target);
375 if (q != (char *) NULL)
379 if (LocaleCompare(target,"none") == 0)
381 image->storage_class=DirectClass;
382 image->matte=MagickTrue;
384 status=QueryColorCompliance(target,AllCompliance,&image->colormap[j],
386 if (status == MagickFalse)
389 if (j < (ssize_t) image->colors)
390 ThrowReaderException(CorruptImageError,"CorruptImage");
392 if (image_info->ping == MagickFalse)
397 for (y=0; y < (ssize_t) image->rows; y++)
400 if (p == (char *) NULL)
402 r=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
403 if (r == (PixelPacket *) NULL)
405 indexes=GetAuthenticIndexQueue(image);
406 for (x=0; x < (ssize_t) image->columns; x++)
408 (void) CopyXPMColor(key,p,(size_t) width);
409 j=(ssize_t) GetValueFromSplayTree(xpm_colors,key);
410 if (image->storage_class == PseudoClass)
411 indexes[x]=(IndexPacket) j;
412 *r=image->colormap[j];
416 if (SyncAuthenticPixels(image,exception) == MagickFalse)
419 if (y < (ssize_t) image->rows)
420 ThrowReaderException(CorruptImageError,"NotEnoughPixelData");
423 Relinquish resources.
425 xpm_colors=DestroySplayTree(xpm_colors);
426 (void) CloseBlob(image);
427 return(GetFirstImageInList(image));
431 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
435 % R e g i s t e r X P M I m a g e %
439 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
441 % RegisterXPMImage() adds attributes for the XPM image format to
442 % the list of supported formats. The attributes include the image format
443 % tag, a method to read and/or write the format, whether the format
444 % supports the saving of more than one frame to the same file or blob,
445 % whether the format supports native in-memory I/O, and a brief
446 % description of the format.
448 % The format of the RegisterXPMImage method is:
450 % size_t RegisterXPMImage(void)
453 ModuleExport size_t RegisterXPMImage(void)
458 entry=SetMagickInfo("PICON");
459 entry->decoder=(DecodeImageHandler *) ReadXPMImage;
460 entry->encoder=(EncodeImageHandler *) WritePICONImage;
461 entry->adjoin=MagickFalse;
462 entry->description=ConstantString("Personal Icon");
463 entry->module=ConstantString("XPM");
464 (void) RegisterMagickInfo(entry);
465 entry=SetMagickInfo("PM");
466 entry->decoder=(DecodeImageHandler *) ReadXPMImage;
467 entry->encoder=(EncodeImageHandler *) WriteXPMImage;
468 entry->adjoin=MagickFalse;
469 entry->stealth=MagickTrue;
470 entry->description=ConstantString("X Windows system pixmap (color)");
471 entry->module=ConstantString("XPM");
472 (void) RegisterMagickInfo(entry);
473 entry=SetMagickInfo("XPM");
474 entry->decoder=(DecodeImageHandler *) ReadXPMImage;
475 entry->encoder=(EncodeImageHandler *) WriteXPMImage;
476 entry->magick=(IsImageFormatHandler *) IsXPM;
477 entry->adjoin=MagickFalse;
478 entry->description=ConstantString("X Windows system pixmap (color)");
479 entry->module=ConstantString("XPM");
480 (void) RegisterMagickInfo(entry);
481 return(MagickImageCoderSignature);
485 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
489 % U n r e g i s t e r X P M I m a g e %
493 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
495 % UnregisterXPMImage() removes format registrations made by the
496 % XPM module from the list of supported formats.
498 % The format of the UnregisterXPMImage method is:
500 % UnregisterXPMImage(void)
503 ModuleExport void UnregisterXPMImage(void)
505 (void) UnregisterMagickInfo("PICON");
506 (void) UnregisterMagickInfo("PM");
507 (void) UnregisterMagickInfo("XPM");
511 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
515 % W r i t e P I C O N I m a g e %
519 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
521 % WritePICONImage() writes an image to a file in the Personal Icon format.
523 % The format of the WritePICONImage method is:
525 % MagickBooleanType WritePICONImage(const ImageInfo *image_info,
528 % A description of each parameter follows.
530 % o image_info: the image info.
532 % o image: The image.
535 static MagickBooleanType WritePICONImage(const ImageInfo *image_info,
538 #define ColormapExtent 155
539 #define GraymapExtent 95
540 #define PiconGeometry "48x48>"
545 0x47, 0x49, 0x46, 0x38, 0x37, 0x61, 0x06, 0x00, 0x05, 0x00, 0xf4, 0x05,
546 0x00, 0x00, 0x00, 0x00, 0x2f, 0x4f, 0x4f, 0x70, 0x80, 0x90, 0x7e, 0x7e,
547 0x7e, 0xdc, 0xdc, 0xdc, 0xff, 0xff, 0xff, 0x00, 0x00, 0x80, 0x00, 0x00,
548 0xff, 0x1e, 0x90, 0xff, 0x87, 0xce, 0xeb, 0xe6, 0xe6, 0xfa, 0x00, 0xff,
549 0xff, 0x80, 0x00, 0x80, 0xb2, 0x22, 0x22, 0x2e, 0x8b, 0x57, 0x32, 0xcd,
550 0x32, 0x00, 0xff, 0x00, 0x98, 0xfb, 0x98, 0xff, 0x00, 0xff, 0xff, 0x00,
551 0x00, 0xff, 0x63, 0x47, 0xff, 0xa5, 0x00, 0xff, 0xd7, 0x00, 0xff, 0xff,
552 0x00, 0xee, 0x82, 0xee, 0xa0, 0x52, 0x2d, 0xcd, 0x85, 0x3f, 0xd2, 0xb4,
553 0x8c, 0xf5, 0xde, 0xb3, 0xff, 0xfa, 0xcd, 0x00, 0x00, 0x00, 0x00, 0x00,
554 0x00, 0x21, 0xf9, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00,
555 0x00, 0x00, 0x06, 0x00, 0x05, 0x00, 0x00, 0x05, 0x18, 0x20, 0x10, 0x08,
556 0x03, 0x51, 0x18, 0x07, 0x92, 0x28, 0x0b, 0xd3, 0x38, 0x0f, 0x14, 0x49,
557 0x13, 0x55, 0x59, 0x17, 0x96, 0x69, 0x1b, 0xd7, 0x85, 0x00, 0x3b,
561 0x47, 0x49, 0x46, 0x38, 0x37, 0x61, 0x04, 0x00, 0x04, 0x00, 0xf3, 0x0f,
562 0x00, 0x00, 0x00, 0x00, 0x12, 0x12, 0x12, 0x21, 0x21, 0x21, 0x33, 0x33,
563 0x33, 0x45, 0x45, 0x45, 0x54, 0x54, 0x54, 0x66, 0x66, 0x66, 0x78, 0x78,
564 0x78, 0x87, 0x87, 0x87, 0x99, 0x99, 0x99, 0xab, 0xab, 0xab, 0xba, 0xba,
565 0xba, 0xcc, 0xcc, 0xcc, 0xde, 0xde, 0xde, 0xed, 0xed, 0xed, 0xff, 0xff,
566 0xff, 0x21, 0xf9, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00,
567 0x00, 0x00, 0x04, 0x00, 0x04, 0x00, 0x00, 0x04, 0x0c, 0x10, 0x04, 0x31,
568 0x48, 0x31, 0x07, 0x25, 0xb5, 0x58, 0x73, 0x4f, 0x04, 0x00, 0x3b,
574 Cixel[MaxCixels+1] = " .XoO+@#$%&*=-;:>,<1234567890qwertyuipasdfghjk"
575 "lzxcvbnmMNBVCZASDFGHJKLPIUYTREWQ!~^/()_`'][{}|";
578 buffer[MaxTextExtent],
579 basename[MaxTextExtent],
581 symbol[MaxTextExtent];
611 register const IndexPacket
614 register const PixelPacket
625 characters_per_pixel,
629 Open output image file.
631 assert(image_info != (const ImageInfo *) NULL);
632 assert(image_info->signature == MagickSignature);
633 assert(image != (Image *) NULL);
634 assert(image->signature == MagickSignature);
635 if (image->debug != MagickFalse)
636 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
637 status=OpenBlob(image_info,image,WriteBinaryBlobMode,&image->exception);
638 if (status == MagickFalse)
640 if (image->colorspace != RGBColorspace)
641 (void) TransformImageColorspace(image,RGBColorspace);
642 SetGeometry(image,&geometry);
643 (void) ParseMetaGeometry(PiconGeometry,&geometry.x,&geometry.y,
644 &geometry.width,&geometry.height);
645 picon=ResizeImage(image,geometry.width,geometry.height,TriangleFilter,1.0,
647 blob_info=CloneImageInfo(image_info);
648 (void) AcquireUniqueFilename(blob_info->filename);
649 if ((image_info->type != TrueColorType) &&
650 (IsGrayImage(image,&image->exception) != MagickFalse))
651 affinity_image=BlobToImage(blob_info,Graymap,GraymapExtent,
654 affinity_image=BlobToImage(blob_info,Colormap,ColormapExtent,
656 (void) RelinquishUniqueFileResource(blob_info->filename);
657 blob_info=DestroyImageInfo(blob_info);
658 if ((picon == (Image *) NULL) || (affinity_image == (Image *) NULL))
660 quantize_info=AcquireQuantizeInfo(image_info);
661 status=RemapImage(quantize_info,picon,affinity_image);
662 quantize_info=DestroyQuantizeInfo(quantize_info);
663 affinity_image=DestroyImage(affinity_image);
664 transparent=MagickFalse;
665 exception=(&image->exception);
666 if (picon->storage_class == PseudoClass)
668 (void) CompressImageColormap(picon);
669 if (picon->matte != MagickFalse)
670 transparent=MagickTrue;
675 Convert DirectClass to PseudoClass picon.
677 if (picon->matte != MagickFalse)
680 Map all the transparent pixels.
682 for (y=0; y < (ssize_t) picon->rows; y++)
684 q=GetAuthenticPixels(picon,0,y,picon->columns,1,exception);
685 if (q == (PixelPacket *) NULL)
687 for (x=0; x < (ssize_t) picon->columns; x++)
689 if (q->opacity == (Quantum) TransparentOpacity)
690 transparent=MagickTrue;
692 SetOpacityPixelComponent(q,OpaqueOpacity);
695 if (SyncAuthenticPixels(picon,exception) == MagickFalse)
699 (void) SetImageType(picon,PaletteType);
701 colors=picon->colors;
702 if (transparent != MagickFalse)
708 picon->colormap=(PixelPacket *) ResizeQuantumMemory((void **)
709 picon->colormap,(size_t) colors,sizeof(*picon->colormap));
710 if (picon->colormap == (PixelPacket *) NULL)
711 ThrowWriterException(ResourceLimitError,"MemoryAllocationError");
712 for (y=0; y < (ssize_t) picon->rows; y++)
714 q=GetAuthenticPixels(picon,0,y,picon->columns,1,exception);
715 if (q == (PixelPacket *) NULL)
717 indexes=GetAuthenticIndexQueue(picon);
718 for (x=0; x < (ssize_t) picon->columns; x++)
720 if (q->opacity == (Quantum) TransparentOpacity)
721 indexes[x]=(IndexPacket) picon->colors;
724 if (SyncAuthenticPixels(picon,exception) == MagickFalse)
729 Compute the character per pixel.
731 characters_per_pixel=1;
732 for (k=MaxCixels; (ssize_t) colors > k; k*=MaxCixels)
733 characters_per_pixel++;
737 (void) WriteBlobString(image,"/* XPM */\n");
738 GetPathComponent(picon->filename,BasePath,basename);
739 (void) FormatMagickString(buffer,MaxTextExtent,
740 "static char *%s[] = {\n",basename);
741 (void) WriteBlobString(image,buffer);
742 (void) WriteBlobString(image,"/* columns rows colors chars-per-pixel */\n");
743 (void) FormatMagickString(buffer,MaxTextExtent,
744 "\"%.20g %.20g %.20g %.20g\",\n",(double) picon->columns,(double)
745 picon->rows,(double) colors,(double) characters_per_pixel);
746 (void) WriteBlobString(image,buffer);
747 GetMagickPixelPacket(image,&pixel);
748 for (i=0; i < (ssize_t) colors; i++)
753 SetMagickPixelPacket(image,picon->colormap+i,(IndexPacket *) NULL,&pixel);
754 pixel.colorspace=RGBColorspace;
756 pixel.opacity=(MagickRealType) OpaqueOpacity;
757 (void) QueryMagickColorname(image,&pixel,XPMCompliance,name,
759 if (transparent != MagickFalse)
761 if (i == (ssize_t) (colors-1))
762 (void) CopyMagickString(name,"grey75",MaxTextExtent);
769 for (j=1; j < (ssize_t) characters_per_pixel; j++)
771 k=((i-k)/MaxCixels) % MaxCixels;
775 (void) FormatMagickString(buffer,MaxTextExtent,"\"%s c %s\",\n",
777 (void) WriteBlobString(image,buffer);
782 (void) WriteBlobString(image,"/* pixels */\n");
783 for (y=0; y < (ssize_t) picon->rows; y++)
785 p=GetVirtualPixels(picon,0,y,picon->columns,1,&picon->exception);
786 if (p == (const PixelPacket *) NULL)
788 indexes=GetVirtualIndexQueue(picon);
789 (void) WriteBlobString(image,"\"");
790 for (x=0; x < (ssize_t) picon->columns; x++)
792 k=((ssize_t) indexes[x] % MaxCixels);
794 for (j=1; j < (ssize_t) characters_per_pixel; j++)
796 k=(((int) indexes[x]-k)/MaxCixels) % MaxCixels;
800 (void) CopyMagickString(buffer,symbol,MaxTextExtent);
801 (void) WriteBlobString(image,buffer);
803 (void) FormatMagickString(buffer,MaxTextExtent,"\"%s\n",
804 y == (ssize_t) (picon->rows-1) ? "" : ",");
805 (void) WriteBlobString(image,buffer);
806 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
808 if (status == MagickFalse)
811 picon=DestroyImage(picon);
812 (void) WriteBlobString(image,"};\n");
813 (void) CloseBlob(image);
818 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
822 % W r i t e X P M I m a g e %
826 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
828 % WriteXPMImage() writes an image to a file in the X pixmap format.
830 % The format of the WriteXPMImage method is:
832 % MagickBooleanType WriteXPMImage(const ImageInfo *image_info,Image *image)
834 % A description of each parameter follows.
836 % o image_info: the image info.
838 % o image: The image.
841 static MagickBooleanType WriteXPMImage(const ImageInfo *image_info,Image *image)
846 Cixel[MaxCixels+1] = " .XoO+@#$%&*=-;:>,<1234567890qwertyuipasdfghjk"
847 "lzxcvbnmMNBVCZASDFGHJKLPIUYTREWQ!~^/()_`'][{}|";
850 buffer[MaxTextExtent],
851 basename[MaxTextExtent],
853 symbol[MaxTextExtent];
867 register const IndexPacket
870 register const PixelPacket
878 characters_per_pixel;
881 Open output image file.
883 assert(image_info != (const ImageInfo *) NULL);
884 assert(image_info->signature == MagickSignature);
885 assert(image != (Image *) NULL);
886 assert(image->signature == MagickSignature);
887 if (image->debug != MagickFalse)
888 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
889 status=OpenBlob(image_info,image,WriteBinaryBlobMode,&image->exception);
890 if (status == MagickFalse)
892 if (image->colorspace != RGBColorspace)
893 (void) TransformImageColorspace(image,RGBColorspace);
895 if (image->matte == MagickFalse)
897 if ((image->storage_class == DirectClass) || (image->colors > 256))
898 (void) SetImageType(image,PaletteType);
907 Identify transparent colormap index.
909 if ((image->storage_class == DirectClass) || (image->colors > 256))
910 (void) SetImageType(image,PaletteBilevelMatteType);
911 for (i=0; i < (ssize_t) image->colors; i++)
912 if (image->colormap[i].opacity != OpaqueOpacity)
919 alpha=(Quantum) TransparentOpacity-(MagickRealType)
920 image->colormap[i].opacity;
921 beta=(Quantum) TransparentOpacity-(MagickRealType)
922 image->colormap[opacity].opacity;
928 (void) SetImageType(image,PaletteBilevelMatteType);
929 for (i=0; i < (ssize_t) image->colors; i++)
930 if (image->colormap[i].opacity != OpaqueOpacity)
937 alpha=(Quantum) TransparentOpacity-(MagickRealType)
938 image->colormap[i].opacity;
939 beta=(Quantum) TransparentOpacity-(MagickRealType)
940 image->colormap[opacity].opacity;
947 image->colormap[opacity].red=image->transparent_color.red;
948 image->colormap[opacity].green=image->transparent_color.green;
949 image->colormap[opacity].blue=image->transparent_color.blue;
953 Compute the character per pixel.
955 characters_per_pixel=1;
956 for (k=MaxCixels; (ssize_t) image->colors > k; k*=MaxCixels)
957 characters_per_pixel++;
961 (void) WriteBlobString(image,"/* XPM */\n");
962 GetPathComponent(image->filename,BasePath,basename);
963 if (isalnum((int) ((unsigned char) *basename)) == 0)
965 (void) FormatMagickString(buffer,MaxTextExtent,"xpm_%s",basename);
966 (void) CopyMagickString(basename,buffer,MaxTextExtent);
968 if (isalpha((int) ((unsigned char) basename[0])) == 0)
970 for (i=1; basename[i] != '\0'; i++)
971 if (isalnum((int) ((unsigned char) basename[i])) == 0)
973 (void) FormatMagickString(buffer,MaxTextExtent,
974 "static char *%s[] = {\n",basename);
975 (void) WriteBlobString(image,buffer);
976 (void) WriteBlobString(image,"/* columns rows colors chars-per-pixel */\n");
977 (void) FormatMagickString(buffer,MaxTextExtent,
978 "\"%.20g %.20g %.20g %.20g \",\n",(double) image->columns,(double)
979 image->rows,(double) image->colors,(double) characters_per_pixel);
980 (void) WriteBlobString(image,buffer);
981 GetMagickPixelPacket(image,&pixel);
982 for (i=0; i < (ssize_t) image->colors; i++)
987 SetMagickPixelPacket(image,image->colormap+i,(IndexPacket *) NULL,&pixel);
988 pixel.colorspace=RGBColorspace;
990 pixel.opacity=(MagickRealType) OpaqueOpacity;
991 (void) QueryMagickColorname(image,&pixel,XPMCompliance,name,
994 (void) CopyMagickString(name,"None",MaxTextExtent);
1000 for (j=1; j < (ssize_t) characters_per_pixel; j++)
1002 k=((i-k)/MaxCixels) % MaxCixels;
1006 (void) FormatMagickString(buffer,MaxTextExtent,"\"%s c %s\",\n",symbol,
1008 (void) WriteBlobString(image,buffer);
1013 (void) WriteBlobString(image,"/* pixels */\n");
1014 for (y=0; y < (ssize_t) image->rows; y++)
1016 p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception);
1017 if (p == (const PixelPacket *) NULL)
1019 indexes=GetVirtualIndexQueue(image);
1020 (void) WriteBlobString(image,"\"");
1021 for (x=0; x < (ssize_t) image->columns; x++)
1023 k=((ssize_t) indexes[x] % MaxCixels);
1025 for (j=1; j < (ssize_t) characters_per_pixel; j++)
1027 k=(((int) indexes[x]-k)/MaxCixels) % MaxCixels;
1031 (void) CopyMagickString(buffer,symbol,MaxTextExtent);
1032 (void) WriteBlobString(image,buffer);
1034 (void) FormatMagickString(buffer,MaxTextExtent,"\"%s\n",
1035 (y == (ssize_t) (image->rows-1) ? "" : ","));
1036 (void) WriteBlobString(image,buffer);
1037 if (image->previous == (Image *) NULL)
1039 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
1041 if (status == MagickFalse)
1045 (void) WriteBlobString(image,"};\n");
1046 (void) CloseBlob(image);