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