]> granicus.if.org Git - imagemagick/blob - coders/icon.c
https://github.com/ImageMagick/ImageMagick/issues/659
[imagemagick] / coders / icon.c
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-2017 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://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 \f
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 \f
69 /*
70   Define declarations.
71 */
72 #if !defined(MAGICKCORE_WINDOWS_SUPPORT) || defined(__MINGW32__) || defined(__MINGW64__)
73 #define BI_RGB  0
74 #define BI_RLE8  1
75 #define BI_BITFIELDS  3
76 #endif
77 #define MaxIcons  1024
78 \f
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 \f
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
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 \f
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 */
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) 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) || (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             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             {
459               icon_colormap=(unsigned char *) RelinquishMagickMemory(
460                 icon_colormap);
461               ThrowReaderException(CorruptImageError,
462                 "InsufficientImageDataInFile");
463             }
464           p=icon_colormap;
465           for (i=0; i < (ssize_t) image->colors; i++)
466           {
467             image->colormap[i].blue=(Quantum) ScaleCharToQuantum(*p++);
468             image->colormap[i].green=(Quantum) ScaleCharToQuantum(*p++);
469             image->colormap[i].red=(Quantum) ScaleCharToQuantum(*p++);
470             p++;
471           }
472           icon_colormap=(unsigned char *) RelinquishMagickMemory(icon_colormap);
473         }
474         /*
475           Convert Icon raster image to pixel packets.
476         */
477         if ((image_info->ping != MagickFalse) &&
478             (image_info->number_scenes != 0))
479           if (image->scene >= (image_info->scene+image_info->number_scenes-1))
480             break;
481         status=SetImageExtent(image,image->columns,image->rows,exception);
482         if (status == MagickFalse)
483           return(DestroyImageList(image));
484         bytes_per_line=(((image->columns*icon_info.bits_per_pixel)+31) &
485           ~31) >> 3;
486         (void) bytes_per_line;
487         scanline_pad=((((image->columns*icon_info.bits_per_pixel)+31) & ~31)-
488           (image->columns*icon_info.bits_per_pixel)) >> 3;
489         switch (icon_info.bits_per_pixel)
490         {
491           case 1:
492           {
493             /*
494               Convert bitmap scanline.
495             */
496             for (y=(ssize_t) image->rows-1; y >= 0; y--)
497             {
498               q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
499               if (q == (Quantum *) NULL)
500                 break;
501               for (x=0; x < (ssize_t) (image->columns-7); x+=8)
502               {
503                 byte=(size_t) ReadBlobByte(image);
504                 for (bit=0; bit < 8; bit++)
505                 {
506                   SetPixelIndex(image,((byte & (0x80 >> bit)) != 0 ? 0x01 :
507                     0x00),q);
508                   q+=GetPixelChannels(image);
509                 }
510               }
511               if ((image->columns % 8) != 0)
512                 {
513                   byte=(size_t) ReadBlobByte(image);
514                   for (bit=0; bit < (image->columns % 8); bit++)
515                   {
516                     SetPixelIndex(image,((byte & (0x80 >> bit)) != 0 ? 0x01 :
517                       0x00),q);
518                     q+=GetPixelChannels(image);
519                   }
520                 }
521               for (x=0; x < (ssize_t) scanline_pad; x++)
522                 (void) ReadBlobByte(image);
523               if (SyncAuthenticPixels(image,exception) == MagickFalse)
524                 break;
525               if (image->previous == (Image *) NULL)
526                 {
527                   status=SetImageProgress(image,LoadImageTag,image->rows-y-1,
528                     image->rows);
529                   if (status == MagickFalse)
530                     break;
531                 }
532             }
533             break;
534           }
535           case 4:
536           {
537             /*
538               Read 4-bit Icon scanline.
539             */
540             for (y=(ssize_t) image->rows-1; y >= 0; y--)
541             {
542               q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
543               if (q == (Quantum *) NULL)
544                 break;
545               for (x=0; x < ((ssize_t) image->columns-1); x+=2)
546               {
547                 byte=(size_t) ReadBlobByte(image);
548                 SetPixelIndex(image,((byte >> 4) & 0xf),q);
549                 q+=GetPixelChannels(image);
550                 SetPixelIndex(image,((byte) & 0xf),q);
551                 q+=GetPixelChannels(image);
552               }
553               if ((image->columns % 2) != 0)
554                 {
555                   byte=(size_t) ReadBlobByte(image);
556                   SetPixelIndex(image,((byte >> 4) & 0xf),q);
557                   q+=GetPixelChannels(image);
558                 }
559               for (x=0; x < (ssize_t) scanline_pad; x++)
560                 (void) ReadBlobByte(image);
561               if (SyncAuthenticPixels(image,exception) == MagickFalse)
562                 break;
563               if (image->previous == (Image *) NULL)
564                 {
565                   status=SetImageProgress(image,LoadImageTag,image->rows-y-1,
566                     image->rows);
567                   if (status == MagickFalse)
568                     break;
569                 }
570             }
571             break;
572           }
573           case 8:
574           {
575             /*
576               Convert PseudoColor scanline.
577             */
578             for (y=(ssize_t) image->rows-1; y >= 0; y--)
579             {
580               q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
581               if (q == (Quantum *) NULL)
582                 break;
583               for (x=0; x < (ssize_t) image->columns; x++)
584               {
585                 byte=(size_t) ReadBlobByte(image);
586                 SetPixelIndex(image,(Quantum) byte,q);
587                 q+=GetPixelChannels(image);
588               }
589               for (x=0; x < (ssize_t) scanline_pad; x++)
590                 (void) ReadBlobByte(image);
591               if (SyncAuthenticPixels(image,exception) == MagickFalse)
592                 break;
593               if (image->previous == (Image *) NULL)
594                 {
595                   status=SetImageProgress(image,LoadImageTag,image->rows-y-1,
596                     image->rows);
597                   if (status == MagickFalse)
598                     break;
599                 }
600             }
601             break;
602           }
603           case 16:
604           {
605             /*
606               Convert PseudoColor scanline.
607             */
608             for (y=(ssize_t) image->rows-1; y >= 0; y--)
609             {
610               q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
611               if (q == (Quantum *) NULL)
612                 break;
613               for (x=0; x < (ssize_t) image->columns; x++)
614               {
615                 byte=(size_t) ReadBlobByte(image);
616                 byte|=(size_t) (ReadBlobByte(image) << 8);
617                 SetPixelIndex(image,(Quantum) byte,q);
618                 q+=GetPixelChannels(image);
619               }
620               for (x=0; x < (ssize_t) scanline_pad; x++)
621                 (void) ReadBlobByte(image);
622               if (SyncAuthenticPixels(image,exception) == MagickFalse)
623                 break;
624               if (image->previous == (Image *) NULL)
625                 {
626                   status=SetImageProgress(image,LoadImageTag,image->rows-y-1,
627                     image->rows);
628                   if (status == MagickFalse)
629                     break;
630                 }
631             }
632             break;
633           }
634           case 24:
635           case 32:
636           {
637             /*
638               Convert DirectColor scanline.
639             */
640             for (y=(ssize_t) image->rows-1; y >= 0; y--)
641             {
642               q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
643               if (q == (Quantum *) NULL)
644                 break;
645               for (x=0; x < (ssize_t) image->columns; x++)
646               {
647                 SetPixelBlue(image,ScaleCharToQuantum((unsigned char)
648                   ReadBlobByte(image)),q);
649                 SetPixelGreen(image,ScaleCharToQuantum((unsigned char)
650                   ReadBlobByte(image)),q);
651                 SetPixelRed(image,ScaleCharToQuantum((unsigned char)
652                   ReadBlobByte(image)),q);
653                 if (icon_info.bits_per_pixel == 32)
654                   SetPixelAlpha(image,ScaleCharToQuantum((unsigned char)
655                     ReadBlobByte(image)),q);
656                 q+=GetPixelChannels(image);
657               }
658               if (icon_info.bits_per_pixel == 24)
659                 for (x=0; x < (ssize_t) scanline_pad; x++)
660                   (void) ReadBlobByte(image);
661               if (SyncAuthenticPixels(image,exception) == MagickFalse)
662                 break;
663               if (image->previous == (Image *) NULL)
664                 {
665                   status=SetImageProgress(image,LoadImageTag,image->rows-y-1,
666                     image->rows);
667                   if (status == MagickFalse)
668                     break;
669                 }
670             }
671             break;
672           }
673           default:
674             ThrowReaderException(CorruptImageError,"ImproperImageHeader");
675         }
676         if ((image_info->ping == MagickFalse) &&
677             (icon_info.bits_per_pixel <= 16))
678           (void) SyncImage(image,exception);
679         if (icon_info.bits_per_pixel != 32)
680           {
681             /*
682               Read the ICON alpha mask.
683             */
684             image->storage_class=DirectClass;
685             for (y=(ssize_t) image->rows-1; y >= 0; y--)
686             {
687               q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
688               if (q == (Quantum *) NULL)
689                 break;
690               for (x=0; x < ((ssize_t) image->columns-7); x+=8)
691               {
692                 byte=(size_t) ReadBlobByte(image);
693                 for (bit=0; bit < 8; bit++)
694                 {
695                   SetPixelAlpha(image,(((byte & (0x80 >> bit)) != 0) ?
696                     TransparentAlpha : OpaqueAlpha),q);
697                   q+=GetPixelChannels(image);
698                 }
699               }
700               if ((image->columns % 8) != 0)
701                 {
702                   byte=(size_t) ReadBlobByte(image);
703                   for (bit=0; bit < (image->columns % 8); bit++)
704                   {
705                     SetPixelAlpha(image,(((byte & (0x80 >> bit)) != 0) ?
706                       TransparentAlpha : OpaqueAlpha),q);
707                     q+=GetPixelChannels(image);
708                   }
709                 }
710               if ((image->columns % 32) != 0)
711                 for (x=0; x < (ssize_t) ((32-(image->columns % 32))/8); x++)
712                   (void) ReadBlobByte(image);
713               if (SyncAuthenticPixels(image,exception) == MagickFalse)
714                 break;
715             }
716           }
717         if (EOFBlob(image) != MagickFalse)
718           {
719             ThrowFileException(exception,CorruptImageError,
720               "UnexpectedEndOfFile",image->filename);
721             break;
722           }
723       }
724     /*
725       Proceed to next image.
726     */
727     if (image_info->number_scenes != 0)
728       if (image->scene >= (image_info->scene+image_info->number_scenes-1))
729         break;
730     if (i < (ssize_t) (icon_file.count-1))
731       {
732         /*
733           Allocate next image structure.
734         */
735         AcquireNextImage(image_info,image,exception);
736         if (GetNextImageInList(image) == (Image *) NULL)
737           {
738             image=DestroyImageList(image);
739             return((Image *) NULL);
740           }
741         image=SyncNextImageInList(image);
742         status=SetImageProgress(image,LoadImagesTag,TellBlob(image),
743           GetBlobSize(image));
744         if (status == MagickFalse)
745           break;
746       }
747   }
748   (void) CloseBlob(image);
749   return(GetFirstImageInList(image));
750 }
751 \f
752 /*
753 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
754 %                                                                             %
755 %                                                                             %
756 %                                                                             %
757 %   R e g i s t e r I C O N I m a g e                                         %
758 %                                                                             %
759 %                                                                             %
760 %                                                                             %
761 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
762 %
763 %  RegisterICONImage() adds attributes for the Icon image format to
764 %  the list of supported formats.  The attributes include the image format
765 %  tag, a method to read and/or write the format, whether the format
766 %  supports the saving of more than one frame to the same file or blob,
767 %  whether the format supports native in-memory I/O, and a brief
768 %  description of the format.
769 %
770 %  The format of the RegisterICONImage method is:
771 %
772 %      size_t RegisterICONImage(void)
773 %
774 */
775 ModuleExport size_t RegisterICONImage(void)
776 {
777   MagickInfo
778     *entry;
779
780   entry=AcquireMagickInfo("ICON","CUR","Microsoft icon");
781   entry->decoder=(DecodeImageHandler *) ReadICONImage;
782   entry->encoder=(EncodeImageHandler *) WriteICONImage;
783   entry->flags^=CoderAdjoinFlag;
784   entry->flags|=CoderDecoderSeekableStreamFlag;
785   entry->flags|=CoderEncoderSeekableStreamFlag;
786   (void) RegisterMagickInfo(entry);
787   entry=AcquireMagickInfo("ICON","ICO","Microsoft icon");
788   entry->decoder=(DecodeImageHandler *) ReadICONImage;
789   entry->encoder=(EncodeImageHandler *) WriteICONImage;
790   entry->flags|=CoderDecoderSeekableStreamFlag;
791   entry->flags|=CoderEncoderSeekableStreamFlag;
792   (void) RegisterMagickInfo(entry);
793   entry=AcquireMagickInfo("ICON","ICON","Microsoft icon");
794   entry->decoder=(DecodeImageHandler *) ReadICONImage;
795   entry->encoder=(EncodeImageHandler *) WriteICONImage;
796   entry->flags^=CoderAdjoinFlag;
797   entry->flags|=CoderDecoderSeekableStreamFlag;
798   entry->flags|=CoderEncoderSeekableStreamFlag;
799   (void) RegisterMagickInfo(entry);
800   return(MagickImageCoderSignature);
801 }
802 \f
803 /*
804 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
805 %                                                                             %
806 %                                                                             %
807 %                                                                             %
808 %   U n r e g i s t e r I C O N I m a g e                                     %
809 %                                                                             %
810 %                                                                             %
811 %                                                                             %
812 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
813 %
814 %  UnregisterICONImage() removes format registrations made by the
815 %  ICON module from the list of supported formats.
816 %
817 %  The format of the UnregisterICONImage method is:
818 %
819 %      UnregisterICONImage(void)
820 %
821 */
822 ModuleExport void UnregisterICONImage(void)
823 {
824   (void) UnregisterMagickInfo("CUR");
825   (void) UnregisterMagickInfo("ICO");
826   (void) UnregisterMagickInfo("ICON");
827 }
828 \f
829 /*
830 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
831 %                                                                             %
832 %                                                                             %
833 %                                                                             %
834 %   W r i t e I C O N I m a g e                                               %
835 %                                                                             %
836 %                                                                             %
837 %                                                                             %
838 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
839 %
840 %  WriteICONImage() writes an image in Microsoft Windows bitmap encoded
841 %  image format, version 3 for Windows or (if the image has a matte channel)
842 %  version 4.
843 %
844 %  It encodes any subimage as a compressed PNG image ("BI_PNG)", only when its
845 %  dimensions are 256x256 and image->compression is undefined or is defined as
846 %  ZipCompression.
847 %
848 %  The format of the WriteICONImage method is:
849 %
850 %      MagickBooleanType WriteICONImage(const ImageInfo *image_info,
851 %        Image *image,ExceptionInfo *exception)
852 %
853 %  A description of each parameter follows.
854 %
855 %    o image_info: the image info.
856 %
857 %    o image:  The image.
858 %
859 %    o exception: return any errors or warnings in this structure.
860 %
861 */
862 static MagickBooleanType WriteICONImage(const ImageInfo *image_info,
863   Image *image,ExceptionInfo *exception)
864 {
865   const char
866     *option;
867
868   IconFile
869     icon_file;
870
871   IconInfo
872     icon_info;
873
874   Image
875     *images,
876     *next;
877   
878   MagickBooleanType
879     status;
880
881   MagickOffsetType
882     offset,
883     scene;
884
885   register const Quantum
886     *p;
887
888   register ssize_t
889     i,
890     x;
891
892   register unsigned char
893     *q;
894
895   size_t
896     bytes_per_line,
897     scanline_pad;
898
899   ssize_t
900     y;
901
902   unsigned char
903     bit,
904     byte,
905     *pixels;
906
907   /*
908     Open output image file.
909   */
910   assert(image_info != (const ImageInfo *) NULL);
911   assert(image_info->signature == MagickCoreSignature);
912   assert(image != (Image *) NULL);
913   assert(image->signature == MagickCoreSignature);
914     (void) LogMagickEvent(CoderEvent,GetMagickModule(),"%s",image->filename);
915   assert(exception != (ExceptionInfo *) NULL);
916   assert(exception->signature == MagickCoreSignature);
917   status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
918   if (status == MagickFalse)
919     return(status);
920   images=(Image *) NULL;
921   option=GetImageOption(image_info,"icon:auto-resize");
922   if (option != (const char *) NULL)
923     {
924       images=AutoResizeImage(image,option,&scene,exception);
925       if (images == (Image *) NULL)
926         ThrowWriterException(ImageError,"InvalidDimensions");
927     }
928   else
929     {
930       scene=0;
931       next=image;
932       do
933       {
934         if ((image->columns > 256L) || (image->rows > 256L))
935           ThrowWriterException(ImageError,"WidthOrHeightExceedsLimit");
936         scene++;
937         next=SyncNextImageInList(next);
938       } while ((next != (Image *) NULL) && (image_info->adjoin != MagickFalse));
939     }
940   /*
941     Dump out a ICON header template to be properly initialized later.
942   */
943   (void) WriteBlobLSBShort(image,0);
944   (void) WriteBlobLSBShort(image,1);
945   (void) WriteBlobLSBShort(image,(unsigned char) scene);
946   (void) ResetMagickMemory(&icon_file,0,sizeof(icon_file));
947   (void) ResetMagickMemory(&icon_info,0,sizeof(icon_info));
948   scene=0;
949   next=(images != (Image *) NULL) ? images : image;
950   do
951   {
952     (void) WriteBlobByte(image,icon_file.directory[scene].width);
953     (void) WriteBlobByte(image,icon_file.directory[scene].height);
954     (void) WriteBlobByte(image,icon_file.directory[scene].colors);
955     (void) WriteBlobByte(image,icon_file.directory[scene].reserved);
956     (void) WriteBlobLSBShort(image,icon_file.directory[scene].planes);
957     (void) WriteBlobLSBShort(image,icon_file.directory[scene].bits_per_pixel);
958     (void) WriteBlobLSBLong(image,(unsigned int)
959       icon_file.directory[scene].size);
960     (void) WriteBlobLSBLong(image,(unsigned int)
961       icon_file.directory[scene].offset);
962     scene++;
963     next=SyncNextImageInList(next);
964   } while ((next != (Image *) NULL) && (image_info->adjoin != MagickFalse));
965   scene=0;
966   next=(images != (Image *) NULL) ? images : image;
967   do
968   {
969     if ((next->columns > 255L) && (next->rows > 255L) &&
970         ((next->compression == UndefinedCompression) ||
971         (next->compression == ZipCompression)))
972       {
973         Image
974           *write_image;
975
976         ImageInfo
977           *write_info;
978
979         size_t
980           length;
981
982         unsigned char
983           *png;
984
985         write_image=CloneImage(next,0,0,MagickTrue,exception);
986         if (write_image == (Image *) NULL)
987           {
988             images=DestroyImageList(images);
989             return(MagickFalse);
990           }
991         write_info=CloneImageInfo(image_info);
992         (void) CopyMagickString(write_info->filename,"PNG:",MagickPathExtent);
993
994         /* Don't write any ancillary chunks except for gAMA */
995         (void) SetImageArtifact(write_image,"png:include-chunk","none,gama");
996
997         /* Only write PNG32 formatted PNG (32-bit RGBA), 8 bits per channel */
998         (void) SetImageArtifact(write_image,"png:format","png32");
999
1000         png=(unsigned char *) ImageToBlob(write_info,write_image,&length,
1001           exception);
1002         write_image=DestroyImageList(write_image);
1003         write_info=DestroyImageInfo(write_info);
1004         if (png == (unsigned char *) NULL)
1005           {
1006             images=DestroyImageList(images);
1007             return(MagickFalse);
1008           }
1009         icon_file.directory[scene].width=0;
1010         icon_file.directory[scene].height=0;
1011         icon_file.directory[scene].colors=0;
1012         icon_file.directory[scene].reserved=0;
1013         icon_file.directory[scene].planes=1;
1014         icon_file.directory[scene].bits_per_pixel=32;
1015         icon_file.directory[scene].size=(size_t) length;
1016         icon_file.directory[scene].offset=(size_t) TellBlob(image);
1017         (void) WriteBlob(image,(size_t) length,png);
1018         png=(unsigned char *) RelinquishMagickMemory(png);
1019       }
1020     else
1021       {
1022         /*
1023           Initialize ICON raster file header.
1024         */
1025         (void) TransformImageColorspace(next,sRGBColorspace,exception);
1026         icon_info.file_size=14+12+28;
1027         icon_info.offset_bits=icon_info.file_size;
1028         icon_info.compression=BI_RGB;
1029         if ((next->storage_class != DirectClass) && (next->colors > 256))
1030           (void) SetImageStorageClass(next,DirectClass,exception);
1031         if (next->storage_class == DirectClass)
1032           {
1033             /*
1034               Full color ICON raster.
1035             */
1036             icon_info.number_colors=0;
1037             icon_info.bits_per_pixel=32;
1038             icon_info.compression=(size_t) BI_RGB;
1039           }
1040         else
1041           {
1042             size_t
1043               one;
1044
1045             /*
1046               Colormapped ICON raster.
1047             */
1048             icon_info.bits_per_pixel=8;
1049             if (next->colors <= 256)
1050               icon_info.bits_per_pixel=8;
1051             if (next->colors <= 16)
1052               icon_info.bits_per_pixel=4;
1053             if (next->colors <= 2)
1054               icon_info.bits_per_pixel=1;
1055             one=1;
1056             icon_info.number_colors=one << icon_info.bits_per_pixel;
1057             if (icon_info.number_colors < next->colors)
1058               {
1059                 (void) SetImageStorageClass(next,DirectClass,exception);
1060                 icon_info.number_colors=0;
1061                 icon_info.bits_per_pixel=(unsigned short) 24;
1062                 icon_info.compression=(size_t) BI_RGB;
1063               }
1064             else
1065               {
1066                 size_t
1067                   one;
1068
1069                 one=1;
1070                 icon_info.file_size+=3*(one << icon_info.bits_per_pixel);
1071                 icon_info.offset_bits+=3*(one << icon_info.bits_per_pixel);
1072                 icon_info.file_size+=(one << icon_info.bits_per_pixel);
1073                 icon_info.offset_bits+=(one << icon_info.bits_per_pixel);
1074               }
1075           }
1076         bytes_per_line=(((next->columns*icon_info.bits_per_pixel)+31) &
1077           ~31) >> 3;
1078         icon_info.ba_offset=0;
1079         icon_info.width=(ssize_t) next->columns;
1080         icon_info.height=(ssize_t) next->rows;
1081         icon_info.planes=1;
1082         icon_info.image_size=bytes_per_line*next->rows;
1083         icon_info.size=40;
1084         icon_info.size+=(4*icon_info.number_colors);
1085         icon_info.size+=icon_info.image_size;
1086         icon_info.size+=(((icon_info.width+31) & ~31) >> 3)*icon_info.height;
1087         icon_info.file_size+=icon_info.image_size;
1088         icon_info.x_pixels=0;
1089         icon_info.y_pixels=0;
1090         switch (next->units)
1091         {
1092           case UndefinedResolution:
1093           case PixelsPerInchResolution:
1094           {
1095             icon_info.x_pixels=(size_t) (100.0*next->resolution.x/2.54);
1096             icon_info.y_pixels=(size_t) (100.0*next->resolution.y/2.54);
1097             break;
1098           }
1099           case PixelsPerCentimeterResolution:
1100           {
1101             icon_info.x_pixels=(size_t) (100.0*next->resolution.x);
1102             icon_info.y_pixels=(size_t) (100.0*next->resolution.y);
1103             break;
1104           }
1105         }
1106         icon_info.colors_important=icon_info.number_colors;
1107         /*
1108           Convert MIFF to ICON raster pixels.
1109         */
1110         pixels=(unsigned char *) AcquireQuantumMemory((size_t)
1111           icon_info.image_size,sizeof(*pixels));
1112         if (pixels == (unsigned char *) NULL)
1113           {
1114             images=DestroyImageList(images);
1115             ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
1116           }
1117         (void) ResetMagickMemory(pixels,0,(size_t) icon_info.image_size);
1118         switch (icon_info.bits_per_pixel)
1119         {
1120           case 1:
1121           {
1122             size_t
1123               bit,
1124               byte;
1125
1126             /*
1127               Convert PseudoClass image to a ICON monochrome image.
1128             */
1129             for (y=0; y < (ssize_t) next->rows; y++)
1130             {
1131               p=GetVirtualPixels(next,0,y,next->columns,1,exception);
1132               if (p == (const Quantum *) NULL)
1133                 break;
1134               q=pixels+(next->rows-y-1)*bytes_per_line;
1135               bit=0;
1136               byte=0;
1137               for (x=0; x < (ssize_t) next->columns; x++)
1138               {
1139                 byte<<=1;
1140                 byte|=GetPixelIndex(next,p) != 0 ? 0x01 : 0x00;
1141                 bit++;
1142                 if (bit == 8)
1143                   {
1144                     *q++=(unsigned char) byte;
1145                     bit=0;
1146                     byte=0;
1147                   }
1148                 p+=GetPixelChannels(image);
1149               }
1150               if (bit != 0)
1151                 *q++=(unsigned char) (byte << (8-bit));
1152               if (next->previous == (Image *) NULL)
1153                 {
1154                   status=SetImageProgress(next,SaveImageTag,y,next->rows);
1155                   if (status == MagickFalse)
1156                     break;
1157                 }
1158             }
1159             break;
1160           }
1161           case 4:
1162           {
1163             size_t
1164               nibble,
1165               byte;
1166
1167             /*
1168               Convert PseudoClass image to a ICON monochrome image.
1169             */
1170             for (y=0; y < (ssize_t) next->rows; y++)
1171             {
1172               p=GetVirtualPixels(next,0,y,next->columns,1,exception);
1173               if (p == (const Quantum *) NULL)
1174                 break;
1175               q=pixels+(next->rows-y-1)*bytes_per_line;
1176               nibble=0;
1177               byte=0;
1178               for (x=0; x < (ssize_t) next->columns; x++)
1179               {
1180                 byte<<=4;
1181                 byte|=((size_t) GetPixelIndex(next,p) & 0x0f);
1182                 nibble++;
1183                 if (nibble == 2)
1184                   {
1185                     *q++=(unsigned char) byte;
1186                     nibble=0;
1187                     byte=0;
1188                   }
1189                 p+=GetPixelChannels(image);
1190               }
1191               if (nibble != 0)
1192                 *q++=(unsigned char) (byte << 4);
1193               if (next->previous == (Image *) NULL)
1194                 {
1195                   status=SetImageProgress(next,SaveImageTag,y,next->rows);
1196                   if (status == MagickFalse)
1197                     break;
1198                 }
1199             }
1200             break;
1201           }
1202           case 8:
1203           {
1204             /*
1205               Convert PseudoClass packet to ICON pixel.
1206             */
1207             for (y=0; y < (ssize_t) next->rows; y++)
1208             {
1209               p=GetVirtualPixels(next,0,y,next->columns,1,exception);
1210               if (p == (const Quantum *) NULL)
1211                 break;
1212               q=pixels+(next->rows-y-1)*bytes_per_line;
1213               for (x=0; x < (ssize_t) next->columns; x++)
1214               {
1215                 *q++=(unsigned char) GetPixelIndex(next,p);
1216                 p+=GetPixelChannels(image);
1217               }
1218               if (next->previous == (Image *) NULL)
1219                 {
1220                   status=SetImageProgress(next,SaveImageTag,y,next->rows);
1221                   if (status == MagickFalse)
1222                     break;
1223                 }
1224             }
1225             break;
1226           }
1227           case 24:
1228           case 32:
1229           {
1230             /*
1231               Convert DirectClass packet to ICON BGR888 or BGRA8888 pixel.
1232             */
1233             for (y=0; y < (ssize_t) next->rows; y++)
1234             {
1235               p=GetVirtualPixels(next,0,y,next->columns,1,exception);
1236               if (p == (const Quantum *) NULL)
1237                 break;
1238               q=pixels+(next->rows-y-1)*bytes_per_line;
1239               for (x=0; x < (ssize_t) next->columns; x++)
1240               {
1241                 *q++=ScaleQuantumToChar(GetPixelBlue(next,p));
1242                 *q++=ScaleQuantumToChar(GetPixelGreen(next,p));
1243                 *q++=ScaleQuantumToChar(GetPixelRed(next,p));
1244                 if (next->alpha_trait == UndefinedPixelTrait)
1245                   *q++=ScaleQuantumToChar(QuantumRange);
1246                 else
1247                   *q++=ScaleQuantumToChar(GetPixelAlpha(next,p));
1248                 p+=GetPixelChannels(next);
1249               }
1250               if (icon_info.bits_per_pixel == 24)
1251                 for (x=3L*(ssize_t) next->columns; x < (ssize_t) bytes_per_line; x++)
1252                   *q++=0x00;
1253               if (next->previous == (Image *) NULL)
1254                 {
1255                   status=SetImageProgress(next,SaveImageTag,y,next->rows);
1256                   if (status == MagickFalse)
1257                     break;
1258                 }
1259             }
1260             break;
1261           }
1262         }
1263         /*
1264           Write 40-byte version 3+ bitmap header.
1265         */
1266         icon_file.directory[scene].width=(unsigned char) icon_info.width;
1267         icon_file.directory[scene].height=(unsigned char) icon_info.height;
1268         icon_file.directory[scene].colors=(unsigned char)
1269           icon_info.number_colors;
1270         icon_file.directory[scene].reserved=0;
1271         icon_file.directory[scene].planes=icon_info.planes;
1272         icon_file.directory[scene].bits_per_pixel=icon_info.bits_per_pixel;
1273         icon_file.directory[scene].size=icon_info.size;
1274         icon_file.directory[scene].offset=(size_t) TellBlob(image);
1275         (void) WriteBlobLSBLong(image,(unsigned int) 40);
1276         (void) WriteBlobLSBLong(image,(unsigned int) icon_info.width);
1277         (void) WriteBlobLSBLong(image,(unsigned int) icon_info.height*2);
1278         (void) WriteBlobLSBShort(image,icon_info.planes);
1279         (void) WriteBlobLSBShort(image,icon_info.bits_per_pixel);
1280         (void) WriteBlobLSBLong(image,(unsigned int) icon_info.compression);
1281         (void) WriteBlobLSBLong(image,(unsigned int) icon_info.image_size);
1282         (void) WriteBlobLSBLong(image,(unsigned int) icon_info.x_pixels);
1283         (void) WriteBlobLSBLong(image,(unsigned int) icon_info.y_pixels);
1284         (void) WriteBlobLSBLong(image,(unsigned int) icon_info.number_colors);
1285         (void) WriteBlobLSBLong(image,(unsigned int) icon_info.colors_important);
1286         if (next->storage_class == PseudoClass)
1287           {
1288             unsigned char
1289               *icon_colormap;
1290
1291             /*
1292               Dump colormap to file.
1293             */
1294             icon_colormap=(unsigned char *) AcquireQuantumMemory((size_t)
1295               (1UL << icon_info.bits_per_pixel),4UL*sizeof(*icon_colormap));
1296             if (icon_colormap == (unsigned char *) NULL)
1297               {
1298                 images=DestroyImageList(images);
1299                 ThrowWriterException(ResourceLimitError,
1300                   "MemoryAllocationFailed");
1301               }
1302             q=icon_colormap;
1303             for (i=0; i < (ssize_t) next->colors; i++)
1304             {
1305               *q++=ScaleQuantumToChar(next->colormap[i].blue);
1306               *q++=ScaleQuantumToChar(next->colormap[i].green);
1307               *q++=ScaleQuantumToChar(next->colormap[i].red);
1308               *q++=(unsigned char) 0x0;
1309             }
1310             for ( ; i < (ssize_t) (1UL << icon_info.bits_per_pixel); i++)
1311             {
1312               *q++=(unsigned char) 0x00;
1313               *q++=(unsigned char) 0x00;
1314               *q++=(unsigned char) 0x00;
1315               *q++=(unsigned char) 0x00;
1316             }
1317             (void) WriteBlob(image,(size_t) (4UL*(1UL <<
1318               icon_info.bits_per_pixel)),icon_colormap);
1319             icon_colormap=(unsigned char *) RelinquishMagickMemory(
1320               icon_colormap);
1321           }
1322         (void) WriteBlob(image,(size_t) icon_info.image_size,pixels);
1323         pixels=(unsigned char *) RelinquishMagickMemory(pixels);
1324         /*
1325           Write matte mask.
1326         */
1327         scanline_pad=(((next->columns+31) & ~31)-next->columns) >> 3;
1328         for (y=((ssize_t) next->rows - 1); y >= 0; y--)
1329         {
1330           p=GetVirtualPixels(next,0,y,next->columns,1,exception);
1331           if (p == (const Quantum *) NULL)
1332             break;
1333           bit=0;
1334           byte=0;
1335           for (x=0; x < (ssize_t) next->columns; x++)
1336           {
1337             byte<<=1;
1338             if ((next->alpha_trait != UndefinedPixelTrait) &&
1339                 (GetPixelAlpha(next,p) == (Quantum) TransparentAlpha))
1340               byte|=0x01;
1341             bit++;
1342             if (bit == 8)
1343               {
1344                 (void) WriteBlobByte(image,(unsigned char) byte);
1345                 bit=0;
1346                 byte=0;
1347               }
1348             p+=GetPixelChannels(next);
1349           }
1350           if (bit != 0)
1351             (void) WriteBlobByte(image,(unsigned char) (byte << (8-bit)));
1352           for (i=0; i < (ssize_t) scanline_pad; i++)
1353             (void) WriteBlobByte(image,(unsigned char) 0);
1354         }
1355       }
1356     if (GetNextImageInList(next) == (Image *) NULL)
1357       break;
1358     status=SetImageProgress(next,SaveImagesTag,scene++,
1359       GetImageListLength(next));
1360     if (status == MagickFalse)
1361       break;
1362     next=SyncNextImageInList(next);
1363   } while ((next != (Image *) NULL) && (image_info->adjoin != MagickFalse));
1364   offset=SeekBlob(image,0,SEEK_SET);
1365   (void) offset;
1366   (void) WriteBlobLSBShort(image,0);
1367   (void) WriteBlobLSBShort(image,1);
1368   (void) WriteBlobLSBShort(image,(unsigned short) (scene+1));
1369   scene=0;
1370   next=(images != (Image *) NULL) ? images : image;
1371   do
1372   {
1373     (void) WriteBlobByte(image,icon_file.directory[scene].width);
1374     (void) WriteBlobByte(image,icon_file.directory[scene].height);
1375     (void) WriteBlobByte(image,icon_file.directory[scene].colors);
1376     (void) WriteBlobByte(image,icon_file.directory[scene].reserved);
1377     (void) WriteBlobLSBShort(image,icon_file.directory[scene].planes);
1378     (void) WriteBlobLSBShort(image,icon_file.directory[scene].bits_per_pixel);
1379     (void) WriteBlobLSBLong(image,(unsigned int)
1380       icon_file.directory[scene].size);
1381     (void) WriteBlobLSBLong(image,(unsigned int)
1382       icon_file.directory[scene].offset);
1383     scene++;
1384     next=SyncNextImageInList(next);
1385   } while ((next != (Image *) NULL) && (image_info->adjoin != MagickFalse));
1386   (void) CloseBlob(image);
1387   images=DestroyImageList(images);
1388   return(MagickTrue);
1389 }