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