Home | History | Annotate | Download | only in coders
      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