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