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