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