icon.c revision acd2ed254c18c254a0ab5aafa06d1645e5d079d8
1/* 2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 3% % 4% % 5% % 6% IIIII CCCC OOO N N % 7% I C O O NN N % 8% I C O O N N N % 9% I C O O N NN % 10% IIIII CCCC OOO N N % 11% % 12% % 13% Read Microsoft Windows Icon 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/blob.h" 44#include "MagickCore/blob-private.h" 45#include "MagickCore/cache.h" 46#include "MagickCore/colormap.h" 47#include "MagickCore/colorspace.h" 48#include "MagickCore/exception.h" 49#include "MagickCore/exception-private.h" 50#include "MagickCore/image.h" 51#include "MagickCore/image-private.h" 52#include "MagickCore/list.h" 53#include "MagickCore/log.h" 54#include "MagickCore/magick.h" 55#include "MagickCore/memory_.h" 56#include "MagickCore/monitor.h" 57#include "MagickCore/monitor-private.h" 58#include "MagickCore/nt-feature.h" 59#include "MagickCore/pixel-accessor.h" 60#include "MagickCore/quantize.h" 61#include "MagickCore/quantum-private.h" 62#include "MagickCore/static.h" 63#include "MagickCore/string_.h" 64#include "MagickCore/module.h" 65 66/* 67 Define declarations. 68*/ 69#if !defined(MAGICKCORE_WINDOWS_SUPPORT) || defined(__MINGW32__) 70#define BI_RGB 0 71#define BI_RLE8 1 72#define BI_BITFIELDS 3 73#endif 74#define MaxIcons 1024 75 76/* 77 Typedef declarations. 78*/ 79typedef struct _IconEntry 80{ 81 unsigned char 82 width, 83 height, 84 colors, 85 reserved; 86 87 unsigned short int 88 planes, 89 bits_per_pixel; 90 91 size_t 92 size, 93 offset; 94} IconEntry; 95 96typedef struct _IconFile 97{ 98 short 99 reserved, 100 resource_type, 101 count; 102 103 IconEntry 104 directory[MaxIcons]; 105} IconFile; 106 107typedef struct _IconInfo 108{ 109 size_t 110 file_size, 111 ba_offset, 112 offset_bits, 113 size; 114 115 ssize_t 116 width, 117 height; 118 119 unsigned short 120 planes, 121 bits_per_pixel; 122 123 size_t 124 compression, 125 image_size, 126 x_pixels, 127 y_pixels, 128 number_colors, 129 red_mask, 130 green_mask, 131 blue_mask, 132 alpha_mask, 133 colors_important; 134 135 ssize_t 136 colorspace; 137} IconInfo; 138 139/* 140 Forward declaractions. 141*/ 142static MagickBooleanType 143 WriteICONImage(const ImageInfo *,Image *,ExceptionInfo *); 144 145/* 146%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 147% % 148% % 149% % 150% R e a d I C O N I m a g e % 151% % 152% % 153% % 154%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 155% 156% ReadICONImage() reads a Microsoft icon image file and returns it. It 157% allocates the memory necessary for the new Image structure and returns a 158% pointer to the new image. 159% 160% The format of the ReadICONImage method is: 161% 162% Image *ReadICONImage(const ImageInfo *image_info, 163% ExceptionInfo *exception) 164% 165% A description of each parameter follows: 166% 167% o image_info: the image info. 168% 169% o exception: return any errors or warnings in this structure. 170% 171*/ 172static Image *ReadICONImage(const ImageInfo *image_info, 173 ExceptionInfo *exception) 174{ 175 IconFile 176 icon_file; 177 178 IconInfo 179 icon_info; 180 181 Image 182 *image; 183 184 MagickBooleanType 185 status; 186 187 register ssize_t 188 i, 189 x; 190 191 register Quantum 192 *q; 193 194 register unsigned char 195 *p; 196 197 size_t 198 bit, 199 byte, 200 bytes_per_line, 201 one, 202 scanline_pad; 203 204 ssize_t 205 count, 206 offset, 207 y; 208 209 /* 210 Open image file. 211 */ 212 assert(image_info != (const ImageInfo *) NULL); 213 assert(image_info->signature == MagickSignature); 214 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"%s",image_info->filename); 215 assert(exception != (ExceptionInfo *) NULL); 216 assert(exception->signature == MagickSignature); 217 image=AcquireImage(image_info); 218 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception); 219 if (status == MagickFalse) 220 { 221 image=DestroyImageList(image); 222 return((Image *) NULL); 223 } 224 icon_file.reserved=(short) ReadBlobLSBShort(image); 225 icon_file.resource_type=(short) ReadBlobLSBShort(image); 226 icon_file.count=(short) ReadBlobLSBShort(image); 227 if ((icon_file.reserved != 0) || 228 ((icon_file.resource_type != 1) && (icon_file.resource_type != 2)) || 229 (icon_file.count > MaxIcons)) 230 ThrowReaderException(CorruptImageError,"ImproperImageHeader"); 231 for (i=0; i < icon_file.count; i++) 232 { 233 icon_file.directory[i].width=(unsigned char) ReadBlobByte(image); 234 icon_file.directory[i].height=(unsigned char) ReadBlobByte(image); 235 icon_file.directory[i].colors=(unsigned char) ReadBlobByte(image); 236 icon_file.directory[i].reserved=(unsigned char) ReadBlobByte(image); 237 icon_file.directory[i].planes=(unsigned short) ReadBlobLSBShort(image); 238 icon_file.directory[i].bits_per_pixel=(unsigned short) 239 ReadBlobLSBShort(image); 240 icon_file.directory[i].size=ReadBlobLSBLong(image); 241 icon_file.directory[i].offset=ReadBlobLSBLong(image); 242 } 243 one=1; 244 for (i=0; i < icon_file.count; i++) 245 { 246 /* 247 Verify Icon identifier. 248 */ 249 offset=(ssize_t) SeekBlob(image,(MagickOffsetType) 250 icon_file.directory[i].offset,SEEK_SET); 251 if (offset < 0) 252 ThrowReaderException(CorruptImageError,"ImproperImageHeader"); 253 icon_info.size=ReadBlobLSBLong(image); 254 icon_info.width=(unsigned char) ((int) ReadBlobLSBLong(image)); 255 icon_info.height=(unsigned char) ((int) ReadBlobLSBLong(image)/2); 256 if ((icon_file.directory[i].width == 0) && 257 (icon_file.directory[i].height == 0)) 258 { 259 Image 260 *icon_image; 261 262 ImageInfo 263 *read_info; 264 265 size_t 266 length; 267 268 unsigned char 269 *png; 270 271 /* 272 Icon image encoded as a compressed PNG image. 273 */ 274 length=icon_file.directory[i].size; 275 png=(unsigned char *) AcquireQuantumMemory(length+12,sizeof(*png)); 276 if (png == (unsigned char *) NULL) 277 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed"); 278 (void) CopyMagickMemory(png,"\211PNG\r\n\032\n\000\000\000\015",12); 279 count=ReadBlob(image,length-12,png+12); 280 if (count != (ssize_t) (length-12)) 281 { 282 png=(unsigned char *) RelinquishMagickMemory(png); 283 ThrowReaderException(CorruptImageError, 284 "InsufficientImageDataInFile"); 285 } 286 read_info=CloneImageInfo(image_info); 287 (void) CopyMagickString(read_info->magick,"PNG",MaxTextExtent); 288 icon_image=BlobToImage(read_info,png,length+12,exception); 289 read_info=DestroyImageInfo(read_info); 290 png=(unsigned char *) RelinquishMagickMemory(png); 291 if (icon_image == (Image *) NULL) 292 { 293 image=DestroyImageList(image); 294 return((Image *) NULL); 295 } 296 DestroyBlob(icon_image); 297 icon_image->blob=ReferenceBlob(image->blob); 298 ReplaceImageInList(&image,icon_image); 299 } 300 else 301 { 302 icon_info.planes=ReadBlobLSBShort(image); 303 icon_info.bits_per_pixel=ReadBlobLSBShort(image); 304 if (icon_info.bits_per_pixel > 32) 305 ThrowReaderException(CorruptImageError,"ImproperImageHeader"); 306 icon_info.compression=ReadBlobLSBLong(image); 307 icon_info.image_size=ReadBlobLSBLong(image); 308 icon_info.x_pixels=ReadBlobLSBLong(image); 309 icon_info.y_pixels=ReadBlobLSBLong(image); 310 icon_info.number_colors=ReadBlobLSBLong(image); 311 icon_info.colors_important=ReadBlobLSBLong(image); 312 image->matte=MagickTrue; 313 image->columns=(size_t) icon_file.directory[i].width; 314 if ((ssize_t) image->columns > icon_info.width) 315 image->columns=(size_t) icon_info.width; 316 image->rows=(size_t) icon_file.directory[i].height; 317 if ((ssize_t) image->rows > icon_info.height) 318 image->rows=(size_t) icon_info.height; 319 image->depth=icon_info.bits_per_pixel; 320 if (image->debug != MagickFalse) 321 { 322 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 323 " scene = %.20g",(double) i); 324 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 325 " size = %.20g",(double) icon_info.size); 326 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 327 " width = %.20g",(double) icon_file.directory[i].width); 328 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 329 " height = %.20g",(double) icon_file.directory[i].height); 330 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 331 " colors = %.20g",(double ) icon_info.number_colors); 332 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 333 " planes = %.20g",(double) icon_info.planes); 334 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 335 " bpp = %.20g",(double) icon_info.bits_per_pixel); 336 } 337 if ((icon_info.number_colors != 0) || (icon_info.bits_per_pixel <= 16)) 338 { 339 image->storage_class=PseudoClass; 340 image->colors=icon_info.number_colors; 341 if (image->colors == 0) 342 image->colors=one << icon_info.bits_per_pixel; 343 } 344 if (image->storage_class == PseudoClass) 345 { 346 register ssize_t 347 i; 348 349 size_t 350 number_colors, 351 one; 352 353 unsigned char 354 *icon_colormap; 355 356 /* 357 Read Icon raster colormap. 358 */ 359 one=1; 360 number_colors=one << icon_info.bits_per_pixel; 361 if (AcquireImageColormap(image,number_colors) == MagickFalse) 362 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed"); 363 icon_colormap=(unsigned char *) AcquireQuantumMemory((size_t) 364 image->colors,4UL*sizeof(*icon_colormap)); 365 if (icon_colormap == (unsigned char *) NULL) 366 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed"); 367 count=ReadBlob(image,(size_t) (4*image->colors),icon_colormap); 368 if (count != (ssize_t) (4*image->colors)) 369 ThrowReaderException(CorruptImageError, 370 "InsufficientImageDataInFile"); 371 p=icon_colormap; 372 for (i=0; i < (ssize_t) image->colors; i++) 373 { 374 image->colormap[i].blue=(Quantum) ScaleCharToQuantum(*p++); 375 image->colormap[i].green=(Quantum) ScaleCharToQuantum(*p++); 376 image->colormap[i].red=(Quantum) ScaleCharToQuantum(*p++); 377 p++; 378 } 379 icon_colormap=(unsigned char *) RelinquishMagickMemory(icon_colormap); 380 } 381 /* 382 Convert Icon raster image to pixel packets. 383 */ 384 if ((image_info->ping != MagickFalse) && 385 (image_info->number_scenes != 0)) 386 if (image->scene >= (image_info->scene+image_info->number_scenes-1)) 387 break; 388 bytes_per_line=(((image->columns*icon_info.bits_per_pixel)+31) & 389 ~31) >> 3; 390 (void) bytes_per_line; 391 scanline_pad=((((image->columns*icon_info.bits_per_pixel)+31) & ~31)- 392 (image->columns*icon_info.bits_per_pixel)) >> 3; 393 switch (icon_info.bits_per_pixel) 394 { 395 case 1: 396 { 397 /* 398 Convert bitmap scanline. 399 */ 400 for (y=(ssize_t) image->rows-1; y >= 0; y--) 401 { 402 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception); 403 if (q == (Quantum *) NULL) 404 break; 405 for (x=0; x < (ssize_t) (image->columns-7); x+=8) 406 { 407 byte=(size_t) ReadBlobByte(image); 408 for (bit=0; bit < 8; bit++) 409 { 410 SetPixelIndex(image,((byte & (0x80 >> bit)) != 0 ? 0x01 : 411 0x00),q); 412 q+=GetPixelChannels(image); 413 } 414 } 415 if ((image->columns % 8) != 0) 416 { 417 byte=(size_t) ReadBlobByte(image); 418 for (bit=0; bit < (image->columns % 8); bit++) 419 { 420 SetPixelIndex(image,((byte & (0x80 >> bit)) != 0 ? 0x01 : 421 0x00),q); 422 q+=GetPixelChannels(image); 423 } 424 } 425 for (x=0; x < (ssize_t) scanline_pad; x++) 426 (void) ReadBlobByte(image); 427 if (SyncAuthenticPixels(image,exception) == MagickFalse) 428 break; 429 if (image->previous == (Image *) NULL) 430 { 431 status=SetImageProgress(image,LoadImageTag,image->rows-y-1, 432 image->rows); 433 if (status == MagickFalse) 434 break; 435 } 436 } 437 break; 438 } 439 case 4: 440 { 441 /* 442 Read 4-bit Icon scanline. 443 */ 444 for (y=(ssize_t) image->rows-1; y >= 0; y--) 445 { 446 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception); 447 if (q == (Quantum *) NULL) 448 break; 449 for (x=0; x < ((ssize_t) image->columns-1); x+=2) 450 { 451 byte=(size_t) ReadBlobByte(image); 452 SetPixelIndex(image,((byte >> 4) & 0xf),q); 453 q+=GetPixelChannels(image); 454 SetPixelIndex(image,((byte) & 0xf),q); 455 q+=GetPixelChannels(image); 456 } 457 if ((image->columns % 2) != 0) 458 { 459 byte=(size_t) ReadBlobByte(image); 460 SetPixelIndex(image,((byte >> 4) & 0xf),q); 461 q+=GetPixelChannels(image); 462 } 463 for (x=0; x < (ssize_t) scanline_pad; x++) 464 (void) ReadBlobByte(image); 465 if (SyncAuthenticPixels(image,exception) == MagickFalse) 466 break; 467 if (image->previous == (Image *) NULL) 468 { 469 status=SetImageProgress(image,LoadImageTag,image->rows-y-1, 470 image->rows); 471 if (status == MagickFalse) 472 break; 473 } 474 } 475 break; 476 } 477 case 8: 478 { 479 /* 480 Convert PseudoColor scanline. 481 */ 482 for (y=(ssize_t) image->rows-1; y >= 0; y--) 483 { 484 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception); 485 if (q == (Quantum *) NULL) 486 break; 487 for (x=0; x < (ssize_t) image->columns; x++) 488 { 489 byte=(size_t) ReadBlobByte(image); 490 SetPixelIndex(image,byte,q); 491 q+=GetPixelChannels(image); 492 } 493 for (x=0; x < (ssize_t) scanline_pad; x++) 494 (void) ReadBlobByte(image); 495 if (SyncAuthenticPixels(image,exception) == MagickFalse) 496 break; 497 if (image->previous == (Image *) NULL) 498 { 499 status=SetImageProgress(image,LoadImageTag,image->rows-y-1, 500 image->rows); 501 if (status == MagickFalse) 502 break; 503 } 504 } 505 break; 506 } 507 case 16: 508 { 509 /* 510 Convert PseudoColor scanline. 511 */ 512 for (y=(ssize_t) image->rows-1; y >= 0; y--) 513 { 514 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception); 515 if (q == (Quantum *) NULL) 516 break; 517 for (x=0; x < (ssize_t) image->columns; x++) 518 { 519 byte=(size_t) ReadBlobByte(image); 520 byte|=(size_t) (ReadBlobByte(image) << 8); 521 SetPixelIndex(image,byte,q); 522 q+=GetPixelChannels(image); 523 } 524 for (x=0; x < (ssize_t) scanline_pad; x++) 525 (void) ReadBlobByte(image); 526 if (SyncAuthenticPixels(image,exception) == MagickFalse) 527 break; 528 if (image->previous == (Image *) NULL) 529 { 530 status=SetImageProgress(image,LoadImageTag,image->rows-y-1, 531 image->rows); 532 if (status == MagickFalse) 533 break; 534 } 535 } 536 break; 537 } 538 case 24: 539 case 32: 540 { 541 /* 542 Convert DirectColor scanline. 543 */ 544 for (y=(ssize_t) image->rows-1; y >= 0; y--) 545 { 546 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception); 547 if (q == (Quantum *) NULL) 548 break; 549 for (x=0; x < (ssize_t) image->columns; x++) 550 { 551 SetPixelBlue(image,ScaleCharToQuantum((unsigned char) 552 ReadBlobByte(image)),q); 553 SetPixelGreen(image,ScaleCharToQuantum((unsigned char) 554 ReadBlobByte(image)),q); 555 SetPixelRed(image,ScaleCharToQuantum((unsigned char) 556 ReadBlobByte(image)),q); 557 if (icon_info.bits_per_pixel == 32) 558 SetPixelAlpha(image,ScaleCharToQuantum((unsigned char) 559 ReadBlobByte(image)),q); 560 q+=GetPixelChannels(image); 561 } 562 if (icon_info.bits_per_pixel == 24) 563 for (x=0; x < (ssize_t) scanline_pad; x++) 564 (void) ReadBlobByte(image); 565 if (SyncAuthenticPixels(image,exception) == MagickFalse) 566 break; 567 if (image->previous == (Image *) NULL) 568 { 569 status=SetImageProgress(image,LoadImageTag,image->rows-y-1, 570 image->rows); 571 if (status == MagickFalse) 572 break; 573 } 574 } 575 break; 576 } 577 default: 578 ThrowReaderException(CorruptImageError,"ImproperImageHeader"); 579 } 580 if (image_info->ping == MagickFalse) 581 (void) SyncImage(image); 582 if (icon_info.bits_per_pixel != 32) 583 { 584 /* 585 Read the ICON alpha mask. 586 */ 587 image->storage_class=DirectClass; 588 for (y=(ssize_t) image->rows-1; y >= 0; y--) 589 { 590 q=GetAuthenticPixels(image,0,y,image->columns,1,exception); 591 if (q == (Quantum *) NULL) 592 break; 593 for (x=0; x < ((ssize_t) image->columns-7); x+=8) 594 { 595 byte=(size_t) ReadBlobByte(image); 596 for (bit=0; bit < 8; bit++) 597 { 598 SetPixelAlpha(image,(((byte & (0x80 >> bit)) != 0) ? 599 TransparentAlpha : OpaqueAlpha),q); 600 q+=GetPixelChannels(image); 601 } 602 } 603 if ((image->columns % 8) != 0) 604 { 605 byte=(size_t) ReadBlobByte(image); 606 for (bit=0; bit < (image->columns % 8); bit++) 607 { 608 SetPixelAlpha(image,(((byte & (0x80 >> bit)) != 0) ? 609 TransparentAlpha : OpaqueAlpha),q); 610 q+=GetPixelChannels(image); 611 } 612 } 613 if ((image->columns % 32) != 0) 614 for (x=0; x < (ssize_t) ((32-(image->columns % 32))/8); x++) 615 (void) ReadBlobByte(image); 616 if (SyncAuthenticPixels(image,exception) == MagickFalse) 617 break; 618 } 619 } 620 if (EOFBlob(image) != MagickFalse) 621 { 622 ThrowFileException(exception,CorruptImageError, 623 "UnexpectedEndOfFile",image->filename); 624 break; 625 } 626 } 627 /* 628 Proceed to next image. 629 */ 630 if (image_info->number_scenes != 0) 631 if (image->scene >= (image_info->scene+image_info->number_scenes-1)) 632 break; 633 if (i < (ssize_t) (icon_file.count-1)) 634 { 635 /* 636 Allocate next image structure. 637 */ 638 AcquireNextImage(image_info,image); 639 if (GetNextImageInList(image) == (Image *) NULL) 640 { 641 image=DestroyImageList(image); 642 return((Image *) NULL); 643 } 644 image=SyncNextImageInList(image); 645 status=SetImageProgress(image,LoadImagesTag,TellBlob(image), 646 GetBlobSize(image)); 647 if (status == MagickFalse) 648 break; 649 } 650 } 651 (void) CloseBlob(image); 652 return(GetFirstImageInList(image)); 653} 654 655/* 656%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 657% % 658% % 659% % 660% R e g i s t e r I C O N I m a g e % 661% % 662% % 663% % 664%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 665% 666% RegisterICONImage() adds attributes for the Icon image format to 667% the list of supported formats. The attributes include the image format 668% tag, a method to read and/or write the format, whether the format 669% supports the saving of more than one frame to the same file or blob, 670% whether the format supports native in-memory I/O, and a brief 671% description of the format. 672% 673% The format of the RegisterICONImage method is: 674% 675% size_t RegisterICONImage(void) 676% 677*/ 678ModuleExport size_t RegisterICONImage(void) 679{ 680 MagickInfo 681 *entry; 682 683 entry=SetMagickInfo("CUR"); 684 entry->decoder=(DecodeImageHandler *) ReadICONImage; 685 entry->encoder=(EncodeImageHandler *) WriteICONImage; 686 entry->adjoin=MagickFalse; 687 entry->seekable_stream=MagickTrue; 688 entry->description=ConstantString("Microsoft icon"); 689 entry->module=ConstantString("CUR"); 690 (void) RegisterMagickInfo(entry); 691 entry=SetMagickInfo("ICO"); 692 entry->decoder=(DecodeImageHandler *) ReadICONImage; 693 entry->encoder=(EncodeImageHandler *) WriteICONImage; 694 entry->adjoin=MagickTrue; 695 entry->seekable_stream=MagickTrue; 696 entry->description=ConstantString("Microsoft icon"); 697 entry->module=ConstantString("ICON"); 698 (void) RegisterMagickInfo(entry); 699 entry=SetMagickInfo("ICON"); 700 entry->decoder=(DecodeImageHandler *) ReadICONImage; 701 entry->encoder=(EncodeImageHandler *) WriteICONImage; 702 entry->adjoin=MagickFalse; 703 entry->seekable_stream=MagickTrue; 704 entry->description=ConstantString("Microsoft icon"); 705 entry->module=ConstantString("ICON"); 706 (void) RegisterMagickInfo(entry); 707 return(MagickImageCoderSignature); 708} 709 710/* 711%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 712% % 713% % 714% % 715% U n r e g i s t e r I C O N I m a g e % 716% % 717% % 718% % 719%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 720% 721% UnregisterICONImage() removes format registrations made by the 722% ICON module from the list of supported formats. 723% 724% The format of the UnregisterICONImage method is: 725% 726% UnregisterICONImage(void) 727% 728*/ 729ModuleExport void UnregisterICONImage(void) 730{ 731 (void) UnregisterMagickInfo("CUR"); 732 (void) UnregisterMagickInfo("ICO"); 733 (void) UnregisterMagickInfo("ICON"); 734} 735 736/* 737%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 738% % 739% % 740% % 741% W r i t e I C O N I m a g e % 742% % 743% % 744% % 745%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 746% 747% WriteICONImage() writes an image in Microsoft Windows bitmap encoded 748% image format, version 3 for Windows or (if the image has a matte channel) 749% version 4. 750% 751% The format of the WriteICONImage method is: 752% 753% MagickBooleanType WriteICONImage(const ImageInfo *image_info, 754% Image *image,ExceptionInfo *exception) 755% 756% A description of each parameter follows. 757% 758% o image_info: the image info. 759% 760% o image: The image. 761% 762% o exception: return any errors or warnings in this structure. 763% 764*/ 765static MagickBooleanType WriteICONImage(const ImageInfo *image_info, 766 Image *image,ExceptionInfo *exception) 767{ 768 IconFile 769 icon_file; 770 771 IconInfo 772 icon_info; 773 774 Image 775 *next; 776 777 MagickBooleanType 778 status; 779 780 MagickOffsetType 781 offset, 782 scene; 783 784 register const Quantum 785 *p; 786 787 register ssize_t 788 i, 789 x; 790 791 register unsigned char 792 *q; 793 794 size_t 795 bytes_per_line, 796 scanline_pad; 797 798 ssize_t 799 y; 800 801 unsigned char 802 bit, 803 byte, 804 *pixels; 805 806 /* 807 Open output image file. 808 */ 809 assert(image_info != (const ImageInfo *) NULL); 810 assert(image_info->signature == MagickSignature); 811 assert(image != (Image *) NULL); 812 assert(image->signature == MagickSignature); 813 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"%s",image->filename); 814 assert(exception != (ExceptionInfo *) NULL); 815 assert(exception->signature == MagickSignature); 816 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception); 817 if (status == MagickFalse) 818 return(status); 819 scene=0; 820 next=image; 821 do 822 { 823 if ((image->columns > 256L) || (image->rows > 256L)) 824 ThrowWriterException(ImageError,"WidthOrHeightExceedsLimit"); 825 scene++; 826 next=SyncNextImageInList(next); 827 } while ((next != (Image *) NULL) && (image_info->adjoin != MagickFalse)); 828 /* 829 Dump out a ICON header template to be properly initialized later. 830 */ 831 (void) WriteBlobLSBShort(image,0); 832 (void) WriteBlobLSBShort(image,1); 833 (void) WriteBlobLSBShort(image,(unsigned char) scene); 834 (void) ResetMagickMemory(&icon_file,0,sizeof(icon_file)); 835 (void) ResetMagickMemory(&icon_info,0,sizeof(icon_info)); 836 scene=0; 837 next=image; 838 do 839 { 840 (void) WriteBlobByte(image,icon_file.directory[scene].width); 841 (void) WriteBlobByte(image,icon_file.directory[scene].height); 842 (void) WriteBlobByte(image,icon_file.directory[scene].colors); 843 (void) WriteBlobByte(image,icon_file.directory[scene].reserved); 844 (void) WriteBlobLSBShort(image,icon_file.directory[scene].planes); 845 (void) WriteBlobLSBShort(image,icon_file.directory[scene].bits_per_pixel); 846 (void) WriteBlobLSBLong(image,(unsigned int) 847 icon_file.directory[scene].size); 848 (void) WriteBlobLSBLong(image,(unsigned int) 849 icon_file.directory[scene].offset); 850 scene++; 851 next=SyncNextImageInList(next); 852 } while ((next != (Image *) NULL) && (image_info->adjoin != MagickFalse)); 853 scene=0; 854 next=image; 855 do 856 { 857 if ((next->columns == 256) && (next->rows == 256)) 858 { 859 Image 860 *write_image; 861 862 ImageInfo 863 *write_info; 864 865 size_t 866 length; 867 868 unsigned char 869 *png; 870 871 /* 872 Icon image encoded as a compressed PNG image. 873 */ 874 write_image=CloneImage(next,0,0,MagickTrue,exception); 875 if (write_image == (Image *) NULL) 876 return(MagickFalse); 877 write_info=CloneImageInfo(image_info); 878 (void) CopyMagickString(write_info->filename,"PNG:",MaxTextExtent); 879 png=(unsigned char *) ImageToBlob(write_info,write_image,&length, 880 exception); 881 write_image=DestroyImage(write_image); 882 write_info=DestroyImageInfo(write_info); 883 if (png == (unsigned char *) NULL) 884 return(MagickFalse); 885 icon_file.directory[scene].width=0; 886 icon_file.directory[scene].height=0; 887 icon_file.directory[scene].colors=0; 888 icon_file.directory[scene].reserved=0; 889 icon_file.directory[scene].planes=1; 890 icon_file.directory[scene].bits_per_pixel=32; 891 icon_file.directory[scene].size=(size_t) length; 892 icon_file.directory[scene].offset=(size_t) TellBlob(image); 893 (void) WriteBlob(image,(size_t) length,png); 894 png=(unsigned char *) RelinquishMagickMemory(png); 895 } 896 else 897 { 898 /* 899 Initialize ICON raster file header. 900 */ 901 if (next->colorspace != RGBColorspace) 902 (void) TransformImageColorspace(next,RGBColorspace); 903 icon_info.file_size=14+12+28; 904 icon_info.offset_bits=icon_info.file_size; 905 icon_info.compression=BI_RGB; 906 if ((next->storage_class != DirectClass) && (next->colors > 256)) 907 (void) SetImageStorageClass(next,DirectClass,exception); 908 if (next->storage_class == DirectClass) 909 { 910 /* 911 Full color ICON raster. 912 */ 913 icon_info.number_colors=0; 914 icon_info.bits_per_pixel=32; 915 icon_info.compression=(size_t) BI_RGB; 916 } 917 else 918 { 919 size_t 920 one; 921 922 /* 923 Colormapped ICON raster. 924 */ 925 icon_info.bits_per_pixel=8; 926 if (next->colors <= 256) 927 icon_info.bits_per_pixel=8; 928 if (next->colors <= 16) 929 icon_info.bits_per_pixel=4; 930 if (next->colors <= 2) 931 icon_info.bits_per_pixel=1; 932 one=1; 933 icon_info.number_colors=one << icon_info.bits_per_pixel; 934 if (icon_info.number_colors < next->colors) 935 { 936 (void) SetImageStorageClass(next,DirectClass,exception); 937 icon_info.number_colors=0; 938 icon_info.bits_per_pixel=(unsigned short) 24; 939 icon_info.compression=(size_t) BI_RGB; 940 } 941 else 942 { 943 size_t 944 one; 945 946 one=1; 947 icon_info.file_size+=3*(one << icon_info.bits_per_pixel); 948 icon_info.offset_bits+=3*(one << icon_info.bits_per_pixel); 949 icon_info.file_size+=(one << icon_info.bits_per_pixel); 950 icon_info.offset_bits+=(one << icon_info.bits_per_pixel); 951 } 952 } 953 bytes_per_line=(((next->columns*icon_info.bits_per_pixel)+31) & 954 ~31) >> 3; 955 icon_info.ba_offset=0; 956 icon_info.width=(ssize_t) next->columns; 957 icon_info.height=(ssize_t) next->rows; 958 icon_info.planes=1; 959 icon_info.image_size=bytes_per_line*next->rows; 960 icon_info.size=40; 961 icon_info.size+=(4*icon_info.number_colors); 962 icon_info.size+=icon_info.image_size; 963 icon_info.size+=(((icon_info.width+31) & ~31) >> 3)*icon_info.height; 964 icon_info.file_size+=icon_info.image_size; 965 icon_info.x_pixels=0; 966 icon_info.y_pixels=0; 967 switch (next->units) 968 { 969 case UndefinedResolution: 970 case PixelsPerInchResolution: 971 { 972 icon_info.x_pixels=(size_t) (100.0*next->x_resolution/2.54); 973 icon_info.y_pixels=(size_t) (100.0*next->y_resolution/2.54); 974 break; 975 } 976 case PixelsPerCentimeterResolution: 977 { 978 icon_info.x_pixels=(size_t) (100.0*next->x_resolution); 979 icon_info.y_pixels=(size_t) (100.0*next->y_resolution); 980 break; 981 } 982 } 983 icon_info.colors_important=icon_info.number_colors; 984 /* 985 Convert MIFF to ICON raster pixels. 986 */ 987 pixels=(unsigned char *) AcquireQuantumMemory((size_t) 988 icon_info.image_size,sizeof(*pixels)); 989 if (pixels == (unsigned char *) NULL) 990 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed"); 991 (void) ResetMagickMemory(pixels,0,(size_t) icon_info.image_size); 992 switch (icon_info.bits_per_pixel) 993 { 994 case 1: 995 { 996 size_t 997 bit, 998 byte; 999 1000 /* 1001 Convert PseudoClass image to a ICON monochrome image. 1002 */ 1003 for (y=0; y < (ssize_t) next->rows; y++) 1004 { 1005 p=GetVirtualPixels(next,0,y,next->columns,1,exception); 1006 if (p == (const Quantum *) NULL) 1007 break; 1008 q=pixels+(next->rows-y-1)*bytes_per_line; 1009 bit=0; 1010 byte=0; 1011 for (x=0; x < (ssize_t) next->columns; x++) 1012 { 1013 byte<<=1; 1014 byte|=GetPixelIndex(next,p) != 0 ? 0x01 : 0x00; 1015 bit++; 1016 if (bit == 8) 1017 { 1018 *q++=(unsigned char) byte; 1019 bit=0; 1020 byte=0; 1021 } 1022 p+=GetPixelChannels(image); 1023 } 1024 if (bit != 0) 1025 *q++=(unsigned char) (byte << (8-bit)); 1026 if (next->previous == (Image *) NULL) 1027 { 1028 status=SetImageProgress(next,SaveImageTag,y,next->rows); 1029 if (status == MagickFalse) 1030 break; 1031 } 1032 } 1033 break; 1034 } 1035 case 4: 1036 { 1037 size_t 1038 nibble, 1039 byte; 1040 1041 /* 1042 Convert PseudoClass image to a ICON monochrome image. 1043 */ 1044 for (y=0; y < (ssize_t) next->rows; y++) 1045 { 1046 p=GetVirtualPixels(next,0,y,next->columns,1,exception); 1047 if (p == (const Quantum *) NULL) 1048 break; 1049 q=pixels+(next->rows-y-1)*bytes_per_line; 1050 nibble=0; 1051 byte=0; 1052 for (x=0; x < (ssize_t) next->columns; x++) 1053 { 1054 byte<<=4; 1055 byte|=((size_t) GetPixelIndex(next,p) & 0x0f); 1056 nibble++; 1057 if (nibble == 2) 1058 { 1059 *q++=(unsigned char) byte; 1060 nibble=0; 1061 byte=0; 1062 } 1063 p+=GetPixelChannels(image); 1064 } 1065 if (nibble != 0) 1066 *q++=(unsigned char) (byte << 4); 1067 if (next->previous == (Image *) NULL) 1068 { 1069 status=SetImageProgress(next,SaveImageTag,y,next->rows); 1070 if (status == MagickFalse) 1071 break; 1072 } 1073 } 1074 break; 1075 } 1076 case 8: 1077 { 1078 /* 1079 Convert PseudoClass packet to ICON pixel. 1080 */ 1081 for (y=0; y < (ssize_t) next->rows; y++) 1082 { 1083 p=GetVirtualPixels(next,0,y,next->columns,1,exception); 1084 if (p == (const Quantum *) NULL) 1085 break; 1086 q=pixels+(next->rows-y-1)*bytes_per_line; 1087 for (x=0; x < (ssize_t) next->columns; x++) 1088 { 1089 *q++=(unsigned char) GetPixelIndex(next,p); 1090 p+=GetPixelChannels(image); 1091 } 1092 if (next->previous == (Image *) NULL) 1093 { 1094 status=SetImageProgress(next,SaveImageTag,y,next->rows); 1095 if (status == MagickFalse) 1096 break; 1097 } 1098 } 1099 break; 1100 } 1101 case 24: 1102 case 32: 1103 { 1104 /* 1105 Convert DirectClass packet to ICON BGR888 or BGRA8888 pixel. 1106 */ 1107 for (y=0; y < (ssize_t) next->rows; y++) 1108 { 1109 p=GetVirtualPixels(next,0,y,next->columns,1,exception); 1110 if (p == (const Quantum *) NULL) 1111 break; 1112 q=pixels+(next->rows-y-1)*bytes_per_line; 1113 for (x=0; x < (ssize_t) next->columns; x++) 1114 { 1115 *q++=ScaleQuantumToChar(GetPixelBlue(next,p)); 1116 *q++=ScaleQuantumToChar(GetPixelGreen(next,p)); 1117 *q++=ScaleQuantumToChar(GetPixelRed(next,p)); 1118 if (next->matte == MagickFalse) 1119 *q++=ScaleQuantumToChar(QuantumRange); 1120 else 1121 *q++=ScaleQuantumToChar(GetPixelAlpha(next,p)); 1122 p+=GetPixelChannels(next); 1123 } 1124 if (icon_info.bits_per_pixel == 24) 1125 for (x=3L*(ssize_t) next->columns; x < (ssize_t) bytes_per_line; x++) 1126 *q++=0x00; 1127 if (next->previous == (Image *) NULL) 1128 { 1129 status=SetImageProgress(next,SaveImageTag,y,next->rows); 1130 if (status == MagickFalse) 1131 break; 1132 } 1133 } 1134 break; 1135 } 1136 } 1137 /* 1138 Write 40-byte version 3+ bitmap header. 1139 */ 1140 icon_file.directory[scene].width=(unsigned char) icon_info.width; 1141 icon_file.directory[scene].height=(unsigned char) icon_info.height; 1142 icon_file.directory[scene].colors=(unsigned char) 1143 icon_info.number_colors; 1144 icon_file.directory[scene].reserved=0; 1145 icon_file.directory[scene].planes=icon_info.planes; 1146 icon_file.directory[scene].bits_per_pixel=icon_info.bits_per_pixel; 1147 icon_file.directory[scene].size=icon_info.size; 1148 icon_file.directory[scene].offset=(size_t) TellBlob(image); 1149 (void) WriteBlobLSBLong(image,(unsigned int) 40); 1150 (void) WriteBlobLSBLong(image,(unsigned int) icon_info.width); 1151 (void) WriteBlobLSBLong(image,(unsigned int) icon_info.height*2); 1152 (void) WriteBlobLSBShort(image,icon_info.planes); 1153 (void) WriteBlobLSBShort(image,icon_info.bits_per_pixel); 1154 (void) WriteBlobLSBLong(image,(unsigned int) icon_info.compression); 1155 (void) WriteBlobLSBLong(image,(unsigned int) icon_info.image_size); 1156 (void) WriteBlobLSBLong(image,(unsigned int) icon_info.x_pixels); 1157 (void) WriteBlobLSBLong(image,(unsigned int) icon_info.y_pixels); 1158 (void) WriteBlobLSBLong(image,(unsigned int) icon_info.number_colors); 1159 (void) WriteBlobLSBLong(image,(unsigned int) icon_info.colors_important); 1160 if (next->storage_class == PseudoClass) 1161 { 1162 unsigned char 1163 *icon_colormap; 1164 1165 /* 1166 Dump colormap to file. 1167 */ 1168 icon_colormap=(unsigned char *) AcquireQuantumMemory((size_t) 1169 (1UL << icon_info.bits_per_pixel),4UL*sizeof(*icon_colormap)); 1170 if (icon_colormap == (unsigned char *) NULL) 1171 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed"); 1172 q=icon_colormap; 1173 for (i=0; i < (ssize_t) next->colors; i++) 1174 { 1175 *q++=ScaleQuantumToChar(next->colormap[i].blue); 1176 *q++=ScaleQuantumToChar(next->colormap[i].green); 1177 *q++=ScaleQuantumToChar(next->colormap[i].red); 1178 *q++=(unsigned char) 0x0; 1179 } 1180 for ( ; i < (ssize_t) (1UL << icon_info.bits_per_pixel); i++) 1181 { 1182 *q++=(unsigned char) 0x00; 1183 *q++=(unsigned char) 0x00; 1184 *q++=(unsigned char) 0x00; 1185 *q++=(unsigned char) 0x00; 1186 } 1187 (void) WriteBlob(image,(size_t) (4UL*(1UL << 1188 icon_info.bits_per_pixel)),icon_colormap); 1189 icon_colormap=(unsigned char *) RelinquishMagickMemory( 1190 icon_colormap); 1191 } 1192 (void) WriteBlob(image,(size_t) icon_info.image_size,pixels); 1193 pixels=(unsigned char *) RelinquishMagickMemory(pixels); 1194 /* 1195 Write matte mask. 1196 */ 1197 scanline_pad=(((next->columns+31) & ~31)-next->columns) >> 3; 1198 for (y=((ssize_t) next->rows - 1); y >= 0; y--) 1199 { 1200 p=GetVirtualPixels(next,0,y,next->columns,1,exception); 1201 if (p == (const Quantum *) NULL) 1202 break; 1203 bit=0; 1204 byte=0; 1205 for (x=0; x < (ssize_t) next->columns; x++) 1206 { 1207 byte<<=1; 1208 if ((next->matte == MagickTrue) && 1209 (GetPixelAlpha(next,p) == (Quantum) TransparentAlpha)) 1210 byte|=0x01; 1211 bit++; 1212 if (bit == 8) 1213 { 1214 (void) WriteBlobByte(image,(unsigned char) byte); 1215 bit=0; 1216 byte=0; 1217 } 1218 p+=GetPixelChannels(next); 1219 } 1220 if (bit != 0) 1221 (void) WriteBlobByte(image,(unsigned char) (byte << (8-bit))); 1222 for (i=0; i < (ssize_t) scanline_pad; i++) 1223 (void) WriteBlobByte(image,(unsigned char) 0); 1224 } 1225 } 1226 if (GetNextImageInList(next) == (Image *) NULL) 1227 break; 1228 next=SyncNextImageInList(next); 1229 status=SetImageProgress(next,SaveImagesTag,scene++, 1230 GetImageListLength(next)); 1231 if (status == MagickFalse) 1232 break; 1233 } while ((next != (Image *) NULL) && (image_info->adjoin != MagickFalse)); 1234 offset=SeekBlob(image,0,SEEK_SET); 1235 (void) offset; 1236 (void) WriteBlobLSBShort(image,0); 1237 (void) WriteBlobLSBShort(image,1); 1238 (void) WriteBlobLSBShort(image,(unsigned short) (scene+1)); 1239 scene=0; 1240 next=image; 1241 do 1242 { 1243 (void) WriteBlobByte(image,icon_file.directory[scene].width); 1244 (void) WriteBlobByte(image,icon_file.directory[scene].height); 1245 (void) WriteBlobByte(image,icon_file.directory[scene].colors); 1246 (void) WriteBlobByte(image,icon_file.directory[scene].reserved); 1247 (void) WriteBlobLSBShort(image,icon_file.directory[scene].planes); 1248 (void) WriteBlobLSBShort(image,icon_file.directory[scene].bits_per_pixel); 1249 (void) WriteBlobLSBLong(image,(unsigned int) 1250 icon_file.directory[scene].size); 1251 (void) WriteBlobLSBLong(image,(unsigned int) 1252 icon_file.directory[scene].offset); 1253 scene++; 1254 next=SyncNextImageInList(next); 1255 } while ((next != (Image *) NULL) && (image_info->adjoin != MagickFalse)); 1256 (void) CloseBlob(image); 1257 return(MagickTrue); 1258} 1259