xpm.c revision a19f1d70e9a9f88279c4ecafe6dfafc1f9a09599
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 (IssRGBCompatibleColorspace(image->colorspace) == MagickFalse) 635 (void) TransformImageColorspace(image,sRGBColorspace,exception); 636 SetGeometry(image,&geometry); 637 (void) ParseMetaGeometry(PiconGeometry,&geometry.x,&geometry.y, 638 &geometry.width,&geometry.height); 639 picon=ResizeImage(image,geometry.width,geometry.height,TriangleFilter, 640 exception); 641 blob_info=CloneImageInfo(image_info); 642 (void) AcquireUniqueFilename(blob_info->filename); 643 if ((image_info->type != TrueColorType) && 644 (IsImageGray(image,exception) != MagickFalse)) 645 affinity_image=BlobToImage(blob_info,Graymap,GraymapExtent,exception); 646 else 647 affinity_image=BlobToImage(blob_info,Colormap,ColormapExtent,exception); 648 (void) RelinquishUniqueFileResource(blob_info->filename); 649 blob_info=DestroyImageInfo(blob_info); 650 if ((picon == (Image *) NULL) || (affinity_image == (Image *) NULL)) 651 return(MagickFalse); 652 quantize_info=AcquireQuantizeInfo(image_info); 653 status=RemapImage(quantize_info,picon,affinity_image,exception); 654 quantize_info=DestroyQuantizeInfo(quantize_info); 655 affinity_image=DestroyImage(affinity_image); 656 transparent=MagickFalse; 657 if (picon->storage_class == PseudoClass) 658 { 659 (void) CompressImageColormap(picon,exception); 660 if (picon->matte != MagickFalse) 661 transparent=MagickTrue; 662 } 663 else 664 { 665 /* 666 Convert DirectClass to PseudoClass picon. 667 */ 668 if (picon->matte != MagickFalse) 669 { 670 /* 671 Map all the transparent pixels. 672 */ 673 for (y=0; y < (ssize_t) picon->rows; y++) 674 { 675 q=GetAuthenticPixels(picon,0,y,picon->columns,1,exception); 676 if (q == (Quantum *) NULL) 677 break; 678 for (x=0; x < (ssize_t) picon->columns; x++) 679 { 680 if (GetPixelAlpha(image,q) == (Quantum) TransparentAlpha) 681 transparent=MagickTrue; 682 else 683 SetPixelAlpha(picon,OpaqueAlpha,q); 684 q+=GetPixelChannels(picon); 685 } 686 if (SyncAuthenticPixels(picon,exception) == MagickFalse) 687 break; 688 } 689 } 690 (void) SetImageType(picon,PaletteType,exception); 691 } 692 colors=picon->colors; 693 if (transparent != MagickFalse) 694 { 695 colors++; 696 picon->colormap=(PixelInfo *) ResizeQuantumMemory((void **) 697 picon->colormap,(size_t) colors,sizeof(*picon->colormap)); 698 if (picon->colormap == (PixelInfo *) NULL) 699 ThrowWriterException(ResourceLimitError,"MemoryAllocationError"); 700 for (y=0; y < (ssize_t) picon->rows; y++) 701 { 702 q=GetAuthenticPixels(picon,0,y,picon->columns,1,exception); 703 if (q == (Quantum *) NULL) 704 break; 705 for (x=0; x < (ssize_t) picon->columns; x++) 706 { 707 if (GetPixelAlpha(image,q) == (Quantum) TransparentAlpha) 708 SetPixelIndex(picon,picon->colors,q); 709 q+=GetPixelChannels(picon); 710 } 711 if (SyncAuthenticPixels(picon,exception) == MagickFalse) 712 break; 713 } 714 } 715 /* 716 Compute the character per pixel. 717 */ 718 characters_per_pixel=1; 719 for (k=MaxCixels; (ssize_t) colors > k; k*=MaxCixels) 720 characters_per_pixel++; 721 /* 722 XPM header. 723 */ 724 (void) WriteBlobString(image,"/* XPM */\n"); 725 GetPathComponent(picon->filename,BasePath,basename); 726 (void) FormatLocaleString(buffer,MaxTextExtent, 727 "static char *%s[] = {\n",basename); 728 (void) WriteBlobString(image,buffer); 729 (void) WriteBlobString(image,"/* columns rows colors chars-per-pixel */\n"); 730 (void) FormatLocaleString(buffer,MaxTextExtent, 731 "\"%.20g %.20g %.20g %.20g\",\n",(double) picon->columns,(double) 732 picon->rows,(double) colors,(double) characters_per_pixel); 733 (void) WriteBlobString(image,buffer); 734 GetPixelInfo(image,&pixel); 735 for (i=0; i < (ssize_t) colors; i++) 736 { 737 /* 738 Define XPM color. 739 */ 740 pixel=picon->colormap[i]; 741 pixel.colorspace=sRGBColorspace; 742 pixel.depth=8; 743 pixel.alpha=(double) OpaqueAlpha; 744 (void) QueryColorname(image,&pixel,XPMCompliance,name,exception); 745 if (transparent != MagickFalse) 746 { 747 if (i == (ssize_t) (colors-1)) 748 (void) CopyMagickString(name,"grey75",MaxTextExtent); 749 } 750 /* 751 Write XPM color. 752 */ 753 k=i % MaxCixels; 754 symbol[0]=Cixel[k]; 755 for (j=1; j < (ssize_t) characters_per_pixel; j++) 756 { 757 k=((i-k)/MaxCixels) % MaxCixels; 758 symbol[j]=Cixel[k]; 759 } 760 symbol[j]='\0'; 761 (void) FormatLocaleString(buffer,MaxTextExtent,"\"%s c %s\",\n", 762 symbol,name); 763 (void) WriteBlobString(image,buffer); 764 } 765 /* 766 Define XPM pixels. 767 */ 768 (void) WriteBlobString(image,"/* pixels */\n"); 769 for (y=0; y < (ssize_t) picon->rows; y++) 770 { 771 p=GetVirtualPixels(picon,0,y,picon->columns,1,exception); 772 if (p == (const Quantum *) NULL) 773 break; 774 (void) WriteBlobString(image,"\""); 775 for (x=0; x < (ssize_t) picon->columns; x++) 776 { 777 k=((ssize_t) GetPixelIndex(picon,p) % MaxCixels); 778 symbol[0]=Cixel[k]; 779 for (j=1; j < (ssize_t) characters_per_pixel; j++) 780 { 781 k=(((int) GetPixelIndex(picon,p)-k)/MaxCixels) % MaxCixels; 782 symbol[j]=Cixel[k]; 783 } 784 symbol[j]='\0'; 785 (void) CopyMagickString(buffer,symbol,MaxTextExtent); 786 (void) WriteBlobString(image,buffer); 787 p+=GetPixelChannels(image); 788 } 789 (void) FormatLocaleString(buffer,MaxTextExtent,"\"%s\n", 790 y == (ssize_t) (picon->rows-1) ? "" : ","); 791 (void) WriteBlobString(image,buffer); 792 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y, 793 picon->rows); 794 if (status == MagickFalse) 795 break; 796 } 797 picon=DestroyImage(picon); 798 (void) WriteBlobString(image,"};\n"); 799 (void) CloseBlob(image); 800 return(MagickTrue); 801} 802 803/* 804%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 805% % 806% % 807% % 808% W r i t e X P M I m a g e % 809% % 810% % 811% % 812%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 813% 814% WriteXPMImage() writes an image to a file in the X pixmap format. 815% 816% The format of the WriteXPMImage method is: 817% 818% MagickBooleanType WriteXPMImage(const ImageInfo *image_info, 819% Image *image,ExceptionInfo *exception) 820% 821% A description of each parameter follows. 822% 823% o image_info: the image info. 824% 825% o image: The image. 826% 827% o exception: return any errors or warnings in this structure. 828% 829*/ 830static MagickBooleanType WriteXPMImage(const ImageInfo *image_info,Image *image, 831 ExceptionInfo *exception) 832{ 833#define MaxCixels 92 834 835 static const char 836 Cixel[MaxCixels+1] = " .XoO+@#$%&*=-;:>,<1234567890qwertyuipasdfghjk" 837 "lzxcvbnmMNBVCZASDFGHJKLPIUYTREWQ!~^/()_`'][{}|"; 838 839 char 840 buffer[MaxTextExtent], 841 basename[MaxTextExtent], 842 name[MaxTextExtent], 843 symbol[MaxTextExtent]; 844 845 MagickBooleanType 846 status; 847 848 PixelInfo 849 pixel; 850 851 register const Quantum 852 *p; 853 854 register ssize_t 855 i, 856 x; 857 858 size_t 859 characters_per_pixel; 860 861 ssize_t 862 j, 863 k, 864 opacity, 865 y; 866 867 /* 868 Open output image file. 869 */ 870 assert(image_info != (const ImageInfo *) NULL); 871 assert(image_info->signature == MagickSignature); 872 assert(image != (Image *) NULL); 873 assert(image->signature == MagickSignature); 874 if (image->debug != MagickFalse) 875 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); 876 assert(exception != (ExceptionInfo *) NULL); 877 assert(exception->signature == MagickSignature); 878 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception); 879 if (status == MagickFalse) 880 return(status); 881 if (IssRGBCompatibleColorspace(image->colorspace) == MagickFalse) 882 (void) TransformImageColorspace(image,sRGBColorspace,exception); 883 opacity=(-1); 884 if (image->matte == MagickFalse) 885 { 886 if ((image->storage_class == DirectClass) || (image->colors > 256)) 887 (void) SetImageType(image,PaletteType,exception); 888 } 889 else 890 { 891 double 892 alpha, 893 beta; 894 895 /* 896 Identify transparent colormap index. 897 */ 898 if ((image->storage_class == DirectClass) || (image->colors > 256)) 899 (void) SetImageType(image,PaletteBilevelMatteType,exception); 900 for (i=0; i < (ssize_t) image->colors; i++) 901 if (image->colormap[i].alpha != OpaqueAlpha) 902 { 903 if (opacity < 0) 904 { 905 opacity=i; 906 continue; 907 } 908 alpha=(double) TransparentAlpha-(double) 909 image->colormap[i].alpha; 910 beta=(double) TransparentAlpha-(double) 911 image->colormap[opacity].alpha; 912 if (alpha < beta) 913 opacity=i; 914 } 915 if (opacity == -1) 916 { 917 (void) SetImageType(image,PaletteBilevelMatteType,exception); 918 for (i=0; i < (ssize_t) image->colors; i++) 919 if (image->colormap[i].alpha != OpaqueAlpha) 920 { 921 if (opacity < 0) 922 { 923 opacity=i; 924 continue; 925 } 926 alpha=(Quantum) TransparentAlpha-(double) 927 image->colormap[i].alpha; 928 beta=(Quantum) TransparentAlpha-(double) 929 image->colormap[opacity].alpha; 930 if (alpha < beta) 931 opacity=i; 932 } 933 } 934 if (opacity >= 0) 935 { 936 image->colormap[opacity].red=image->transparent_color.red; 937 image->colormap[opacity].green=image->transparent_color.green; 938 image->colormap[opacity].blue=image->transparent_color.blue; 939 } 940 } 941 /* 942 Compute the character per pixel. 943 */ 944 characters_per_pixel=1; 945 for (k=MaxCixels; (ssize_t) image->colors > k; k*=MaxCixels) 946 characters_per_pixel++; 947 /* 948 XPM header. 949 */ 950 (void) WriteBlobString(image,"/* XPM */\n"); 951 GetPathComponent(image->filename,BasePath,basename); 952 if (isalnum((int) ((unsigned char) *basename)) == 0) 953 { 954 (void) FormatLocaleString(buffer,MaxTextExtent,"xpm_%s",basename); 955 (void) CopyMagickString(basename,buffer,MaxTextExtent); 956 } 957 if (isalpha((int) ((unsigned char) basename[0])) == 0) 958 basename[0]='_'; 959 for (i=1; basename[i] != '\0'; i++) 960 if (isalnum((int) ((unsigned char) basename[i])) == 0) 961 basename[i]='_'; 962 (void) FormatLocaleString(buffer,MaxTextExtent, 963 "static char *%s[] = {\n",basename); 964 (void) WriteBlobString(image,buffer); 965 (void) WriteBlobString(image,"/* columns rows colors chars-per-pixel */\n"); 966 (void) FormatLocaleString(buffer,MaxTextExtent, 967 "\"%.20g %.20g %.20g %.20g \",\n",(double) image->columns,(double) 968 image->rows,(double) image->colors,(double) characters_per_pixel); 969 (void) WriteBlobString(image,buffer); 970 GetPixelInfo(image,&pixel); 971 for (i=0; i < (ssize_t) image->colors; i++) 972 { 973 /* 974 Define XPM color. 975 */ 976 pixel=image->colormap[i]; 977 pixel.colorspace=sRGBColorspace; 978 pixel.depth=8; 979 pixel.alpha=(double) OpaqueAlpha; 980 (void) QueryColorname(image,&pixel,XPMCompliance,name,exception); 981 if (i == opacity) 982 (void) CopyMagickString(name,"None",MaxTextExtent); 983 /* 984 Write XPM color. 985 */ 986 k=i % MaxCixels; 987 symbol[0]=Cixel[k]; 988 for (j=1; j < (ssize_t) characters_per_pixel; j++) 989 { 990 k=((i-k)/MaxCixels) % MaxCixels; 991 symbol[j]=Cixel[k]; 992 } 993 symbol[j]='\0'; 994 (void) FormatLocaleString(buffer,MaxTextExtent,"\"%s c %s\",\n",symbol, 995 name); 996 (void) WriteBlobString(image,buffer); 997 } 998 /* 999 Define XPM pixels. 1000 */ 1001 (void) WriteBlobString(image,"/* pixels */\n"); 1002 for (y=0; y < (ssize_t) image->rows; y++) 1003 { 1004 p=GetVirtualPixels(image,0,y,image->columns,1,exception); 1005 if (p == (const Quantum *) NULL) 1006 break; 1007 (void) WriteBlobString(image,"\""); 1008 for (x=0; x < (ssize_t) image->columns; x++) 1009 { 1010 k=((ssize_t) GetPixelIndex(image,p) % MaxCixels); 1011 symbol[0]=Cixel[k]; 1012 for (j=1; j < (ssize_t) characters_per_pixel; j++) 1013 { 1014 k=(((int) GetPixelIndex(image,p)-k)/MaxCixels) % MaxCixels; 1015 symbol[j]=Cixel[k]; 1016 } 1017 symbol[j]='\0'; 1018 (void) CopyMagickString(buffer,symbol,MaxTextExtent); 1019 (void) WriteBlobString(image,buffer); 1020 p+=GetPixelChannels(image); 1021 } 1022 (void) FormatLocaleString(buffer,MaxTextExtent,"\"%s\n", 1023 (y == (ssize_t) (image->rows-1) ? "" : ",")); 1024 (void) WriteBlobString(image,buffer); 1025 if (image->previous == (Image *) NULL) 1026 { 1027 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y, 1028 image->rows); 1029 if (status == MagickFalse) 1030 break; 1031 } 1032 } 1033 (void) WriteBlobString(image,"};\n"); 1034 (void) CloseBlob(image); 1035 return(MagickTrue); 1036} 1037