xpm.c revision ab37187df1c707c6eb99e573a9448ce0b164956d
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-2012 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 *,ExceptionInfo *), 79 WriteXPMImage(const ImageInfo *,Image *,ExceptionInfo *); 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,exception); 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,exception) == 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 SetPixelInfoPixel(image,image->colormap+j,r); 409 p+=width; 410 r+=GetPixelChannels(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,ExceptionInfo *exception) 523% 524% A description of each parameter follows. 525% 526% o image_info: the image info. 527% 528% o image: The image. 529% 530% o exception: return any errors or warnings in this structure. 531% 532*/ 533static MagickBooleanType WritePICONImage(const ImageInfo *image_info, 534 Image *image,ExceptionInfo *exception) 535{ 536#define ColormapExtent 155 537#define GraymapExtent 95 538#define PiconGeometry "48x48>" 539 540 static unsigned char 541 Colormap[]= 542 { 543 0x47, 0x49, 0x46, 0x38, 0x37, 0x61, 0x06, 0x00, 0x05, 0x00, 0xf4, 0x05, 544 0x00, 0x00, 0x00, 0x00, 0x2f, 0x4f, 0x4f, 0x70, 0x80, 0x90, 0x7e, 0x7e, 545 0x7e, 0xdc, 0xdc, 0xdc, 0xff, 0xff, 0xff, 0x00, 0x00, 0x80, 0x00, 0x00, 546 0xff, 0x1e, 0x90, 0xff, 0x87, 0xce, 0xeb, 0xe6, 0xe6, 0xfa, 0x00, 0xff, 547 0xff, 0x80, 0x00, 0x80, 0xb2, 0x22, 0x22, 0x2e, 0x8b, 0x57, 0x32, 0xcd, 548 0x32, 0x00, 0xff, 0x00, 0x98, 0xfb, 0x98, 0xff, 0x00, 0xff, 0xff, 0x00, 549 0x00, 0xff, 0x63, 0x47, 0xff, 0xa5, 0x00, 0xff, 0xd7, 0x00, 0xff, 0xff, 550 0x00, 0xee, 0x82, 0xee, 0xa0, 0x52, 0x2d, 0xcd, 0x85, 0x3f, 0xd2, 0xb4, 551 0x8c, 0xf5, 0xde, 0xb3, 0xff, 0xfa, 0xcd, 0x00, 0x00, 0x00, 0x00, 0x00, 552 0x00, 0x21, 0xf9, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 553 0x00, 0x00, 0x06, 0x00, 0x05, 0x00, 0x00, 0x05, 0x18, 0x20, 0x10, 0x08, 554 0x03, 0x51, 0x18, 0x07, 0x92, 0x28, 0x0b, 0xd3, 0x38, 0x0f, 0x14, 0x49, 555 0x13, 0x55, 0x59, 0x17, 0x96, 0x69, 0x1b, 0xd7, 0x85, 0x00, 0x3b, 556 }, 557 Graymap[]= 558 { 559 0x47, 0x49, 0x46, 0x38, 0x37, 0x61, 0x04, 0x00, 0x04, 0x00, 0xf3, 0x0f, 560 0x00, 0x00, 0x00, 0x00, 0x12, 0x12, 0x12, 0x21, 0x21, 0x21, 0x33, 0x33, 561 0x33, 0x45, 0x45, 0x45, 0x54, 0x54, 0x54, 0x66, 0x66, 0x66, 0x78, 0x78, 562 0x78, 0x87, 0x87, 0x87, 0x99, 0x99, 0x99, 0xab, 0xab, 0xab, 0xba, 0xba, 563 0xba, 0xcc, 0xcc, 0xcc, 0xde, 0xde, 0xde, 0xed, 0xed, 0xed, 0xff, 0xff, 564 0xff, 0x21, 0xf9, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 565 0x00, 0x00, 0x04, 0x00, 0x04, 0x00, 0x00, 0x04, 0x0c, 0x10, 0x04, 0x31, 566 0x48, 0x31, 0x07, 0x25, 0xb5, 0x58, 0x73, 0x4f, 0x04, 0x00, 0x3b, 567 }; 568 569#define MaxCixels 92 570 571 static const char 572 Cixel[MaxCixels+1] = " .XoO+@#$%&*=-;:>,<1234567890qwertyuipasdfghjk" 573 "lzxcvbnmMNBVCZASDFGHJKLPIUYTREWQ!~^/()_`'][{}|"; 574 575 char 576 buffer[MaxTextExtent], 577 basename[MaxTextExtent], 578 name[MaxTextExtent], 579 symbol[MaxTextExtent]; 580 581 Image 582 *affinity_image, 583 *picon; 584 585 ImageInfo 586 *blob_info; 587 588 MagickBooleanType 589 status, 590 transparent; 591 592 PixelInfo 593 pixel; 594 595 QuantizeInfo 596 *quantize_info; 597 598 RectangleInfo 599 geometry; 600 601 register const Quantum 602 *p; 603 604 register ssize_t 605 i, 606 x; 607 608 register Quantum 609 *q; 610 611 size_t 612 characters_per_pixel, 613 colors; 614 615 ssize_t 616 j, 617 k, 618 y; 619 620 /* 621 Open output image file. 622 */ 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 assert(exception != (ExceptionInfo *) NULL); 630 assert(exception->signature == MagickSignature); 631 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception); 632 if (status == MagickFalse) 633 return(status); 634 if ((IssRGBColorspace(image->colorspace) == MagickFalse) && 635 (IsRGBColorspace(image->colorspace) == MagickFalse)) 636 (void) TransformImageColorspace(image,sRGBColorspace,exception); 637 SetGeometry(image,&geometry); 638 (void) ParseMetaGeometry(PiconGeometry,&geometry.x,&geometry.y, 639 &geometry.width,&geometry.height); 640 picon=ResizeImage(image,geometry.width,geometry.height,TriangleFilter, 641 exception); 642 blob_info=CloneImageInfo(image_info); 643 (void) AcquireUniqueFilename(blob_info->filename); 644 if ((image_info->type != TrueColorType) && 645 (IsImageGray(image,exception) != MagickFalse)) 646 affinity_image=BlobToImage(blob_info,Graymap,GraymapExtent,exception); 647 else 648 affinity_image=BlobToImage(blob_info,Colormap,ColormapExtent,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,exception); 655 quantize_info=DestroyQuantizeInfo(quantize_info); 656 affinity_image=DestroyImage(affinity_image); 657 transparent=MagickFalse; 658 if (picon->storage_class == PseudoClass) 659 { 660 (void) CompressImageColormap(picon,exception); 661 if (picon->matte != MagickFalse) 662 transparent=MagickTrue; 663 } 664 else 665 { 666 /* 667 Convert DirectClass to PseudoClass picon. 668 */ 669 if (picon->matte != MagickFalse) 670 { 671 /* 672 Map all the transparent pixels. 673 */ 674 for (y=0; y < (ssize_t) picon->rows; y++) 675 { 676 q=GetAuthenticPixels(picon,0,y,picon->columns,1,exception); 677 if (q == (Quantum *) NULL) 678 break; 679 for (x=0; x < (ssize_t) picon->columns; x++) 680 { 681 if (GetPixelAlpha(image,q) == (Quantum) TransparentAlpha) 682 transparent=MagickTrue; 683 else 684 SetPixelAlpha(picon,OpaqueAlpha,q); 685 q+=GetPixelChannels(picon); 686 } 687 if (SyncAuthenticPixels(picon,exception) == MagickFalse) 688 break; 689 } 690 } 691 (void) SetImageType(picon,PaletteType,exception); 692 } 693 colors=picon->colors; 694 if (transparent != MagickFalse) 695 { 696 colors++; 697 picon->colormap=(PixelInfo *) ResizeQuantumMemory((void **) 698 picon->colormap,(size_t) colors,sizeof(*picon->colormap)); 699 if (picon->colormap == (PixelInfo *) NULL) 700 ThrowWriterException(ResourceLimitError,"MemoryAllocationError"); 701 for (y=0; y < (ssize_t) picon->rows; y++) 702 { 703 q=GetAuthenticPixels(picon,0,y,picon->columns,1,exception); 704 if (q == (Quantum *) NULL) 705 break; 706 for (x=0; x < (ssize_t) picon->columns; x++) 707 { 708 if (GetPixelAlpha(image,q) == (Quantum) TransparentAlpha) 709 SetPixelIndex(picon,picon->colors,q); 710 q+=GetPixelChannels(picon); 711 } 712 if (SyncAuthenticPixels(picon,exception) == MagickFalse) 713 break; 714 } 715 } 716 /* 717 Compute the character per pixel. 718 */ 719 characters_per_pixel=1; 720 for (k=MaxCixels; (ssize_t) colors > k; k*=MaxCixels) 721 characters_per_pixel++; 722 /* 723 XPM header. 724 */ 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++) 737 { 738 /* 739 Define XPM color. 740 */ 741 pixel=picon->colormap[i]; 742 pixel.colorspace=sRGBColorspace; 743 pixel.depth=8; 744 pixel.alpha=(MagickRealType) OpaqueAlpha; 745 (void) QueryColorname(image,&pixel,XPMCompliance,name,exception); 746 if (transparent != MagickFalse) 747 { 748 if (i == (ssize_t) (colors-1)) 749 (void) CopyMagickString(name,"grey75",MaxTextExtent); 750 } 751 /* 752 Write XPM color. 753 */ 754 k=i % MaxCixels; 755 symbol[0]=Cixel[k]; 756 for (j=1; j < (ssize_t) characters_per_pixel; j++) 757 { 758 k=((i-k)/MaxCixels) % MaxCixels; 759 symbol[j]=Cixel[k]; 760 } 761 symbol[j]='\0'; 762 (void) FormatLocaleString(buffer,MaxTextExtent,"\"%s c %s\",\n", 763 symbol,name); 764 (void) WriteBlobString(image,buffer); 765 } 766 /* 767 Define XPM pixels. 768 */ 769 (void) WriteBlobString(image,"/* pixels */\n"); 770 for (y=0; y < (ssize_t) picon->rows; y++) 771 { 772 p=GetVirtualPixels(picon,0,y,picon->columns,1,exception); 773 if (p == (const Quantum *) NULL) 774 break; 775 (void) WriteBlobString(image,"\""); 776 for (x=0; x < (ssize_t) picon->columns; x++) 777 { 778 k=((ssize_t) GetPixelIndex(picon,p) % MaxCixels); 779 symbol[0]=Cixel[k]; 780 for (j=1; j < (ssize_t) characters_per_pixel; j++) 781 { 782 k=(((int) GetPixelIndex(picon,p)-k)/MaxCixels) % MaxCixels; 783 symbol[j]=Cixel[k]; 784 } 785 symbol[j]='\0'; 786 (void) CopyMagickString(buffer,symbol,MaxTextExtent); 787 (void) WriteBlobString(image,buffer); 788 p+=GetPixelChannels(image); 789 } 790 (void) FormatLocaleString(buffer,MaxTextExtent,"\"%s\n", 791 y == (ssize_t) (picon->rows-1) ? "" : ","); 792 (void) WriteBlobString(image,buffer); 793 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y, 794 picon->rows); 795 if (status == MagickFalse) 796 break; 797 } 798 picon=DestroyImage(picon); 799 (void) WriteBlobString(image,"};\n"); 800 (void) CloseBlob(image); 801 return(MagickTrue); 802} 803 804/* 805%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 806% % 807% % 808% % 809% W r i t e X P M I m a g e % 810% % 811% % 812% % 813%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 814% 815% WriteXPMImage() writes an image to a file in the X pixmap format. 816% 817% The format of the WriteXPMImage method is: 818% 819% MagickBooleanType WriteXPMImage(const ImageInfo *image_info, 820% Image *image,ExceptionInfo *exception) 821% 822% A description of each parameter follows. 823% 824% o image_info: the image info. 825% 826% o image: The image. 827% 828% o exception: return any errors or warnings in this structure. 829% 830*/ 831static MagickBooleanType WriteXPMImage(const ImageInfo *image_info,Image *image, 832 ExceptionInfo *exception) 833{ 834#define MaxCixels 92 835 836 static const char 837 Cixel[MaxCixels+1] = " .XoO+@#$%&*=-;:>,<1234567890qwertyuipasdfghjk" 838 "lzxcvbnmMNBVCZASDFGHJKLPIUYTREWQ!~^/()_`'][{}|"; 839 840 char 841 buffer[MaxTextExtent], 842 basename[MaxTextExtent], 843 name[MaxTextExtent], 844 symbol[MaxTextExtent]; 845 846 MagickBooleanType 847 status; 848 849 PixelInfo 850 pixel; 851 852 register const Quantum 853 *p; 854 855 register ssize_t 856 i, 857 x; 858 859 size_t 860 characters_per_pixel; 861 862 ssize_t 863 j, 864 k, 865 opacity, 866 y; 867 868 /* 869 Open output image file. 870 */ 871 assert(image_info != (const ImageInfo *) NULL); 872 assert(image_info->signature == MagickSignature); 873 assert(image != (Image *) NULL); 874 assert(image->signature == MagickSignature); 875 if (image->debug != MagickFalse) 876 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); 877 assert(exception != (ExceptionInfo *) NULL); 878 assert(exception->signature == MagickSignature); 879 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception); 880 if (status == MagickFalse) 881 return(status); 882 if (IssRGBColorspace(image->colorspace) == MagickFalse) 883 (void) TransformImageColorspace(image,sRGBColorspace,exception); 884 opacity=(-1); 885 if (image->matte == MagickFalse) 886 { 887 if ((image->storage_class == DirectClass) || (image->colors > 256)) 888 (void) SetImageType(image,PaletteType,exception); 889 } 890 else 891 { 892 MagickRealType 893 alpha, 894 beta; 895 896 /* 897 Identify transparent colormap index. 898 */ 899 if ((image->storage_class == DirectClass) || (image->colors > 256)) 900 (void) SetImageType(image,PaletteBilevelMatteType,exception); 901 for (i=0; i < (ssize_t) image->colors; i++) 902 if (image->colormap[i].alpha != OpaqueAlpha) 903 { 904 if (opacity < 0) 905 { 906 opacity=i; 907 continue; 908 } 909 alpha=(MagickRealType) TransparentAlpha-(MagickRealType) 910 image->colormap[i].alpha; 911 beta=(MagickRealType) TransparentAlpha-(MagickRealType) 912 image->colormap[opacity].alpha; 913 if (alpha < beta) 914 opacity=i; 915 } 916 if (opacity == -1) 917 { 918 (void) SetImageType(image,PaletteBilevelMatteType,exception); 919 for (i=0; i < (ssize_t) image->colors; i++) 920 if (image->colormap[i].alpha != OpaqueAlpha) 921 { 922 if (opacity < 0) 923 { 924 opacity=i; 925 continue; 926 } 927 alpha=(Quantum) TransparentAlpha-(MagickRealType) 928 image->colormap[i].alpha; 929 beta=(Quantum) TransparentAlpha-(MagickRealType) 930 image->colormap[opacity].alpha; 931 if (alpha < beta) 932 opacity=i; 933 } 934 } 935 if (opacity >= 0) 936 { 937 image->colormap[opacity].red=image->transparent_color.red; 938 image->colormap[opacity].green=image->transparent_color.green; 939 image->colormap[opacity].blue=image->transparent_color.blue; 940 } 941 } 942 /* 943 Compute the character per pixel. 944 */ 945 characters_per_pixel=1; 946 for (k=MaxCixels; (ssize_t) image->colors > k; k*=MaxCixels) 947 characters_per_pixel++; 948 /* 949 XPM header. 950 */ 951 (void) WriteBlobString(image,"/* XPM */\n"); 952 GetPathComponent(image->filename,BasePath,basename); 953 if (isalnum((int) ((unsigned char) *basename)) == 0) 954 { 955 (void) FormatLocaleString(buffer,MaxTextExtent,"xpm_%s",basename); 956 (void) CopyMagickString(basename,buffer,MaxTextExtent); 957 } 958 if (isalpha((int) ((unsigned char) basename[0])) == 0) 959 basename[0]='_'; 960 for (i=1; basename[i] != '\0'; i++) 961 if (isalnum((int) ((unsigned char) basename[i])) == 0) 962 basename[i]='_'; 963 (void) FormatLocaleString(buffer,MaxTextExtent, 964 "static char *%s[] = {\n",basename); 965 (void) WriteBlobString(image,buffer); 966 (void) WriteBlobString(image,"/* columns rows colors chars-per-pixel */\n"); 967 (void) FormatLocaleString(buffer,MaxTextExtent, 968 "\"%.20g %.20g %.20g %.20g \",\n",(double) image->columns,(double) 969 image->rows,(double) image->colors,(double) characters_per_pixel); 970 (void) WriteBlobString(image,buffer); 971 GetPixelInfo(image,&pixel); 972 for (i=0; i < (ssize_t) image->colors; i++) 973 { 974 /* 975 Define XPM color. 976 */ 977 pixel=image->colormap[i]; 978 pixel.colorspace=sRGBColorspace; 979 pixel.depth=8; 980 pixel.alpha=(MagickRealType) OpaqueAlpha; 981 (void) QueryColorname(image,&pixel,XPMCompliance,name,exception); 982 if (i == opacity) 983 (void) CopyMagickString(name,"None",MaxTextExtent); 984 /* 985 Write XPM color. 986 */ 987 k=i % MaxCixels; 988 symbol[0]=Cixel[k]; 989 for (j=1; j < (ssize_t) characters_per_pixel; j++) 990 { 991 k=((i-k)/MaxCixels) % MaxCixels; 992 symbol[j]=Cixel[k]; 993 } 994 symbol[j]='\0'; 995 (void) FormatLocaleString(buffer,MaxTextExtent,"\"%s c %s\",\n",symbol, 996 name); 997 (void) WriteBlobString(image,buffer); 998 } 999 /* 1000 Define XPM pixels. 1001 */ 1002 (void) WriteBlobString(image,"/* pixels */\n"); 1003 for (y=0; y < (ssize_t) image->rows; y++) 1004 { 1005 p=GetVirtualPixels(image,0,y,image->columns,1,exception); 1006 if (p == (const Quantum *) NULL) 1007 break; 1008 (void) WriteBlobString(image,"\""); 1009 for (x=0; x < (ssize_t) image->columns; x++) 1010 { 1011 k=((ssize_t) GetPixelIndex(image,p) % MaxCixels); 1012 symbol[0]=Cixel[k]; 1013 for (j=1; j < (ssize_t) characters_per_pixel; j++) 1014 { 1015 k=(((int) GetPixelIndex(image,p)-k)/MaxCixels) % MaxCixels; 1016 symbol[j]=Cixel[k]; 1017 } 1018 symbol[j]='\0'; 1019 (void) CopyMagickString(buffer,symbol,MaxTextExtent); 1020 (void) WriteBlobString(image,buffer); 1021 p+=GetPixelChannels(image); 1022 } 1023 (void) FormatLocaleString(buffer,MaxTextExtent,"\"%s\n", 1024 (y == (ssize_t) (image->rows-1) ? "" : ",")); 1025 (void) WriteBlobString(image,buffer); 1026 if (image->previous == (Image *) NULL) 1027 { 1028 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y, 1029 image->rows); 1030 if (status == MagickFalse) 1031 break; 1032 } 1033 } 1034 (void) WriteBlobString(image,"};\n"); 1035 (void) CloseBlob(image); 1036 return(MagickTrue); 1037} 1038