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