xpm.c revision dcfc1ad7e0ad199ccd86e9508e9c5775e4c4bbdb
1/* 2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 3% % 4% % 5% % 6% X X PPPP M M % 7% X X P P MM MM % 8% X PPPP M M M % 9% X X P M M % 10% X X P M M % 11% % 12% % 13% Read/Write X Windows system Pixmap Format % 14% % 15% Software Design % 16% John Cristy % 17% July 1992 % 18% % 19% % 20% Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization % 21% dedicated to making software imaging solutions freely available. % 22% % 23% You may not use this file except in compliance with the License. You may % 24% obtain a copy of the License at % 25% % 26% http://www.imagemagick.org/script/license.php % 27% % 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. % 33% % 34%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 35% 36% 37*/ 38 39/* 40 Include declarations. 41*/ 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" 73 74/* 75 Forward declarations. 76*/ 77static MagickBooleanType 78 WritePICONImage(const ImageInfo *,Image *), 79 WriteXPMImage(const ImageInfo *,Image *); 80 81/* 82%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 83% % 84% % 85% % 86% I s X P M % 87% % 88% % 89% % 90%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 91% 92% IsXPM() returns MagickTrue if the image format type, identified by the 93% magick string, is XPM. 94% 95% The format of the IsXPM method is: 96% 97% MagickBooleanType IsXPM(const unsigned char *magick,const size_t length) 98% 99% A description of each parameter follows: 100% 101% o magick: compare image format pattern against these bytes. or 102% blob. 103% 104% o length: Specifies the length of the magick string. 105% 106*/ 107static MagickBooleanType IsXPM(const unsigned char *magick,const size_t length) 108{ 109 if (length < 9) 110 return(MagickFalse); 111 if (LocaleNCompare((char *) magick+1,"* XPM *",7) == 0) 112 return(MagickTrue); 113 return(MagickFalse); 114} 115 116/* 117%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 118% % 119% % 120% % 121% R e a d X P M I m a g e % 122% % 123% % 124% % 125%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 126% 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. 130% 131% The format of the ReadXPMImage method is: 132% 133% Image *ReadXPMImage(const ImageInfo *image_info,ExceptionInfo *exception) 134% 135% A description of each parameter follows: 136% 137% o image_info: the image info. 138% 139% o exception: return any errors or warnings in this structure. 140% 141*/ 142 143static int CompareXPMColor(const void *target,const void *source) 144{ 145 const char 146 *p, 147 *q; 148 149 p=(const char *) target; 150 q=(const char *) source; 151 return(strcmp(p,q)); 152} 153 154static char *CopyXPMColor(char *destination,const char *source,size_t length) 155{ 156 while (length-- && (*source != '\0')) 157 *destination++=(*source++); 158 *destination='\0'; 159 return(destination-length); 160} 161 162static char *NextXPMLine(char *p) 163{ 164 assert(p != (char*)NULL); 165 p=strchr(p,'\n'); 166 if (p != (char *) NULL) 167 p++; 168 return(p); 169} 170 171static inline size_t MagickMin(const size_t x,const size_t y) 172{ 173 if (x < y) 174 return(x); 175 return(y); 176} 177 178static char *ParseXPMColor(char *color) 179{ 180#define NumberTargets 6 181 182 register char 183 *p, 184 *r; 185 186 register const char 187 *q; 188 189 register ssize_t 190 i; 191 192 static const char 193 *targets[NumberTargets] = { "c ", "g ", "g4 ", "m ", "b ", "s " }; 194 195 for (i=0; i < NumberTargets; i++) 196 { 197 p=color; 198 for (q=targets[i]; *p != '\0'; p++) 199 { 200 if (*p == '\n') 201 break; 202 if (*p != *q) 203 continue; 204 if (isspace((int) ((unsigned char) (*(p-1)))) == 0) 205 continue; 206 r=p; 207 for ( ; ; ) 208 { 209 if (*q == '\0') 210 return(p); 211 if (*r++ != *q++) 212 break; 213 } 214 q=targets[i]; 215 } 216 } 217 return((char *) NULL); 218} 219 220static Image *ReadXPMImage(const ImageInfo *image_info,ExceptionInfo *exception) 221{ 222 char 223 key[MaxTextExtent], 224 target[MaxTextExtent], 225 *xpm_buffer; 226 227 Image 228 *image; 229 230 MagickBooleanType 231 active, 232 status; 233 234 register char 235 *p, 236 *q, 237 *next; 238 239 register ssize_t 240 x; 241 242 register Quantum 243 *r; 244 245 size_t 246 length; 247 248 SplayTreeInfo 249 *xpm_colors; 250 251 ssize_t 252 count, 253 j, 254 y; 255 256 unsigned long 257 colors, 258 columns, 259 rows, 260 width; 261 262 /* 263 Open image file. 264 */ 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) 275 { 276 image=DestroyImageList(image); 277 return((Image *) NULL); 278 } 279 /* 280 Read XPM file. 281 */ 282 length=MaxTextExtent; 283 xpm_buffer=(char *) AcquireQuantumMemory((size_t) length,sizeof(*xpm_buffer)); 284 p=xpm_buffer; 285 if (xpm_buffer != (char *) NULL) 286 while (ReadBlobString(image,p) != (char *) NULL) 287 { 288 if ((*p == '#') && ((p == xpm_buffer) || (*(p-1) == '\n'))) 289 continue; 290 if ((*p == '}') && (*(p+1) == ';')) 291 break; 292 p+=strlen(p); 293 if ((size_t) (p-xpm_buffer+MaxTextExtent) < length) 294 continue; 295 length<<=1; 296 xpm_buffer=(char *) ResizeQuantumMemory(xpm_buffer,length+MaxTextExtent, 297 sizeof(*xpm_buffer)); 298 if (xpm_buffer == (char *) NULL) 299 break; 300 p=xpm_buffer+strlen(xpm_buffer); 301 } 302 if (xpm_buffer == (char *) NULL) 303 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed"); 304 /* 305 Remove comments. 306 */ 307 count=0; 308 for (p=xpm_buffer; *p != '\0'; p++) 309 { 310 if (*p != '"') 311 continue; 312 count=(ssize_t) sscanf(p+1,"%lu %lu %lu %lu",&columns,&rows,&colors,&width); 313 image->columns=columns; 314 image->rows=rows; 315 image->colors=colors; 316 if (count == 4) 317 break; 318 } 319 if ((count != 4) || (width > 10) || (image->columns == 0) || 320 (image->rows == 0) || (image->colors == 0)) 321 ThrowReaderException(CorruptImageError,"ImproperImageHeader"); 322 image->depth=16; 323 /* 324 Remove unquoted characters. 325 */ 326 active=MagickFalse; 327 q=xpm_buffer; 328 while (*p != '\0') 329 { 330 if (*p++ == '"') 331 { 332 if (active != MagickFalse) 333 *q++='\n'; 334 active=active != MagickFalse ? MagickFalse : MagickTrue; 335 } 336 if (active != MagickFalse) 337 *q++=(*p); 338 } 339 *q='\0'; 340 /* 341 Initialize image structure. 342 */ 343 xpm_colors=NewSplayTree(CompareXPMColor,RelinquishMagickMemory, 344 (void *(*)(void *)) NULL); 345 if (AcquireImageColormap(image,image->colors) == MagickFalse) 346 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed"); 347 /* 348 Read image colormap. 349 */ 350 next=NextXPMLine(xpm_buffer); 351 for (j=0; (j < (ssize_t) image->colors) && (next != (char*) NULL); j++) 352 { 353 p=next; 354 next=NextXPMLine(p); 355 (void) CopyXPMColor(key,p,MagickMin((size_t) width,MaxTextExtent)); 356 status=AddValueToSplayTree(xpm_colors,ConstantString(key),(void *) j); 357 /* 358 Parse color. 359 */ 360 (void) CopyMagickString(target,"gray",MaxTextExtent); 361 q=ParseXPMColor(p+width); 362 if (q != (char *) NULL) 363 { 364 while ((isspace((int) ((unsigned char) *q)) == 0) && (*q != '\0')) 365 q++; 366 if (next != (char *) NULL) 367 (void) CopyXPMColor(target,q,MagickMin((size_t) (next-q), 368 MaxTextExtent)); 369 else 370 (void) CopyMagickString(target,q,MaxTextExtent); 371 q=ParseXPMColor(target); 372 if (q != (char *) NULL) 373 *q='\0'; 374 } 375 StripString(target); 376 if (LocaleCompare(target,"none") == 0) 377 { 378 image->storage_class=DirectClass; 379 image->matte=MagickTrue; 380 } 381 status=QueryColorCompliance(target,AllCompliance,&image->colormap[j], 382 exception); 383 if (status == MagickFalse) 384 break; 385 } 386 if (j < (ssize_t) image->colors) 387 ThrowReaderException(CorruptImageError,"CorruptImage"); 388 j=0; 389 if (image_info->ping == MagickFalse) 390 { 391 /* 392 Read image pixels. 393 */ 394 for (y=0; y < (ssize_t) image->rows; y++) 395 { 396 p=NextXPMLine(p); 397 if (p == (char *) NULL) 398 break; 399 r=QueueAuthenticPixels(image,0,y,image->columns,1,exception); 400 if (r == (Quantum *) NULL) 401 break; 402 for (x=0; x < (ssize_t) image->columns; x++) 403 { 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); 409 p+=width; 410 r+=GetPixelComponents(image); 411 } 412 if (SyncAuthenticPixels(image,exception) == MagickFalse) 413 break; 414 } 415 if (y < (ssize_t) image->rows) 416 ThrowReaderException(CorruptImageError,"NotEnoughPixelData"); 417 } 418 /* 419 Relinquish resources. 420 */ 421 xpm_colors=DestroySplayTree(xpm_colors); 422 (void) CloseBlob(image); 423 return(GetFirstImageInList(image)); 424} 425 426/* 427%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 428% % 429% % 430% % 431% R e g i s t e r X P M I m a g e % 432% % 433% % 434% % 435%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 436% 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. 443% 444% The format of the RegisterXPMImage method is: 445% 446% size_t RegisterXPMImage(void) 447% 448*/ 449ModuleExport size_t RegisterXPMImage(void) 450{ 451 MagickInfo 452 *entry; 453 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); 478} 479 480/* 481%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 482% % 483% % 484% % 485% U n r e g i s t e r X P M I m a g e % 486% % 487% % 488% % 489%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 490% 491% UnregisterXPMImage() removes format registrations made by the 492% XPM module from the list of supported formats. 493% 494% The format of the UnregisterXPMImage method is: 495% 496% UnregisterXPMImage(void) 497% 498*/ 499ModuleExport void UnregisterXPMImage(void) 500{ 501 (void) UnregisterMagickInfo("PICON"); 502 (void) UnregisterMagickInfo("PM"); 503 (void) UnregisterMagickInfo("XPM"); 504} 505 506/* 507%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 508% % 509% % 510% % 511% W r i t e P I C O N I m a g e % 512% % 513% % 514% % 515%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 516% 517% WritePICONImage() writes an image to a file in the Personal Icon format. 518% 519% The format of the WritePICONImage method is: 520% 521% MagickBooleanType WritePICONImage(const ImageInfo *image_info, 522% Image *image) 523% 524% A description of each parameter follows. 525% 526% o image_info: the image info. 527% 528% o image: The image. 529% 530*/ 531static MagickBooleanType WritePICONImage(const ImageInfo *image_info, 532 Image *image) 533{ 534#define ColormapExtent 155 535#define GraymapExtent 95 536#define PiconGeometry "48x48>" 537 538 static unsigned char 539 Colormap[]= 540 { 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, 554 }, 555 Graymap[]= 556 { 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, 565 }; 566 567#define MaxCixels 92 568 569 static const char 570 Cixel[MaxCixels+1] = " .XoO+@#$%&*=-;:>,<1234567890qwertyuipasdfghjk" 571 "lzxcvbnmMNBVCZASDFGHJKLPIUYTREWQ!~^/()_`'][{}|"; 572 573 char 574 buffer[MaxTextExtent], 575 basename[MaxTextExtent], 576 name[MaxTextExtent], 577 symbol[MaxTextExtent]; 578 579 ExceptionInfo 580 *exception; 581 582 Image 583 *affinity_image, 584 *picon; 585 586 ImageInfo 587 *blob_info; 588 589 MagickBooleanType 590 status, 591 transparent; 592 593 PixelInfo 594 pixel; 595 596 QuantizeInfo 597 *quantize_info; 598 599 RectangleInfo 600 geometry; 601 602 register const Quantum 603 *p; 604 605 register ssize_t 606 i, 607 x; 608 609 register Quantum 610 *q; 611 612 size_t 613 characters_per_pixel, 614 colors; 615 616 ssize_t 617 j, 618 k, 619 y; 620 621 /* 622 Open output image file. 623 */ 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) 632 return(status); 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, 639 &image->exception); 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, 645 &image->exception); 646 else 647 affinity_image=BlobToImage(blob_info,Colormap,ColormapExtent, 648 &image->exception); 649 (void) RelinquishUniqueFileResource(blob_info->filename); 650 blob_info=DestroyImageInfo(blob_info); 651 if ((picon == (Image *) NULL) || (affinity_image == (Image *) NULL)) 652 return(MagickFalse); 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) 660 { 661 (void) CompressImageColormap(picon); 662 if (picon->matte != MagickFalse) 663 transparent=MagickTrue; 664 } 665 else 666 { 667 /* 668 Convert DirectClass to PseudoClass picon. 669 */ 670 if (picon->matte != MagickFalse) 671 { 672 /* 673 Map all the transparent pixels. 674 */ 675 for (y=0; y < (ssize_t) picon->rows; y++) 676 { 677 q=GetAuthenticPixels(picon,0,y,picon->columns,1,exception); 678 if (q == (const Quantum *) NULL) 679 break; 680 for (x=0; x < (ssize_t) picon->columns; x++) 681 { 682 if (GetPixelAlpha(image,q) == (Quantum) TransparentAlpha) 683 transparent=MagickTrue; 684 else 685 SetPixelAlpha(picon,OpaqueAlpha,q); 686 q+=GetPixelComponents(picon); 687 } 688 if (SyncAuthenticPixels(picon,exception) == MagickFalse) 689 break; 690 } 691 } 692 (void) SetImageType(picon,PaletteType); 693 } 694 colors=picon->colors; 695 if (transparent != MagickFalse) 696 { 697 colors++; 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++) 703 { 704 q=GetAuthenticPixels(picon,0,y,picon->columns,1,exception); 705 if (q == (const Quantum *) NULL) 706 break; 707 for (x=0; x < (ssize_t) picon->columns; x++) 708 { 709 if (GetPixelAlpha(image,q) == (Quantum) TransparentAlpha) 710 SetPixelIndex(picon,picon->colors,q); 711 q+=GetPixelComponents(picon); 712 } 713 if (SyncAuthenticPixels(picon,exception) == MagickFalse) 714 break; 715 } 716 } 717 /* 718 Compute the character per pixel. 719 */ 720 characters_per_pixel=1; 721 for (k=MaxCixels; (ssize_t) colors > k; k*=MaxCixels) 722 characters_per_pixel++; 723 /* 724 XPM header. 725 */ 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++) 738 { 739 /* 740 Define XPM color. 741 */ 742 SetPixelInfoPacket(image,picon->colormap+i,&pixel); 743 pixel.colorspace=RGBColorspace; 744 pixel.depth=8; 745 pixel.alpha=(MagickRealType) OpaqueAlpha; 746 (void) QueryMagickColorname(image,&pixel,XPMCompliance,name, 747 &image->exception); 748 if (transparent != MagickFalse) 749 { 750 if (i == (ssize_t) (colors-1)) 751 (void) CopyMagickString(name,"grey75",MaxTextExtent); 752 } 753 /* 754 Write XPM color. 755 */ 756 k=i % MaxCixels; 757 symbol[0]=Cixel[k]; 758 for (j=1; j < (ssize_t) characters_per_pixel; j++) 759 { 760 k=((i-k)/MaxCixels) % MaxCixels; 761 symbol[j]=Cixel[k]; 762 } 763 symbol[j]='\0'; 764 (void) FormatLocaleString(buffer,MaxTextExtent,"\"%s c %s\",\n", 765 symbol,name); 766 (void) WriteBlobString(image,buffer); 767 } 768 /* 769 Define XPM pixels. 770 */ 771 (void) WriteBlobString(image,"/* pixels */\n"); 772 for (y=0; y < (ssize_t) picon->rows; y++) 773 { 774 p=GetVirtualPixels(picon,0,y,picon->columns,1,&picon->exception); 775 if (p == (const Quantum *) NULL) 776 break; 777 (void) WriteBlobString(image,"\""); 778 for (x=0; x < (ssize_t) picon->columns; x++) 779 { 780 k=((ssize_t) GetPixelIndex(picon,p) % MaxCixels); 781 symbol[0]=Cixel[k]; 782 for (j=1; j < (ssize_t) characters_per_pixel; j++) 783 { 784 k=(((int) GetPixelIndex(picon,p)-k)/MaxCixels) % MaxCixels; 785 symbol[j]=Cixel[k]; 786 } 787 symbol[j]='\0'; 788 (void) CopyMagickString(buffer,symbol,MaxTextExtent); 789 (void) WriteBlobString(image,buffer); 790 p+=GetPixelComponents(image); 791 } 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, 796 picon->rows); 797 if (status == MagickFalse) 798 break; 799 } 800 picon=DestroyImage(picon); 801 (void) WriteBlobString(image,"};\n"); 802 (void) CloseBlob(image); 803 return(MagickTrue); 804} 805 806/* 807%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 808% % 809% % 810% % 811% W r i t e X P M I m a g e % 812% % 813% % 814% % 815%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 816% 817% WriteXPMImage() writes an image to a file in the X pixmap format. 818% 819% The format of the WriteXPMImage method is: 820% 821% MagickBooleanType WriteXPMImage(const ImageInfo *image_info,Image *image) 822% 823% A description of each parameter follows. 824% 825% o image_info: the image info. 826% 827% o image: The image. 828% 829*/ 830static MagickBooleanType WriteXPMImage(const ImageInfo *image_info,Image *image) 831{ 832#define MaxCixels 92 833 834 static const char 835 Cixel[MaxCixels+1] = " .XoO+@#$%&*=-;:>,<1234567890qwertyuipasdfghjk" 836 "lzxcvbnmMNBVCZASDFGHJKLPIUYTREWQ!~^/()_`'][{}|"; 837 838 char 839 buffer[MaxTextExtent], 840 basename[MaxTextExtent], 841 name[MaxTextExtent], 842 symbol[MaxTextExtent]; 843 844 MagickBooleanType 845 status; 846 847 PixelInfo 848 pixel; 849 850 register const Quantum 851 *p; 852 853 register ssize_t 854 i, 855 x; 856 857 size_t 858 characters_per_pixel; 859 860 ssize_t 861 j, 862 k, 863 opacity, 864 y; 865 866 /* 867 Open output image file. 868 */ 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) 877 return(status); 878 if (IsRGBColorspace(image->colorspace) == MagickFalse) 879 (void) TransformImageColorspace(image,RGBColorspace); 880 opacity=(-1); 881 if (image->matte == MagickFalse) 882 { 883 if ((image->storage_class == DirectClass) || (image->colors > 256)) 884 (void) SetImageType(image,PaletteType); 885 } 886 else 887 { 888 MagickRealType 889 alpha, 890 beta; 891 892 /* 893 Identify transparent colormap index. 894 */ 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) 899 { 900 if (opacity < 0) 901 { 902 opacity=i; 903 continue; 904 } 905 alpha=(MagickRealType) TransparentAlpha-(MagickRealType) 906 image->colormap[i].alpha; 907 beta=(MagickRealType) TransparentAlpha-(MagickRealType) 908 image->colormap[opacity].alpha; 909 if (alpha < beta) 910 opacity=i; 911 } 912 if (opacity == -1) 913 { 914 (void) SetImageType(image,PaletteBilevelMatteType); 915 for (i=0; i < (ssize_t) image->colors; i++) 916 if (image->colormap[i].alpha != OpaqueAlpha) 917 { 918 if (opacity < 0) 919 { 920 opacity=i; 921 continue; 922 } 923 alpha=(Quantum) TransparentAlpha-(MagickRealType) 924 image->colormap[i].alpha; 925 beta=(Quantum) TransparentAlpha-(MagickRealType) 926 image->colormap[opacity].alpha; 927 if (alpha < beta) 928 opacity=i; 929 } 930 } 931 if (opacity >= 0) 932 { 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; 936 } 937 } 938 /* 939 Compute the character per pixel. 940 */ 941 characters_per_pixel=1; 942 for (k=MaxCixels; (ssize_t) image->colors > k; k*=MaxCixels) 943 characters_per_pixel++; 944 /* 945 XPM header. 946 */ 947 (void) WriteBlobString(image,"/* XPM */\n"); 948 GetPathComponent(image->filename,BasePath,basename); 949 if (isalnum((int) ((unsigned char) *basename)) == 0) 950 { 951 (void) FormatLocaleString(buffer,MaxTextExtent,"xpm_%s",basename); 952 (void) CopyMagickString(basename,buffer,MaxTextExtent); 953 } 954 if (isalpha((int) ((unsigned char) basename[0])) == 0) 955 basename[0]='_'; 956 for (i=1; basename[i] != '\0'; i++) 957 if (isalnum((int) ((unsigned char) basename[i])) == 0) 958 basename[i]='_'; 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++) 969 { 970 /* 971 Define XPM color. 972 */ 973 SetPixelInfoPacket(image,image->colormap+i,&pixel); 974 pixel.colorspace=RGBColorspace; 975 pixel.depth=8; 976 pixel.alpha=(MagickRealType) OpaqueAlpha; 977 (void) QueryMagickColorname(image,&pixel,XPMCompliance,name, 978 &image->exception); 979 if (i == opacity) 980 (void) CopyMagickString(name,"None",MaxTextExtent); 981 /* 982 Write XPM color. 983 */ 984 k=i % MaxCixels; 985 symbol[0]=Cixel[k]; 986 for (j=1; j < (ssize_t) characters_per_pixel; j++) 987 { 988 k=((i-k)/MaxCixels) % MaxCixels; 989 symbol[j]=Cixel[k]; 990 } 991 symbol[j]='\0'; 992 (void) FormatLocaleString(buffer,MaxTextExtent,"\"%s c %s\",\n",symbol, 993 name); 994 (void) WriteBlobString(image,buffer); 995 } 996 /* 997 Define XPM pixels. 998 */ 999 (void) WriteBlobString(image,"/* pixels */\n"); 1000 for (y=0; y < (ssize_t) image->rows; y++) 1001 { 1002 p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception); 1003 if (p == (const Quantum *) NULL) 1004 break; 1005 (void) WriteBlobString(image,"\""); 1006 for (x=0; x < (ssize_t) image->columns; x++) 1007 { 1008 k=((ssize_t) GetPixelIndex(image,p) % MaxCixels); 1009 symbol[0]=Cixel[k]; 1010 for (j=1; j < (ssize_t) characters_per_pixel; j++) 1011 { 1012 k=(((int) GetPixelIndex(image,p)-k)/MaxCixels) % MaxCixels; 1013 symbol[j]=Cixel[k]; 1014 } 1015 symbol[j]='\0'; 1016 (void) CopyMagickString(buffer,symbol,MaxTextExtent); 1017 (void) WriteBlobString(image,buffer); 1018 p+=GetPixelComponents(image); 1019 } 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) 1024 { 1025 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y, 1026 image->rows); 1027 if (status == MagickFalse) 1028 break; 1029 } 1030 } 1031 (void) WriteBlobString(image,"};\n"); 1032 (void) CloseBlob(image); 1033 return(MagickTrue); 1034} 1035