2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13 % Read/Write X Windows system Pixmap Format %
20 % Copyright 1999-2010 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],
269 assert(image_info != (const ImageInfo *) NULL);
270 assert(image_info->signature == MagickSignature);
271 if (image_info->debug != MagickFalse)
272 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
273 image_info->filename);
274 assert(exception != (ExceptionInfo *) NULL);
275 assert(exception->signature == MagickSignature);
276 image=AcquireImage(image_info);
277 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
278 if (status == MagickFalse)
280 image=DestroyImageList(image);
281 return((Image *) NULL);
286 length=MaxTextExtent;
287 xpm_buffer=(char *) AcquireQuantumMemory((size_t) length,sizeof(*xpm_buffer));
289 if (xpm_buffer != (char *) NULL)
290 while (ReadBlobString(image,p) != (char *) NULL)
292 if ((*p == '#') && ((p == xpm_buffer) || (*(p-1) == '\n')))
294 if ((*p == '}') && (*(p+1) == ';'))
297 if ((size_t) (p-xpm_buffer+MaxTextExtent) < length)
300 xpm_buffer=(char *) ResizeQuantumMemory(xpm_buffer,length+MaxTextExtent,
301 sizeof(*xpm_buffer));
302 if (xpm_buffer == (char *) NULL)
304 p=xpm_buffer+strlen(xpm_buffer);
306 if (xpm_buffer == (char *) NULL)
307 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
312 for (p=xpm_buffer; *p != '\0'; p++)
316 count=(ssize_t) sscanf(p+1,"%lu %lu %lu %lu",&columns,&rows,&colors,&width);
317 image->columns=columns;
319 image->colors=colors;
323 if ((count != 4) || (width > 10) || (image->columns == 0) ||
324 (image->rows == 0) || (image->colors == 0))
325 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
328 Remove unquoted characters.
337 if (active != MagickFalse)
339 active=active != MagickFalse ? MagickFalse : MagickTrue;
341 if (active != MagickFalse)
346 Initialize image structure.
348 xpm_colors=NewSplayTree(CompareXPMColor,RelinquishMagickMemory,
349 (void *(*)(void *)) NULL);
350 if (AcquireImageColormap(image,image->colors) == MagickFalse)
351 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
356 next=NextXPMLine(xpm_buffer);
357 for (j=0; (j < (ssize_t) image->colors) && (next != (char*) NULL); j++)
361 (void) CopyXPMColor(key,p,MagickMin((size_t) width,MaxTextExtent));
362 status=AddValueToSplayTree(xpm_colors,ConstantString(key),(void *) j);
366 (void) CopyMagickString(target,"gray",MaxTextExtent);
367 q=ParseXPMColor(p+width);
368 if (q != (char *) NULL)
370 while ((isspace((int) ((unsigned char) *q)) == 0) && (*q != '\0'))
372 if (next != (char *) NULL)
373 (void) CopyXPMColor(target,q,MagickMin((size_t) (next-q),
376 (void) CopyMagickString(target,q,MaxTextExtent);
377 q=ParseXPMColor(target);
378 if (q != (char *) NULL)
382 if (LocaleCompare(target,"none") == 0)
384 image->storage_class=DirectClass;
385 image->matte=MagickTrue;
387 status=QueryColorCompliance(target,AllCompliance,&image->colormap[j],
389 if (status == MagickFalse)
392 if (j < (ssize_t) image->colors)
393 ThrowReaderException(CorruptImageError,"CorruptImage");
395 if (image_info->ping == MagickFalse)
400 for (y=0; y < (ssize_t) image->rows; y++)
403 if (p == (char *) NULL)
405 r=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
406 if (r == (PixelPacket *) NULL)
408 indexes=GetAuthenticIndexQueue(image);
409 for (x=0; x < (ssize_t) image->columns; x++)
411 (void) CopyXPMColor(key,p,(size_t) width);
412 j=(ssize_t) GetValueFromSplayTree(xpm_colors,key);
413 if (image->storage_class == PseudoClass)
414 indexes[x]=(IndexPacket) j;
415 *r=image->colormap[j];
419 if (SyncAuthenticPixels(image,exception) == MagickFalse)
422 if (y < (ssize_t) image->rows)
423 ThrowReaderException(CorruptImageError,"NotEnoughPixelData");
426 Relinquish resources.
428 xpm_colors=DestroySplayTree(xpm_colors);
429 (void) CloseBlob(image);
430 return(GetFirstImageInList(image));
434 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
438 % R e g i s t e r X P M I m a g e %
442 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
444 % RegisterXPMImage() adds attributes for the XPM image format to
445 % the list of supported formats. The attributes include the image format
446 % tag, a method to read and/or write the format, whether the format
447 % supports the saving of more than one frame to the same file or blob,
448 % whether the format supports native in-memory I/O, and a brief
449 % description of the format.
451 % The format of the RegisterXPMImage method is:
453 % size_t RegisterXPMImage(void)
456 ModuleExport size_t RegisterXPMImage(void)
461 entry=SetMagickInfo("PICON");
462 entry->decoder=(DecodeImageHandler *) ReadXPMImage;
463 entry->encoder=(EncodeImageHandler *) WritePICONImage;
464 entry->adjoin=MagickFalse;
465 entry->description=ConstantString("Personal Icon");
466 entry->module=ConstantString("XPM");
467 (void) RegisterMagickInfo(entry);
468 entry=SetMagickInfo("PM");
469 entry->decoder=(DecodeImageHandler *) ReadXPMImage;
470 entry->encoder=(EncodeImageHandler *) WriteXPMImage;
471 entry->adjoin=MagickFalse;
472 entry->stealth=MagickTrue;
473 entry->description=ConstantString("X Windows system pixmap (color)");
474 entry->module=ConstantString("XPM");
475 (void) RegisterMagickInfo(entry);
476 entry=SetMagickInfo("XPM");
477 entry->decoder=(DecodeImageHandler *) ReadXPMImage;
478 entry->encoder=(EncodeImageHandler *) WriteXPMImage;
479 entry->magick=(IsImageFormatHandler *) IsXPM;
480 entry->adjoin=MagickFalse;
481 entry->description=ConstantString("X Windows system pixmap (color)");
482 entry->module=ConstantString("XPM");
483 (void) RegisterMagickInfo(entry);
484 return(MagickImageCoderSignature);
488 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
492 % U n r e g i s t e r X P M I m a g e %
496 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
498 % UnregisterXPMImage() removes format registrations made by the
499 % XPM module from the list of supported formats.
501 % The format of the UnregisterXPMImage method is:
503 % UnregisterXPMImage(void)
506 ModuleExport void UnregisterXPMImage(void)
508 (void) UnregisterMagickInfo("PICON");
509 (void) UnregisterMagickInfo("PM");
510 (void) UnregisterMagickInfo("XPM");
514 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
518 % W r i t e P I C O N I m a g e %
522 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
524 % WritePICONImage() writes an image to a file in the Personal Icon format.
526 % The format of the WritePICONImage method is:
528 % MagickBooleanType WritePICONImage(const ImageInfo *image_info,
531 % A description of each parameter follows.
533 % o image_info: the image info.
535 % o image: The image.
538 static MagickBooleanType WritePICONImage(const ImageInfo *image_info,
541 #define ColormapExtent 155
542 #define GraymapExtent 95
543 #define PiconGeometry "48x48>"
548 0x47, 0x49, 0x46, 0x38, 0x37, 0x61, 0x06, 0x00, 0x05, 0x00, 0xf4, 0x05,
549 0x00, 0x00, 0x00, 0x00, 0x2f, 0x4f, 0x4f, 0x70, 0x80, 0x90, 0x7e, 0x7e,
550 0x7e, 0xdc, 0xdc, 0xdc, 0xff, 0xff, 0xff, 0x00, 0x00, 0x80, 0x00, 0x00,
551 0xff, 0x1e, 0x90, 0xff, 0x87, 0xce, 0xeb, 0xe6, 0xe6, 0xfa, 0x00, 0xff,
552 0xff, 0x80, 0x00, 0x80, 0xb2, 0x22, 0x22, 0x2e, 0x8b, 0x57, 0x32, 0xcd,
553 0x32, 0x00, 0xff, 0x00, 0x98, 0xfb, 0x98, 0xff, 0x00, 0xff, 0xff, 0x00,
554 0x00, 0xff, 0x63, 0x47, 0xff, 0xa5, 0x00, 0xff, 0xd7, 0x00, 0xff, 0xff,
555 0x00, 0xee, 0x82, 0xee, 0xa0, 0x52, 0x2d, 0xcd, 0x85, 0x3f, 0xd2, 0xb4,
556 0x8c, 0xf5, 0xde, 0xb3, 0xff, 0xfa, 0xcd, 0x00, 0x00, 0x00, 0x00, 0x00,
557 0x00, 0x21, 0xf9, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00,
558 0x00, 0x00, 0x06, 0x00, 0x05, 0x00, 0x00, 0x05, 0x18, 0x20, 0x10, 0x08,
559 0x03, 0x51, 0x18, 0x07, 0x92, 0x28, 0x0b, 0xd3, 0x38, 0x0f, 0x14, 0x49,
560 0x13, 0x55, 0x59, 0x17, 0x96, 0x69, 0x1b, 0xd7, 0x85, 0x00, 0x3b,
564 0x47, 0x49, 0x46, 0x38, 0x37, 0x61, 0x04, 0x00, 0x04, 0x00, 0xf3, 0x0f,
565 0x00, 0x00, 0x00, 0x00, 0x12, 0x12, 0x12, 0x21, 0x21, 0x21, 0x33, 0x33,
566 0x33, 0x45, 0x45, 0x45, 0x54, 0x54, 0x54, 0x66, 0x66, 0x66, 0x78, 0x78,
567 0x78, 0x87, 0x87, 0x87, 0x99, 0x99, 0x99, 0xab, 0xab, 0xab, 0xba, 0xba,
568 0xba, 0xcc, 0xcc, 0xcc, 0xde, 0xde, 0xde, 0xed, 0xed, 0xed, 0xff, 0xff,
569 0xff, 0x21, 0xf9, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00,
570 0x00, 0x00, 0x04, 0x00, 0x04, 0x00, 0x00, 0x04, 0x0c, 0x10, 0x04, 0x31,
571 0x48, 0x31, 0x07, 0x25, 0xb5, 0x58, 0x73, 0x4f, 0x04, 0x00, 0x3b,
577 Cixel[MaxCixels+1] = " .XoO+@#$%&*=-;:>,<1234567890qwertyuipasdfghjk"
578 "lzxcvbnmMNBVCZASDFGHJKLPIUYTREWQ!~^/()_`'][{}|";
581 buffer[MaxTextExtent],
582 basename[MaxTextExtent],
584 symbol[MaxTextExtent];
614 register const IndexPacket
617 register const PixelPacket
628 characters_per_pixel,
632 Open output image file.
634 assert(image_info != (const ImageInfo *) NULL);
635 assert(image_info->signature == MagickSignature);
636 assert(image != (Image *) NULL);
637 assert(image->signature == MagickSignature);
638 if (image->debug != MagickFalse)
639 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
640 status=OpenBlob(image_info,image,WriteBinaryBlobMode,&image->exception);
641 if (status == MagickFalse)
643 if (image->colorspace != RGBColorspace)
644 (void) TransformImageColorspace(image,RGBColorspace);
645 SetGeometry(image,&geometry);
646 (void) ParseMetaGeometry(PiconGeometry,&geometry.x,&geometry.y,
647 &geometry.width,&geometry.height);
648 picon=ResizeImage(image,geometry.width,geometry.height,TriangleFilter,1.0,
650 blob_info=CloneImageInfo(image_info);
651 (void) AcquireUniqueFilename(blob_info->filename);
652 if ((image_info->type != TrueColorType) &&
653 (IsGrayImage(image,&image->exception) != MagickFalse))
654 affinity_image=BlobToImage(blob_info,Graymap,GraymapExtent,
657 affinity_image=BlobToImage(blob_info,Colormap,ColormapExtent,
659 (void) RelinquishUniqueFileResource(blob_info->filename);
660 blob_info=DestroyImageInfo(blob_info);
661 if ((picon == (Image *) NULL) || (affinity_image == (Image *) NULL))
663 quantize_info=AcquireQuantizeInfo(image_info);
664 status=RemapImage(quantize_info,picon,affinity_image);
665 quantize_info=DestroyQuantizeInfo(quantize_info);
666 affinity_image=DestroyImage(affinity_image);
667 transparent=MagickFalse;
668 exception=(&image->exception);
669 if (picon->storage_class == PseudoClass)
671 (void) CompressImageColormap(picon);
672 if (picon->matte != MagickFalse)
673 transparent=MagickTrue;
678 Convert DirectClass to PseudoClass picon.
680 if (picon->matte != MagickFalse)
683 Map all the transparent pixels.
685 for (y=0; y < (ssize_t) picon->rows; y++)
687 q=GetAuthenticPixels(picon,0,y,picon->columns,1,exception);
688 if (q == (PixelPacket *) NULL)
690 for (x=0; x < (ssize_t) picon->columns; x++)
692 if (q->opacity == (Quantum) TransparentOpacity)
693 transparent=MagickTrue;
695 SetOpacityPixelComponent(q,OpaqueOpacity);
698 if (SyncAuthenticPixels(picon,exception) == MagickFalse)
702 (void) SetImageType(picon,PaletteType);
704 colors=picon->colors;
705 if (transparent != MagickFalse)
711 picon->colormap=(PixelPacket *) ResizeQuantumMemory((void **)
712 picon->colormap,(size_t) colors,sizeof(*picon->colormap));
713 if (picon->colormap == (PixelPacket *) NULL)
714 ThrowWriterException(ResourceLimitError,"MemoryAllocationError");
715 for (y=0; y < (ssize_t) picon->rows; y++)
717 q=GetAuthenticPixels(picon,0,y,picon->columns,1,exception);
718 if (q == (PixelPacket *) NULL)
720 indexes=GetAuthenticIndexQueue(picon);
721 for (x=0; x < (ssize_t) picon->columns; x++)
723 if (q->opacity == (Quantum) TransparentOpacity)
724 indexes[x]=(IndexPacket) picon->colors;
727 if (SyncAuthenticPixels(picon,exception) == MagickFalse)
732 Compute the character per pixel.
734 characters_per_pixel=1;
735 for (k=MaxCixels; (ssize_t) colors > k; k*=MaxCixels)
736 characters_per_pixel++;
740 (void) WriteBlobString(image,"/* XPM */\n");
741 GetPathComponent(picon->filename,BasePath,basename);
742 (void) FormatMagickString(buffer,MaxTextExtent,
743 "static char *%s[] = {\n",basename);
744 (void) WriteBlobString(image,buffer);
745 (void) WriteBlobString(image,"/* columns rows colors chars-per-pixel */\n");
746 (void) FormatMagickString(buffer,MaxTextExtent,
747 "\"%.20g %.20g %.20g %.20g\",\n",(double) picon->columns,(double)
748 picon->rows,(double) colors,(double) characters_per_pixel);
749 (void) WriteBlobString(image,buffer);
750 GetMagickPixelPacket(image,&pixel);
751 for (i=0; i < (ssize_t) colors; i++)
756 SetMagickPixelPacket(image,picon->colormap+i,(IndexPacket *) NULL,&pixel);
757 pixel.colorspace=RGBColorspace;
759 pixel.opacity=(MagickRealType) OpaqueOpacity;
760 (void) QueryMagickColorname(image,&pixel,XPMCompliance,name,
762 if (transparent != MagickFalse)
764 if (i == (ssize_t) (colors-1))
765 (void) CopyMagickString(name,"grey75",MaxTextExtent);
772 for (j=1; j < (ssize_t) characters_per_pixel; j++)
774 k=((i-k)/MaxCixels) % MaxCixels;
778 (void) FormatMagickString(buffer,MaxTextExtent,"\"%s c %s\",\n",
780 (void) WriteBlobString(image,buffer);
785 (void) WriteBlobString(image,"/* pixels */\n");
786 for (y=0; y < (ssize_t) picon->rows; y++)
788 p=GetVirtualPixels(picon,0,y,picon->columns,1,&picon->exception);
789 if (p == (const PixelPacket *) NULL)
791 indexes=GetVirtualIndexQueue(picon);
792 (void) WriteBlobString(image,"\"");
793 for (x=0; x < (ssize_t) picon->columns; x++)
795 k=((ssize_t) indexes[x] % MaxCixels);
797 for (j=1; j < (ssize_t) characters_per_pixel; j++)
799 k=(((int) indexes[x]-k)/MaxCixels) % MaxCixels;
803 (void) CopyMagickString(buffer,symbol,MaxTextExtent);
804 (void) WriteBlobString(image,buffer);
806 (void) FormatMagickString(buffer,MaxTextExtent,"\"%s\n",
807 y == (ssize_t) (picon->rows-1) ? "" : ",");
808 (void) WriteBlobString(image,buffer);
809 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
811 if (status == MagickFalse)
814 picon=DestroyImage(picon);
815 (void) WriteBlobString(image,"};\n");
816 (void) CloseBlob(image);
821 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
825 % W r i t e X P M I m a g e %
829 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
831 % WriteXPMImage() writes an image to a file in the X pixmap format.
833 % The format of the WriteXPMImage method is:
835 % MagickBooleanType WriteXPMImage(const ImageInfo *image_info,Image *image)
837 % A description of each parameter follows.
839 % o image_info: the image info.
841 % o image: The image.
844 static MagickBooleanType WriteXPMImage(const ImageInfo *image_info,Image *image)
849 Cixel[MaxCixels+1] = " .XoO+@#$%&*=-;:>,<1234567890qwertyuipasdfghjk"
850 "lzxcvbnmMNBVCZASDFGHJKLPIUYTREWQ!~^/()_`'][{}|";
853 buffer[MaxTextExtent],
854 basename[MaxTextExtent],
856 symbol[MaxTextExtent];
870 register const IndexPacket
873 register const PixelPacket
881 characters_per_pixel;
884 Open output image file.
886 assert(image_info != (const ImageInfo *) NULL);
887 assert(image_info->signature == MagickSignature);
888 assert(image != (Image *) NULL);
889 assert(image->signature == MagickSignature);
890 if (image->debug != MagickFalse)
891 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
892 status=OpenBlob(image_info,image,WriteBinaryBlobMode,&image->exception);
893 if (status == MagickFalse)
895 if (image->colorspace != RGBColorspace)
896 (void) TransformImageColorspace(image,RGBColorspace);
898 if (image->matte == MagickFalse)
900 if ((image->storage_class == DirectClass) || (image->colors > 256))
901 (void) SetImageType(image,PaletteType);
910 Identify transparent colormap index.
912 if ((image->storage_class == DirectClass) || (image->colors > 256))
913 (void) SetImageType(image,PaletteBilevelMatteType);
914 for (i=0; i < (ssize_t) image->colors; i++)
915 if (image->colormap[i].opacity != OpaqueOpacity)
922 alpha=(Quantum) TransparentOpacity-(MagickRealType)
923 image->colormap[i].opacity;
924 beta=(Quantum) TransparentOpacity-(MagickRealType)
925 image->colormap[opacity].opacity;
931 (void) SetImageType(image,PaletteBilevelMatteType);
932 for (i=0; i < (ssize_t) image->colors; i++)
933 if (image->colormap[i].opacity != OpaqueOpacity)
940 alpha=(Quantum) TransparentOpacity-(MagickRealType)
941 image->colormap[i].opacity;
942 beta=(Quantum) TransparentOpacity-(MagickRealType)
943 image->colormap[opacity].opacity;
950 image->colormap[opacity].red=image->transparent_color.red;
951 image->colormap[opacity].green=image->transparent_color.green;
952 image->colormap[opacity].blue=image->transparent_color.blue;
956 Compute the character per pixel.
958 characters_per_pixel=1;
959 for (k=MaxCixels; (ssize_t) image->colors > k; k*=MaxCixels)
960 characters_per_pixel++;
964 (void) WriteBlobString(image,"/* XPM */\n");
965 GetPathComponent(image->filename,BasePath,basename);
966 if (isalnum((int) ((unsigned char) *basename)) == 0)
968 (void) FormatMagickString(buffer,MaxTextExtent,"xpm_%s",basename);
969 (void) CopyMagickString(basename,buffer,MaxTextExtent);
971 for (i=0; basename[i] != '\0'; i++)
972 if (isalpha((int) ((unsigned char) basename[i])) == 0)
974 (void) FormatMagickString(buffer,MaxTextExtent,
975 "static char *%s[] = {\n",basename);
976 (void) WriteBlobString(image,buffer);
977 (void) WriteBlobString(image,"/* columns rows colors chars-per-pixel */\n");
978 (void) FormatMagickString(buffer,MaxTextExtent,
979 "\"%.20g %.20g %.20g %.20g \",\n",(double) image->columns,(double)
980 image->rows,(double) image->colors,(double) characters_per_pixel);
981 (void) WriteBlobString(image,buffer);
982 GetMagickPixelPacket(image,&pixel);
983 for (i=0; i < (ssize_t) image->colors; i++)
988 SetMagickPixelPacket(image,image->colormap+i,(IndexPacket *) NULL,&pixel);
989 pixel.colorspace=RGBColorspace;
991 pixel.opacity=(MagickRealType) OpaqueOpacity;
992 (void) QueryMagickColorname(image,&pixel,XPMCompliance,name,
995 (void) CopyMagickString(name,"None",MaxTextExtent);
1001 for (j=1; j < (ssize_t) characters_per_pixel; j++)
1003 k=((i-k)/MaxCixels) % MaxCixels;
1007 (void) FormatMagickString(buffer,MaxTextExtent,"\"%s c %s\",\n",symbol,
1009 (void) WriteBlobString(image,buffer);
1014 (void) WriteBlobString(image,"/* pixels */\n");
1015 for (y=0; y < (ssize_t) image->rows; y++)
1017 p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception);
1018 if (p == (const PixelPacket *) NULL)
1020 indexes=GetVirtualIndexQueue(image);
1021 (void) WriteBlobString(image,"\"");
1022 for (x=0; x < (ssize_t) image->columns; x++)
1024 k=((ssize_t) indexes[x] % MaxCixels);
1026 for (j=1; j < (ssize_t) characters_per_pixel; j++)
1028 k=(((int) indexes[x]-k)/MaxCixels) % MaxCixels;
1032 (void) CopyMagickString(buffer,symbol,MaxTextExtent);
1033 (void) WriteBlobString(image,buffer);
1035 (void) FormatMagickString(buffer,MaxTextExtent,"\"%s\n",
1036 (y == (ssize_t) (image->rows-1) ? "" : ","));
1037 (void) WriteBlobString(image,buffer);
1038 if (image->previous == (Image *) NULL)
1040 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
1042 if (status == MagickFalse)
1046 (void) WriteBlobString(image,"};\n");
1047 (void) CloseBlob(image);