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/exception.h"
52 #include "MagickCore/exception-private.h"
53 #include "MagickCore/geometry.h"
54 #include "MagickCore/image.h"
55 #include "MagickCore/image-private.h"
56 #include "MagickCore/list.h"
57 #include "MagickCore/magick.h"
58 #include "MagickCore/memory_.h"
59 #include "MagickCore/monitor.h"
60 #include "MagickCore/monitor-private.h"
61 #include "MagickCore/pixel-accessor.h"
62 #include "MagickCore/quantize.h"
63 #include "MagickCore/quantum-private.h"
64 #include "MagickCore/resize.h"
65 #include "MagickCore/resource_.h"
66 #include "MagickCore/splay-tree.h"
67 #include "MagickCore/static.h"
68 #include "MagickCore/string_.h"
69 #include "MagickCore/module.h"
70 #include "MagickCore/threshold.h"
71 #include "MagickCore/utility.h"
76 static MagickBooleanType
77 WritePICONImage(const ImageInfo *,Image *),
78 WriteXPMImage(const ImageInfo *,Image *);
81 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
89 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
91 % IsXPM() returns MagickTrue if the image format type, identified by the
92 % magick string, is XPM.
94 % The format of the IsXPM method is:
96 % MagickBooleanType IsXPM(const unsigned char *magick,const size_t length)
98 % A description of each parameter follows:
100 % o magick: compare image format pattern against these bytes. or
103 % o length: Specifies the length of the magick string.
106 static MagickBooleanType IsXPM(const unsigned char *magick,const size_t length)
110 if (LocaleNCompare((char *) magick+1,"* XPM *",7) == 0)
116 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
120 % R e a d X P M I m a g e %
124 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
126 % ReadXPMImage() reads an X11 pixmap image file and returns it. It
127 % allocates the memory necessary for the new Image structure and returns a
128 % pointer to the new image.
130 % The format of the ReadXPMImage method is:
132 % Image *ReadXPMImage(const ImageInfo *image_info,ExceptionInfo *exception)
134 % A description of each parameter follows:
136 % o image_info: the image info.
138 % o exception: return any errors or warnings in this structure.
142 static int CompareXPMColor(const void *target,const void *source)
148 p=(const char *) target;
149 q=(const char *) source;
153 static char *CopyXPMColor(char *destination,const char *source,size_t length)
155 while (length-- && (*source != '\0'))
156 *destination++=(*source++);
158 return(destination-length);
161 static char *NextXPMLine(char *p)
163 assert(p != (char*)NULL);
165 if (p != (char *) NULL)
170 static inline size_t MagickMin(const size_t x,const size_t y)
177 static char *ParseXPMColor(char *color)
179 #define NumberTargets 6
192 *targets[NumberTargets] = { "c ", "g ", "g4 ", "m ", "b ", "s " };
194 for (i=0; i < NumberTargets; i++)
197 for (q=targets[i]; *p != '\0'; p++)
203 if (isspace((int) ((unsigned char) (*(p-1)))) == 0)
216 return((char *) NULL);
219 static Image *ReadXPMImage(const ImageInfo *image_info,ExceptionInfo *exception)
223 target[MaxTextExtent],
264 assert(image_info != (const ImageInfo *) NULL);
265 assert(image_info->signature == MagickSignature);
266 if (image_info->debug != MagickFalse)
267 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
268 image_info->filename);
269 assert(exception != (ExceptionInfo *) NULL);
270 assert(exception->signature == MagickSignature);
271 image=AcquireImage(image_info);
272 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
273 if (status == MagickFalse)
275 image=DestroyImageList(image);
276 return((Image *) NULL);
281 length=MaxTextExtent;
282 xpm_buffer=(char *) AcquireQuantumMemory((size_t) length,sizeof(*xpm_buffer));
284 if (xpm_buffer != (char *) NULL)
285 while (ReadBlobString(image,p) != (char *) NULL)
287 if ((*p == '#') && ((p == xpm_buffer) || (*(p-1) == '\n')))
289 if ((*p == '}') && (*(p+1) == ';'))
292 if ((size_t) (p-xpm_buffer+MaxTextExtent) < length)
295 xpm_buffer=(char *) ResizeQuantumMemory(xpm_buffer,length+MaxTextExtent,
296 sizeof(*xpm_buffer));
297 if (xpm_buffer == (char *) NULL)
299 p=xpm_buffer+strlen(xpm_buffer);
301 if (xpm_buffer == (char *) NULL)
302 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
307 for (p=xpm_buffer; *p != '\0'; p++)
311 count=(ssize_t) sscanf(p+1,"%lu %lu %lu %lu",&columns,&rows,&colors,&width);
312 image->columns=columns;
314 image->colors=colors;
318 if ((count != 4) || (width > 10) || (image->columns == 0) ||
319 (image->rows == 0) || (image->colors == 0))
320 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
323 Remove unquoted characters.
331 if (active != MagickFalse)
333 active=active != MagickFalse ? MagickFalse : MagickTrue;
335 if (active != MagickFalse)
340 Initialize image structure.
342 xpm_colors=NewSplayTree(CompareXPMColor,RelinquishMagickMemory,
343 (void *(*)(void *)) NULL);
344 if (AcquireImageColormap(image,image->colors) == MagickFalse)
345 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
349 next=NextXPMLine(xpm_buffer);
350 for (j=0; (j < (ssize_t) image->colors) && (next != (char*) NULL); j++)
354 (void) CopyXPMColor(key,p,MagickMin((size_t) width,MaxTextExtent));
355 status=AddValueToSplayTree(xpm_colors,ConstantString(key),(void *) j);
359 (void) CopyMagickString(target,"gray",MaxTextExtent);
360 q=ParseXPMColor(p+width);
361 if (q != (char *) NULL)
363 while ((isspace((int) ((unsigned char) *q)) == 0) && (*q != '\0'))
365 if (next != (char *) NULL)
366 (void) CopyXPMColor(target,q,MagickMin((size_t) (next-q),
369 (void) CopyMagickString(target,q,MaxTextExtent);
370 q=ParseXPMColor(target);
371 if (q != (char *) NULL)
375 if (LocaleCompare(target,"none") == 0)
377 image->storage_class=DirectClass;
378 image->matte=MagickTrue;
380 status=QueryColorCompliance(target,AllCompliance,&image->colormap[j],
382 if (status == MagickFalse)
385 if (j < (ssize_t) image->colors)
386 ThrowReaderException(CorruptImageError,"CorruptImage");
388 if (image_info->ping == MagickFalse)
393 for (y=0; y < (ssize_t) image->rows; y++)
396 if (p == (char *) NULL)
398 r=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
399 if (r == (Quantum *) NULL)
401 for (x=0; x < (ssize_t) image->columns; x++)
403 (void) CopyXPMColor(key,p,(size_t) width);
404 j=(ssize_t) GetValueFromSplayTree(xpm_colors,key);
405 if (image->storage_class == PseudoClass)
406 SetPixelIndex(image,j,r);
407 SetPixelPacket(image,image->colormap+j,r);
409 r+=GetPixelChannels(image);
411 if (SyncAuthenticPixels(image,exception) == MagickFalse)
414 if (y < (ssize_t) image->rows)
415 ThrowReaderException(CorruptImageError,"NotEnoughPixelData");
418 Relinquish resources.
420 xpm_colors=DestroySplayTree(xpm_colors);
421 (void) CloseBlob(image);
422 return(GetFirstImageInList(image));
426 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
430 % R e g i s t e r X P M I m a g e %
434 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
436 % RegisterXPMImage() adds attributes for the XPM image format to
437 % the list of supported formats. The attributes include the image format
438 % tag, a method to read and/or write the format, whether the format
439 % supports the saving of more than one frame to the same file or blob,
440 % whether the format supports native in-memory I/O, and a brief
441 % description of the format.
443 % The format of the RegisterXPMImage method is:
445 % size_t RegisterXPMImage(void)
448 ModuleExport size_t RegisterXPMImage(void)
453 entry=SetMagickInfo("PICON");
454 entry->decoder=(DecodeImageHandler *) ReadXPMImage;
455 entry->encoder=(EncodeImageHandler *) WritePICONImage;
456 entry->adjoin=MagickFalse;
457 entry->description=ConstantString("Personal Icon");
458 entry->module=ConstantString("XPM");
459 (void) RegisterMagickInfo(entry);
460 entry=SetMagickInfo("PM");
461 entry->decoder=(DecodeImageHandler *) ReadXPMImage;
462 entry->encoder=(EncodeImageHandler *) WriteXPMImage;
463 entry->adjoin=MagickFalse;
464 entry->stealth=MagickTrue;
465 entry->description=ConstantString("X Windows system pixmap (color)");
466 entry->module=ConstantString("XPM");
467 (void) RegisterMagickInfo(entry);
468 entry=SetMagickInfo("XPM");
469 entry->decoder=(DecodeImageHandler *) ReadXPMImage;
470 entry->encoder=(EncodeImageHandler *) WriteXPMImage;
471 entry->magick=(IsImageFormatHandler *) IsXPM;
472 entry->adjoin=MagickFalse;
473 entry->description=ConstantString("X Windows system pixmap (color)");
474 entry->module=ConstantString("XPM");
475 (void) RegisterMagickInfo(entry);
476 return(MagickImageCoderSignature);
480 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
484 % U n r e g i s t e r X P M I m a g e %
488 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
490 % UnregisterXPMImage() removes format registrations made by the
491 % XPM module from the list of supported formats.
493 % The format of the UnregisterXPMImage method is:
495 % UnregisterXPMImage(void)
498 ModuleExport void UnregisterXPMImage(void)
500 (void) UnregisterMagickInfo("PICON");
501 (void) UnregisterMagickInfo("PM");
502 (void) UnregisterMagickInfo("XPM");
506 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
510 % W r i t e P I C O N I m a g e %
514 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
516 % WritePICONImage() writes an image to a file in the Personal Icon format.
518 % The format of the WritePICONImage method is:
520 % MagickBooleanType WritePICONImage(const ImageInfo *image_info,
523 % A description of each parameter follows.
525 % o image_info: the image info.
527 % o image: The image.
530 static MagickBooleanType WritePICONImage(const ImageInfo *image_info,
533 #define ColormapExtent 155
534 #define GraymapExtent 95
535 #define PiconGeometry "48x48>"
540 0x47, 0x49, 0x46, 0x38, 0x37, 0x61, 0x06, 0x00, 0x05, 0x00, 0xf4, 0x05,
541 0x00, 0x00, 0x00, 0x00, 0x2f, 0x4f, 0x4f, 0x70, 0x80, 0x90, 0x7e, 0x7e,
542 0x7e, 0xdc, 0xdc, 0xdc, 0xff, 0xff, 0xff, 0x00, 0x00, 0x80, 0x00, 0x00,
543 0xff, 0x1e, 0x90, 0xff, 0x87, 0xce, 0xeb, 0xe6, 0xe6, 0xfa, 0x00, 0xff,
544 0xff, 0x80, 0x00, 0x80, 0xb2, 0x22, 0x22, 0x2e, 0x8b, 0x57, 0x32, 0xcd,
545 0x32, 0x00, 0xff, 0x00, 0x98, 0xfb, 0x98, 0xff, 0x00, 0xff, 0xff, 0x00,
546 0x00, 0xff, 0x63, 0x47, 0xff, 0xa5, 0x00, 0xff, 0xd7, 0x00, 0xff, 0xff,
547 0x00, 0xee, 0x82, 0xee, 0xa0, 0x52, 0x2d, 0xcd, 0x85, 0x3f, 0xd2, 0xb4,
548 0x8c, 0xf5, 0xde, 0xb3, 0xff, 0xfa, 0xcd, 0x00, 0x00, 0x00, 0x00, 0x00,
549 0x00, 0x21, 0xf9, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00,
550 0x00, 0x00, 0x06, 0x00, 0x05, 0x00, 0x00, 0x05, 0x18, 0x20, 0x10, 0x08,
551 0x03, 0x51, 0x18, 0x07, 0x92, 0x28, 0x0b, 0xd3, 0x38, 0x0f, 0x14, 0x49,
552 0x13, 0x55, 0x59, 0x17, 0x96, 0x69, 0x1b, 0xd7, 0x85, 0x00, 0x3b,
556 0x47, 0x49, 0x46, 0x38, 0x37, 0x61, 0x04, 0x00, 0x04, 0x00, 0xf3, 0x0f,
557 0x00, 0x00, 0x00, 0x00, 0x12, 0x12, 0x12, 0x21, 0x21, 0x21, 0x33, 0x33,
558 0x33, 0x45, 0x45, 0x45, 0x54, 0x54, 0x54, 0x66, 0x66, 0x66, 0x78, 0x78,
559 0x78, 0x87, 0x87, 0x87, 0x99, 0x99, 0x99, 0xab, 0xab, 0xab, 0xba, 0xba,
560 0xba, 0xcc, 0xcc, 0xcc, 0xde, 0xde, 0xde, 0xed, 0xed, 0xed, 0xff, 0xff,
561 0xff, 0x21, 0xf9, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00,
562 0x00, 0x00, 0x04, 0x00, 0x04, 0x00, 0x00, 0x04, 0x0c, 0x10, 0x04, 0x31,
563 0x48, 0x31, 0x07, 0x25, 0xb5, 0x58, 0x73, 0x4f, 0x04, 0x00, 0x3b,
569 Cixel[MaxCixels+1] = " .XoO+@#$%&*=-;:>,<1234567890qwertyuipasdfghjk"
570 "lzxcvbnmMNBVCZASDFGHJKLPIUYTREWQ!~^/()_`'][{}|";
573 buffer[MaxTextExtent],
574 basename[MaxTextExtent],
576 symbol[MaxTextExtent];
601 register const Quantum
612 characters_per_pixel,
621 Open output image file.
623 assert(image_info != (const ImageInfo *) NULL);
624 assert(image_info->signature == MagickSignature);
625 assert(image != (Image *) NULL);
626 assert(image->signature == MagickSignature);
627 if (image->debug != MagickFalse)
628 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
629 status=OpenBlob(image_info,image,WriteBinaryBlobMode,&image->exception);
630 if (status == MagickFalse)
632 if (image->colorspace != RGBColorspace)
633 (void) TransformImageColorspace(image,RGBColorspace);
634 SetGeometry(image,&geometry);
635 (void) ParseMetaGeometry(PiconGeometry,&geometry.x,&geometry.y,
636 &geometry.width,&geometry.height);
637 picon=ResizeImage(image,geometry.width,geometry.height,TriangleFilter,1.0,
639 blob_info=CloneImageInfo(image_info);
640 (void) AcquireUniqueFilename(blob_info->filename);
641 if ((image_info->type != TrueColorType) &&
642 (IsImageGray(image,&image->exception) != MagickFalse))
643 affinity_image=BlobToImage(blob_info,Graymap,GraymapExtent,
646 affinity_image=BlobToImage(blob_info,Colormap,ColormapExtent,
648 (void) RelinquishUniqueFileResource(blob_info->filename);
649 blob_info=DestroyImageInfo(blob_info);
650 if ((picon == (Image *) NULL) || (affinity_image == (Image *) NULL))
652 quantize_info=AcquireQuantizeInfo(image_info);
653 status=RemapImage(quantize_info,picon,affinity_image);
654 quantize_info=DestroyQuantizeInfo(quantize_info);
655 affinity_image=DestroyImage(affinity_image);
656 transparent=MagickFalse;
657 exception=(&image->exception);
658 if (picon->storage_class == PseudoClass)
660 (void) CompressImageColormap(picon);
661 if (picon->matte != MagickFalse)
662 transparent=MagickTrue;
667 Convert DirectClass to PseudoClass picon.
669 if (picon->matte != MagickFalse)
672 Map all the transparent pixels.
674 for (y=0; y < (ssize_t) picon->rows; y++)
676 q=GetAuthenticPixels(picon,0,y,picon->columns,1,exception);
677 if (q == (const Quantum *) NULL)
679 for (x=0; x < (ssize_t) picon->columns; x++)
681 if (GetPixelAlpha(image,q) == (Quantum) TransparentAlpha)
682 transparent=MagickTrue;
684 SetPixelAlpha(picon,OpaqueAlpha,q);
685 q+=GetPixelChannels(picon);
687 if (SyncAuthenticPixels(picon,exception) == MagickFalse)
691 (void) SetImageType(picon,PaletteType);
693 colors=picon->colors;
694 if (transparent != MagickFalse)
697 picon->colormap=(PixelPacket *) ResizeQuantumMemory((void **)
698 picon->colormap,(size_t) colors,sizeof(*picon->colormap));
699 if (picon->colormap == (PixelPacket *) NULL)
700 ThrowWriterException(ResourceLimitError,"MemoryAllocationError");
701 for (y=0; y < (ssize_t) picon->rows; y++)
703 q=GetAuthenticPixels(picon,0,y,picon->columns,1,exception);
704 if (q == (const Quantum *) NULL)
706 for (x=0; x < (ssize_t) picon->columns; x++)
708 if (GetPixelAlpha(image,q) == (Quantum) TransparentAlpha)
709 SetPixelIndex(picon,picon->colors,q);
710 q+=GetPixelChannels(picon);
712 if (SyncAuthenticPixels(picon,exception) == MagickFalse)
717 Compute the character per pixel.
719 characters_per_pixel=1;
720 for (k=MaxCixels; (ssize_t) colors > k; k*=MaxCixels)
721 characters_per_pixel++;
725 (void) WriteBlobString(image,"/* XPM */\n");
726 GetPathComponent(picon->filename,BasePath,basename);
727 (void) FormatLocaleString(buffer,MaxTextExtent,
728 "static char *%s[] = {\n",basename);
729 (void) WriteBlobString(image,buffer);
730 (void) WriteBlobString(image,"/* columns rows colors chars-per-pixel */\n");
731 (void) FormatLocaleString(buffer,MaxTextExtent,
732 "\"%.20g %.20g %.20g %.20g\",\n",(double) picon->columns,(double)
733 picon->rows,(double) colors,(double) characters_per_pixel);
734 (void) WriteBlobString(image,buffer);
735 GetPixelInfo(image,&pixel);
736 for (i=0; i < (ssize_t) colors; i++)
741 SetPixelInfoPacket(image,picon->colormap+i,&pixel);
742 pixel.colorspace=RGBColorspace;
744 pixel.alpha=(MagickRealType) OpaqueAlpha;
745 (void) QueryMagickColorname(image,&pixel,XPMCompliance,name,
747 if (transparent != MagickFalse)
749 if (i == (ssize_t) (colors-1))
750 (void) CopyMagickString(name,"grey75",MaxTextExtent);
757 for (j=1; j < (ssize_t) characters_per_pixel; j++)
759 k=((i-k)/MaxCixels) % MaxCixels;
763 (void) FormatLocaleString(buffer,MaxTextExtent,"\"%s c %s\",\n",
765 (void) WriteBlobString(image,buffer);
770 (void) WriteBlobString(image,"/* pixels */\n");
771 for (y=0; y < (ssize_t) picon->rows; y++)
773 p=GetVirtualPixels(picon,0,y,picon->columns,1,&picon->exception);
774 if (p == (const Quantum *) NULL)
776 (void) WriteBlobString(image,"\"");
777 for (x=0; x < (ssize_t) picon->columns; x++)
779 k=((ssize_t) GetPixelIndex(picon,p) % MaxCixels);
781 for (j=1; j < (ssize_t) characters_per_pixel; j++)
783 k=(((int) GetPixelIndex(picon,p)-k)/MaxCixels) % MaxCixels;
787 (void) CopyMagickString(buffer,symbol,MaxTextExtent);
788 (void) WriteBlobString(image,buffer);
789 p+=GetPixelChannels(image);
791 (void) FormatLocaleString(buffer,MaxTextExtent,"\"%s\n",
792 y == (ssize_t) (picon->rows-1) ? "" : ",");
793 (void) WriteBlobString(image,buffer);
794 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
796 if (status == MagickFalse)
799 picon=DestroyImage(picon);
800 (void) WriteBlobString(image,"};\n");
801 (void) CloseBlob(image);
806 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
810 % W r i t e X P M I m a g e %
814 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
816 % WriteXPMImage() writes an image to a file in the X pixmap format.
818 % The format of the WriteXPMImage method is:
820 % MagickBooleanType WriteXPMImage(const ImageInfo *image_info,Image *image)
822 % A description of each parameter follows.
824 % o image_info: the image info.
826 % o image: The image.
829 static MagickBooleanType WriteXPMImage(const ImageInfo *image_info,Image *image)
834 Cixel[MaxCixels+1] = " .XoO+@#$%&*=-;:>,<1234567890qwertyuipasdfghjk"
835 "lzxcvbnmMNBVCZASDFGHJKLPIUYTREWQ!~^/()_`'][{}|";
838 buffer[MaxTextExtent],
839 basename[MaxTextExtent],
841 symbol[MaxTextExtent];
849 register const Quantum
857 characters_per_pixel;
866 Open output image file.
868 assert(image_info != (const ImageInfo *) NULL);
869 assert(image_info->signature == MagickSignature);
870 assert(image != (Image *) NULL);
871 assert(image->signature == MagickSignature);
872 if (image->debug != MagickFalse)
873 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
874 status=OpenBlob(image_info,image,WriteBinaryBlobMode,&image->exception);
875 if (status == MagickFalse)
877 if (image->colorspace != RGBColorspace)
878 (void) TransformImageColorspace(image,RGBColorspace);
880 if (image->matte == MagickFalse)
882 if ((image->storage_class == DirectClass) || (image->colors > 256))
883 (void) SetImageType(image,PaletteType);
892 Identify transparent colormap index.
894 if ((image->storage_class == DirectClass) || (image->colors > 256))
895 (void) SetImageType(image,PaletteBilevelMatteType);
896 for (i=0; i < (ssize_t) image->colors; i++)
897 if (image->colormap[i].alpha != OpaqueAlpha)
904 alpha=(MagickRealType) TransparentAlpha-(MagickRealType)
905 image->colormap[i].alpha;
906 beta=(MagickRealType) TransparentAlpha-(MagickRealType)
907 image->colormap[opacity].alpha;
913 (void) SetImageType(image,PaletteBilevelMatteType);
914 for (i=0; i < (ssize_t) image->colors; i++)
915 if (image->colormap[i].alpha != OpaqueAlpha)
922 alpha=(Quantum) TransparentAlpha-(MagickRealType)
923 image->colormap[i].alpha;
924 beta=(Quantum) TransparentAlpha-(MagickRealType)
925 image->colormap[opacity].alpha;
932 image->colormap[opacity].red=image->transparent_color.red;
933 image->colormap[opacity].green=image->transparent_color.green;
934 image->colormap[opacity].blue=image->transparent_color.blue;
938 Compute the character per pixel.
940 characters_per_pixel=1;
941 for (k=MaxCixels; (ssize_t) image->colors > k; k*=MaxCixels)
942 characters_per_pixel++;
946 (void) WriteBlobString(image,"/* XPM */\n");
947 GetPathComponent(image->filename,BasePath,basename);
948 if (isalnum((int) ((unsigned char) *basename)) == 0)
950 (void) FormatLocaleString(buffer,MaxTextExtent,"xpm_%s",basename);
951 (void) CopyMagickString(basename,buffer,MaxTextExtent);
953 if (isalpha((int) ((unsigned char) basename[0])) == 0)
955 for (i=1; basename[i] != '\0'; i++)
956 if (isalnum((int) ((unsigned char) basename[i])) == 0)
958 (void) FormatLocaleString(buffer,MaxTextExtent,
959 "static char *%s[] = {\n",basename);
960 (void) WriteBlobString(image,buffer);
961 (void) WriteBlobString(image,"/* columns rows colors chars-per-pixel */\n");
962 (void) FormatLocaleString(buffer,MaxTextExtent,
963 "\"%.20g %.20g %.20g %.20g \",\n",(double) image->columns,(double)
964 image->rows,(double) image->colors,(double) characters_per_pixel);
965 (void) WriteBlobString(image,buffer);
966 GetPixelInfo(image,&pixel);
967 for (i=0; i < (ssize_t) image->colors; i++)
972 SetPixelInfoPacket(image,image->colormap+i,&pixel);
973 pixel.colorspace=RGBColorspace;
975 pixel.alpha=(MagickRealType) OpaqueAlpha;
976 (void) QueryMagickColorname(image,&pixel,XPMCompliance,name,
979 (void) CopyMagickString(name,"None",MaxTextExtent);
985 for (j=1; j < (ssize_t) characters_per_pixel; j++)
987 k=((i-k)/MaxCixels) % MaxCixels;
991 (void) FormatLocaleString(buffer,MaxTextExtent,"\"%s c %s\",\n",symbol,
993 (void) WriteBlobString(image,buffer);
998 (void) WriteBlobString(image,"/* pixels */\n");
999 for (y=0; y < (ssize_t) image->rows; y++)
1001 p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception);
1002 if (p == (const Quantum *) NULL)
1004 (void) WriteBlobString(image,"\"");
1005 for (x=0; x < (ssize_t) image->columns; x++)
1007 k=((ssize_t) GetPixelIndex(image,p) % MaxCixels);
1009 for (j=1; j < (ssize_t) characters_per_pixel; j++)
1011 k=(((int) GetPixelIndex(image,p)-k)/MaxCixels) % MaxCixels;
1015 (void) CopyMagickString(buffer,symbol,MaxTextExtent);
1016 (void) WriteBlobString(image,buffer);
1017 p+=GetPixelChannels(image);
1019 (void) FormatLocaleString(buffer,MaxTextExtent,"\"%s\n",
1020 (y == (ssize_t) (image->rows-1) ? "" : ","));
1021 (void) WriteBlobString(image,buffer);
1022 if (image->previous == (Image *) NULL)
1024 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
1026 if (status == MagickFalse)
1030 (void) WriteBlobString(image,"};\n");
1031 (void) CloseBlob(image);