Home | History | Annotate | Download | only in coders
      1 /*
      2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
      3 %                                                                             %
      4 %                                                                             %
      5 %                                                                             %
      6 %                             GGGG  IIIII  FFFFF                              %
      7 %                            G        I    F                                  %
      8 %                            G  GG    I    FFF                                %
      9 %                            G   G    I    F                                  %
     10 %                             GGG   IIIII  F                                  %
     11 %                                                                             %
     12 %                                                                             %
     13 %            Read/Write Compuserv Graphics Interchange Format                 %
     14 %                                                                             %
     15 %                              Software Design                                %
     16 %                                   Cristy                                    %
     17 %                                 July 1992                                   %
     18 %                                                                             %
     19 %                                                                             %
     20 %  Copyright 1999-2019 ImageMagick Studio LLC, a non-profit organization      %
     21 %  dedicated to making software imaging solutions freely available.           %
     22 %                                                                             %
     23 %  You may not use this file except in compliance with the License.  You may  %
     24 %  obtain a copy of the License at                                            %
     25 %                                                                             %
     26 %    https://imagemagick.org/script/license.php                               %
     27 %                                                                             %
     28 %  Unless required by applicable law or agreed to in writing, software        %
     29 %  distributed under the License is distributed on an "AS IS" BASIS,          %
     30 %  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
     31 %  See the License for the specific language governing permissions and        %
     32 %  limitations under the License.                                             %
     33 %                                                                             %
     34 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
     35 %
     36 %
     37 */
     38 
     39 /*
     41   Include declarations.
     42 */
     43 #include "MagickCore/studio.h"
     44 #include "MagickCore/attribute.h"
     45 #include "MagickCore/blob.h"
     46 #include "MagickCore/blob-private.h"
     47 #include "MagickCore/cache.h"
     48 #include "MagickCore/color.h"
     49 #include "MagickCore/color-private.h"
     50 #include "MagickCore/colormap.h"
     51 #include "MagickCore/colormap-private.h"
     52 #include "MagickCore/colorspace.h"
     53 #include "MagickCore/colorspace-private.h"
     54 #include "MagickCore/exception.h"
     55 #include "MagickCore/exception-private.h"
     56 #include "MagickCore/image.h"
     57 #include "MagickCore/image-private.h"
     58 #include "MagickCore/list.h"
     59 #include "MagickCore/profile.h"
     60 #include "MagickCore/magick.h"
     61 #include "MagickCore/memory_.h"
     62 #include "MagickCore/monitor.h"
     63 #include "MagickCore/monitor-private.h"
     64 #include "MagickCore/option.h"
     65 #include "MagickCore/pixel.h"
     66 #include "MagickCore/pixel-accessor.h"
     67 #include "MagickCore/property.h"
     68 #include "MagickCore/quantize.h"
     69 #include "MagickCore/quantum-private.h"
     70 #include "MagickCore/resource_.h"
     71 #include "MagickCore/static.h"
     72 #include "MagickCore/string_.h"
     73 #include "MagickCore/string-private.h"
     74 #include "MagickCore/module.h"
     75 
     76 /*
     78   Define declarations.
     79 */
     80 #define MaximumLZWBits  12
     81 #define MaximumLZWCode  (1UL << MaximumLZWBits)
     82 
     83 /*
     85   Typdef declarations.
     86 */
     87 typedef struct _LZWCodeInfo
     88 {
     89   unsigned char
     90     buffer[280];
     91 
     92   size_t
     93     count,
     94     bit;
     95 
     96   MagickBooleanType
     97     eof;
     98 } LZWCodeInfo;
     99 
    100 typedef struct _LZWStack
    101 {
    102   size_t
    103     *codes,
    104     *index,
    105     *top;
    106 } LZWStack;
    107 
    108 typedef struct _LZWInfo
    109 {
    110   Image
    111     *image;
    112 
    113   LZWStack
    114     *stack;
    115 
    116   MagickBooleanType
    117     genesis;
    118 
    119   size_t
    120     data_size,
    121     maximum_data_value,
    122     clear_code,
    123     end_code,
    124     bits,
    125     first_code,
    126     last_code,
    127     maximum_code,
    128     slot,
    129     *table[2];
    130 
    131   LZWCodeInfo
    132     code_info;
    133 } LZWInfo;
    134 
    135 /*
    137   Forward declarations.
    138 */
    139 static inline int
    140   GetNextLZWCode(LZWInfo *,const size_t);
    141 
    142 static MagickBooleanType
    143   WriteGIFImage(const ImageInfo *,Image *,ExceptionInfo *);
    144 
    145 static ssize_t
    146   ReadBlobBlock(Image *,unsigned char *);
    147 
    148 /*
    150 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    151 %                                                                             %
    152 %                                                                             %
    153 %                                                                             %
    154 %   D e c o d e I m a g e                                                     %
    155 %                                                                             %
    156 %                                                                             %
    157 %                                                                             %
    158 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    159 %
    160 %  DecodeImage uncompresses an image via GIF-coding.
    161 %
    162 %  The format of the DecodeImage method is:
    163 %
    164 %      MagickBooleanType DecodeImage(Image *image,const ssize_t opacity)
    165 %
    166 %  A description of each parameter follows:
    167 %
    168 %    o image: the address of a structure of type Image.
    169 %
    170 %    o opacity:  The colormap index associated with the transparent color.
    171 %
    172 */
    173 
    174 static LZWInfo *RelinquishLZWInfo(LZWInfo *lzw_info)
    175 {
    176   if (lzw_info->table[0] != (size_t *) NULL)
    177     lzw_info->table[0]=(size_t *) RelinquishMagickMemory(
    178       lzw_info->table[0]);
    179   if (lzw_info->table[1] != (size_t *) NULL)
    180     lzw_info->table[1]=(size_t *) RelinquishMagickMemory(
    181       lzw_info->table[1]);
    182   if (lzw_info->stack != (LZWStack *) NULL)
    183     {
    184       if (lzw_info->stack->codes != (size_t *) NULL)
    185         lzw_info->stack->codes=(size_t *) RelinquishMagickMemory(
    186           lzw_info->stack->codes);
    187       lzw_info->stack=(LZWStack *) RelinquishMagickMemory(lzw_info->stack);
    188     }
    189   lzw_info=(LZWInfo *) RelinquishMagickMemory(lzw_info);
    190   return((LZWInfo *) NULL);
    191 }
    192 
    193 static inline void ResetLZWInfo(LZWInfo *lzw_info)
    194 {
    195   size_t
    196     one;
    197 
    198   lzw_info->bits=lzw_info->data_size+1;
    199   one=1;
    200   lzw_info->maximum_code=one << lzw_info->bits;
    201   lzw_info->slot=lzw_info->maximum_data_value+3;
    202   lzw_info->genesis=MagickTrue;
    203 }
    204 
    205 static LZWInfo *AcquireLZWInfo(Image *image,const size_t data_size)
    206 {
    207   LZWInfo
    208     *lzw_info;
    209 
    210   register ssize_t
    211     i;
    212 
    213   size_t
    214     one;
    215 
    216   lzw_info=(LZWInfo *) AcquireMagickMemory(sizeof(*lzw_info));
    217   if (lzw_info == (LZWInfo *) NULL)
    218     return((LZWInfo *) NULL);
    219   (void) memset(lzw_info,0,sizeof(*lzw_info));
    220   lzw_info->image=image;
    221   lzw_info->data_size=data_size;
    222   one=1;
    223   lzw_info->maximum_data_value=(one << data_size)-1;
    224   lzw_info->clear_code=lzw_info->maximum_data_value+1;
    225   lzw_info->end_code=lzw_info->maximum_data_value+2;
    226   lzw_info->table[0]=(size_t *) AcquireQuantumMemory(MaximumLZWCode,
    227     sizeof(**lzw_info->table));
    228   lzw_info->table[1]=(size_t *) AcquireQuantumMemory(MaximumLZWCode,
    229     sizeof(**lzw_info->table));
    230   if ((lzw_info->table[0] == (size_t *) NULL) ||
    231       (lzw_info->table[1] == (size_t *) NULL))
    232     {
    233       lzw_info=RelinquishLZWInfo(lzw_info);
    234       return((LZWInfo *) NULL);
    235     }
    236   (void) memset(lzw_info->table[0],0,MaximumLZWCode*
    237     sizeof(**lzw_info->table));
    238   (void) memset(lzw_info->table[1],0,MaximumLZWCode*
    239     sizeof(**lzw_info->table));
    240   for (i=0; i <= (ssize_t) lzw_info->maximum_data_value; i++)
    241   {
    242     lzw_info->table[0][i]=0;
    243     lzw_info->table[1][i]=(size_t) i;
    244   }
    245   ResetLZWInfo(lzw_info);
    246   lzw_info->code_info.buffer[0]='\0';
    247   lzw_info->code_info.buffer[1]='\0';
    248   lzw_info->code_info.count=2;
    249   lzw_info->code_info.bit=8*lzw_info->code_info.count;
    250   lzw_info->code_info.eof=MagickFalse;
    251   lzw_info->genesis=MagickTrue;
    252   lzw_info->stack=(LZWStack *) AcquireMagickMemory(sizeof(*lzw_info->stack));
    253   if (lzw_info->stack == (LZWStack *) NULL)
    254     {
    255       lzw_info=RelinquishLZWInfo(lzw_info);
    256       return((LZWInfo *) NULL);
    257     }
    258   lzw_info->stack->codes=(size_t *) AcquireQuantumMemory(2UL*
    259     MaximumLZWCode,sizeof(*lzw_info->stack->codes));
    260   if (lzw_info->stack->codes == (size_t *) NULL)
    261     {
    262       lzw_info=RelinquishLZWInfo(lzw_info);
    263       return((LZWInfo *) NULL);
    264     }
    265   lzw_info->stack->index=lzw_info->stack->codes;
    266   lzw_info->stack->top=lzw_info->stack->codes+2*MaximumLZWCode;
    267   return(lzw_info);
    268 }
    269 
    270 static inline int GetNextLZWCode(LZWInfo *lzw_info,const size_t bits)
    271 {
    272   int
    273     code;
    274 
    275   register ssize_t
    276     i;
    277 
    278   size_t
    279     one;
    280 
    281   while (((lzw_info->code_info.bit+bits) > (8*lzw_info->code_info.count)) &&
    282          (lzw_info->code_info.eof == MagickFalse))
    283   {
    284     ssize_t
    285       count;
    286 
    287     lzw_info->code_info.buffer[0]=lzw_info->code_info.buffer[
    288       lzw_info->code_info.count-2];
    289     lzw_info->code_info.buffer[1]=lzw_info->code_info.buffer[
    290       lzw_info->code_info.count-1];
    291     lzw_info->code_info.bit-=8*(lzw_info->code_info.count-2);
    292     lzw_info->code_info.count=2;
    293     count=ReadBlobBlock(lzw_info->image,&lzw_info->code_info.buffer[
    294       lzw_info->code_info.count]);
    295     if (count > 0)
    296       lzw_info->code_info.count+=count;
    297     else
    298       lzw_info->code_info.eof=MagickTrue;
    299   }
    300   if ((lzw_info->code_info.bit+bits) > (8*lzw_info->code_info.count))
    301     return(-1);
    302   code=0;
    303   one=1;
    304   for (i=0; i < (ssize_t) bits; i++)
    305   {
    306     code|=((lzw_info->code_info.buffer[lzw_info->code_info.bit/8] &
    307       (one << (lzw_info->code_info.bit % 8))) != 0) << i;
    308     lzw_info->code_info.bit++;
    309   }
    310   return(code);
    311 }
    312 
    313 static inline int PopLZWStack(LZWStack *stack_info)
    314 {
    315   if (stack_info->index <= stack_info->codes)
    316     return(-1);
    317   stack_info->index--;
    318   return((int) *stack_info->index);
    319 }
    320 
    321 static inline void PushLZWStack(LZWStack *stack_info,const size_t value)
    322 {
    323   if (stack_info->index >= stack_info->top)
    324     return;
    325   *stack_info->index=value;
    326   stack_info->index++;
    327 }
    328 
    329 static int ReadBlobLZWByte(LZWInfo *lzw_info)
    330 {
    331   int
    332     code;
    333 
    334   size_t
    335     one,
    336     value;
    337 
    338   ssize_t
    339     count;
    340 
    341   if (lzw_info->stack->index != lzw_info->stack->codes)
    342     return(PopLZWStack(lzw_info->stack));
    343   if (lzw_info->genesis != MagickFalse)
    344     {
    345       lzw_info->genesis=MagickFalse;
    346       do
    347       {
    348         lzw_info->first_code=(size_t) GetNextLZWCode(lzw_info,lzw_info->bits);
    349         lzw_info->last_code=lzw_info->first_code;
    350       } while (lzw_info->first_code == lzw_info->clear_code);
    351       return((int) lzw_info->first_code);
    352     }
    353   code=GetNextLZWCode(lzw_info,lzw_info->bits);
    354   if (code < 0)
    355     return(code);
    356   if ((size_t) code == lzw_info->clear_code)
    357     {
    358       ResetLZWInfo(lzw_info);
    359       return(ReadBlobLZWByte(lzw_info));
    360     }
    361   if ((size_t) code == lzw_info->end_code)
    362     return(-1);
    363   if ((size_t) code < lzw_info->slot)
    364     value=(size_t) code;
    365   else
    366     {
    367       PushLZWStack(lzw_info->stack,lzw_info->first_code);
    368       value=lzw_info->last_code;
    369     }
    370   count=0;
    371   while (value > lzw_info->maximum_data_value)
    372   {
    373     if ((size_t) count > MaximumLZWCode)
    374       return(-1);
    375     count++;
    376     if ((size_t) value > MaximumLZWCode)
    377       return(-1);
    378     PushLZWStack(lzw_info->stack,lzw_info->table[1][value]);
    379     value=lzw_info->table[0][value];
    380   }
    381   lzw_info->first_code=lzw_info->table[1][value];
    382   PushLZWStack(lzw_info->stack,lzw_info->first_code);
    383   one=1;
    384   if (lzw_info->slot < MaximumLZWCode)
    385     {
    386       lzw_info->table[0][lzw_info->slot]=lzw_info->last_code;
    387       lzw_info->table[1][lzw_info->slot]=lzw_info->first_code;
    388       lzw_info->slot++;
    389       if ((lzw_info->slot >= lzw_info->maximum_code) &&
    390           (lzw_info->bits < MaximumLZWBits))
    391         {
    392           lzw_info->bits++;
    393           lzw_info->maximum_code=one << lzw_info->bits;
    394         }
    395     }
    396   lzw_info->last_code=(size_t) code;
    397   return(PopLZWStack(lzw_info->stack));
    398 }
    399 
    400 static MagickBooleanType DecodeImage(Image *image,const ssize_t opacity,
    401   ExceptionInfo *exception)
    402 {
    403   int
    404     c;
    405 
    406   LZWInfo
    407     *lzw_info;
    408 
    409   size_t
    410     pass;
    411 
    412   ssize_t
    413     index,
    414     offset,
    415     y;
    416 
    417   unsigned char
    418     data_size;
    419 
    420   /*
    421     Allocate decoder tables.
    422   */
    423   assert(image != (Image *) NULL);
    424   assert(image->signature == MagickCoreSignature);
    425   if (image->debug != MagickFalse)
    426     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
    427   data_size=(unsigned char) ReadBlobByte(image);
    428   if (data_size > MaximumLZWBits)
    429     ThrowBinaryException(CorruptImageError,"CorruptImage",image->filename);
    430   lzw_info=AcquireLZWInfo(image,data_size);
    431   if (lzw_info == (LZWInfo *) NULL)
    432     ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
    433       image->filename);
    434   pass=0;
    435   offset=0;
    436   for (y=0; y < (ssize_t) image->rows; y++)
    437   {
    438     register ssize_t
    439       x;
    440 
    441     register Quantum
    442       *magick_restrict q;
    443 
    444     q=QueueAuthenticPixels(image,0,offset,image->columns,1,exception);
    445     if (q == (Quantum *) NULL)
    446       break;
    447     for (x=0; x < (ssize_t) image->columns; )
    448     {
    449       c=ReadBlobLZWByte(lzw_info);
    450       if (c < 0)
    451         break;
    452       index=ConstrainColormapIndex(image,(ssize_t) c,exception);
    453       SetPixelIndex(image,(Quantum) index,q);
    454       SetPixelViaPixelInfo(image,image->colormap+index,q);
    455       SetPixelAlpha(image,index == opacity ? TransparentAlpha : OpaqueAlpha,q);
    456       x++;
    457       q+=GetPixelChannels(image);
    458     }
    459     if (SyncAuthenticPixels(image,exception) == MagickFalse)
    460       break;
    461     if (x < (ssize_t) image->columns)
    462       break;
    463     if (image->interlace == NoInterlace)
    464       offset++;
    465     else
    466       {
    467         switch (pass)
    468         {
    469           case 0:
    470           default:
    471           {
    472             offset+=8;
    473             break;
    474           }
    475           case 1:
    476           {
    477             offset+=8;
    478             break;
    479           }
    480           case 2:
    481           {
    482             offset+=4;
    483             break;
    484           }
    485           case 3:
    486           {
    487             offset+=2;
    488             break;
    489           }
    490         }
    491       if ((pass == 0) && (offset >= (ssize_t) image->rows))
    492         {
    493           pass++;
    494           offset=4;
    495         }
    496       if ((pass == 1) && (offset >= (ssize_t) image->rows))
    497         {
    498           pass++;
    499           offset=2;
    500         }
    501       if ((pass == 2) && (offset >= (ssize_t) image->rows))
    502         {
    503           pass++;
    504           offset=1;
    505         }
    506     }
    507   }
    508   lzw_info=RelinquishLZWInfo(lzw_info);
    509   if (y < (ssize_t) image->rows)
    510     ThrowBinaryException(CorruptImageError,"CorruptImage",image->filename);
    511   return(MagickTrue);
    512 }
    513 
    514 /*
    516 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    517 %                                                                             %
    518 %                                                                             %
    519 %                                                                             %
    520 %   E n c o d e I m a g e                                                     %
    521 %                                                                             %
    522 %                                                                             %
    523 %                                                                             %
    524 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    525 %
    526 %  EncodeImage compresses an image via GIF-coding.
    527 %
    528 %  The format of the EncodeImage method is:
    529 %
    530 %      MagickBooleanType EncodeImage(const ImageInfo *image_info,Image *image,
    531 %        const size_t data_size)
    532 %
    533 %  A description of each parameter follows:
    534 %
    535 %    o image_info: the image info.
    536 %
    537 %    o image: the address of a structure of type Image.
    538 %
    539 %    o data_size:  The number of bits in the compressed packet.
    540 %
    541 */
    542 static MagickBooleanType EncodeImage(const ImageInfo *image_info,Image *image,
    543   const size_t data_size,ExceptionInfo *exception)
    544 {
    545 #define MaxCode(number_bits)  ((one << (number_bits))-1)
    546 #define MaxHashTable  5003
    547 #define MaxGIFBits  12UL
    548 #define MaxGIFTable  (1UL << MaxGIFBits)
    549 #define GIFOutputCode(code) \
    550 { \
    551   /*  \
    552     Emit a code. \
    553   */ \
    554   if (bits > 0) \
    555     datum|=(size_t) (code) << bits; \
    556   else \
    557     datum=(size_t) (code); \
    558   bits+=number_bits; \
    559   while (bits >= 8) \
    560   { \
    561     /*  \
    562       Add a character to current packet. \
    563     */ \
    564     packet[length++]=(unsigned char) (datum & 0xff); \
    565     if (length >= 254) \
    566       { \
    567         (void) WriteBlobByte(image,(unsigned char) length); \
    568         (void) WriteBlob(image,length,packet); \
    569         length=0; \
    570       } \
    571     datum>>=8; \
    572     bits-=8; \
    573   } \
    574   if (free_code > max_code)  \
    575     { \
    576       number_bits++; \
    577       if (number_bits == MaxGIFBits) \
    578         max_code=MaxGIFTable; \
    579       else \
    580         max_code=MaxCode(number_bits); \
    581     } \
    582 }
    583 
    584   Quantum
    585     index;
    586 
    587   short
    588     *hash_code,
    589     *hash_prefix,
    590     waiting_code;
    591 
    592   size_t
    593     bits,
    594     clear_code,
    595     datum,
    596     end_of_information_code,
    597     free_code,
    598     length,
    599     max_code,
    600     next_pixel,
    601     number_bits,
    602     one,
    603     pass;
    604 
    605   ssize_t
    606     displacement,
    607     offset,
    608     k,
    609     y;
    610 
    611   unsigned char
    612     *packet,
    613     *hash_suffix;
    614 
    615   /*
    616     Allocate encoder tables.
    617   */
    618   assert(image != (Image *) NULL);
    619   one=1;
    620   packet=(unsigned char *) AcquireQuantumMemory(256,sizeof(*packet));
    621   hash_code=(short *) AcquireQuantumMemory(MaxHashTable,sizeof(*hash_code));
    622   hash_prefix=(short *) AcquireQuantumMemory(MaxHashTable,sizeof(*hash_prefix));
    623   hash_suffix=(unsigned char *) AcquireQuantumMemory(MaxHashTable,
    624     sizeof(*hash_suffix));
    625   if ((packet == (unsigned char *) NULL) || (hash_code == (short *) NULL) ||
    626       (hash_prefix == (short *) NULL) ||
    627       (hash_suffix == (unsigned char *) NULL))
    628     {
    629       if (packet != (unsigned char *) NULL)
    630         packet=(unsigned char *) RelinquishMagickMemory(packet);
    631       if (hash_code != (short *) NULL)
    632         hash_code=(short *) RelinquishMagickMemory(hash_code);
    633       if (hash_prefix != (short *) NULL)
    634         hash_prefix=(short *) RelinquishMagickMemory(hash_prefix);
    635       if (hash_suffix != (unsigned char *) NULL)
    636         hash_suffix=(unsigned char *) RelinquishMagickMemory(hash_suffix);
    637       return(MagickFalse);
    638     }
    639   /*
    640     Initialize GIF encoder.
    641   */
    642   (void) memset(packet,0,256*sizeof(*packet));
    643   (void) memset(hash_code,0,MaxHashTable*sizeof(*hash_code));
    644   (void) memset(hash_prefix,0,MaxHashTable*sizeof(*hash_prefix));
    645   (void) memset(hash_suffix,0,MaxHashTable*sizeof(*hash_suffix));
    646   number_bits=data_size;
    647   max_code=MaxCode(number_bits);
    648   clear_code=((short) one << (data_size-1));
    649   end_of_information_code=clear_code+1;
    650   free_code=clear_code+2;
    651   length=0;
    652   datum=0;
    653   bits=0;
    654   GIFOutputCode(clear_code);
    655   /*
    656     Encode pixels.
    657   */
    658   offset=0;
    659   pass=0;
    660   waiting_code=0;
    661   for (y=0; y < (ssize_t) image->rows; y++)
    662   {
    663     register const Quantum
    664       *magick_restrict p;
    665 
    666     register ssize_t
    667       x;
    668 
    669     p=GetVirtualPixels(image,0,offset,image->columns,1,exception);
    670     if (p == (const Quantum *) NULL)
    671       break;
    672     if (y == 0)
    673       {
    674         waiting_code=(short) GetPixelIndex(image,p);
    675         p+=GetPixelChannels(image);
    676       }
    677     for (x=(ssize_t) (y == 0 ? 1 : 0); x < (ssize_t) image->columns; x++)
    678     {
    679       /*
    680         Probe hash table.
    681       */
    682       index=(Quantum) ((size_t) GetPixelIndex(image,p) & 0xff);
    683       p+=GetPixelChannels(image);
    684       k=(ssize_t) (((size_t) index << (MaxGIFBits-8))+waiting_code);
    685       if (k >= MaxHashTable)
    686         k-=MaxHashTable;
    687       next_pixel=MagickFalse;
    688       displacement=1;
    689       if (hash_code[k] > 0)
    690         {
    691           if ((hash_prefix[k] == waiting_code) &&
    692               (hash_suffix[k] == (unsigned char) index))
    693             {
    694               waiting_code=hash_code[k];
    695               continue;
    696             }
    697           if (k != 0)
    698             displacement=MaxHashTable-k;
    699           for ( ; ; )
    700           {
    701             k-=displacement;
    702             if (k < 0)
    703               k+=MaxHashTable;
    704             if (hash_code[k] == 0)
    705               break;
    706             if ((hash_prefix[k] == waiting_code) &&
    707                 (hash_suffix[k] == (unsigned char) index))
    708               {
    709                 waiting_code=hash_code[k];
    710                 next_pixel=MagickTrue;
    711                 break;
    712               }
    713           }
    714           if (next_pixel != MagickFalse)
    715             continue;
    716         }
    717       GIFOutputCode(waiting_code);
    718       if (free_code < MaxGIFTable)
    719         {
    720           hash_code[k]=(short) free_code++;
    721           hash_prefix[k]=waiting_code;
    722           hash_suffix[k]=(unsigned char) index;
    723         }
    724       else
    725         {
    726           /*
    727             Fill the hash table with empty entries.
    728           */
    729           for (k=0; k < MaxHashTable; k++)
    730             hash_code[k]=0;
    731           /*
    732             Reset compressor and issue a clear code.
    733           */
    734           free_code=clear_code+2;
    735           GIFOutputCode(clear_code);
    736           number_bits=data_size;
    737           max_code=MaxCode(number_bits);
    738         }
    739       waiting_code=(short) index;
    740     }
    741     if (image_info->interlace == NoInterlace)
    742       offset++;
    743     else
    744       switch (pass)
    745       {
    746         case 0:
    747         default:
    748         {
    749           offset+=8;
    750           if (offset >= (ssize_t) image->rows)
    751             {
    752               pass++;
    753               offset=4;
    754             }
    755           break;
    756         }
    757         case 1:
    758         {
    759           offset+=8;
    760           if (offset >= (ssize_t) image->rows)
    761             {
    762               pass++;
    763               offset=2;
    764             }
    765           break;
    766         }
    767         case 2:
    768         {
    769           offset+=4;
    770           if (offset >= (ssize_t) image->rows)
    771             {
    772               pass++;
    773               offset=1;
    774             }
    775           break;
    776         }
    777         case 3:
    778         {
    779           offset+=2;
    780           break;
    781         }
    782       }
    783   }
    784   /*
    785     Flush out the buffered code.
    786   */
    787   GIFOutputCode(waiting_code);
    788   GIFOutputCode(end_of_information_code);
    789   if (bits > 0)
    790     {
    791       /*
    792         Add a character to current packet.
    793       */
    794       packet[length++]=(unsigned char) (datum & 0xff);
    795       if (length >= 254)
    796         {
    797           (void) WriteBlobByte(image,(unsigned char) length);
    798           (void) WriteBlob(image,length,packet);
    799           length=0;
    800         }
    801     }
    802   /*
    803     Flush accumulated data.
    804   */
    805   if (length > 0)
    806     {
    807       (void) WriteBlobByte(image,(unsigned char) length);
    808       (void) WriteBlob(image,length,packet);
    809     }
    810   /*
    811     Free encoder memory.
    812   */
    813   hash_suffix=(unsigned char *) RelinquishMagickMemory(hash_suffix);
    814   hash_prefix=(short *) RelinquishMagickMemory(hash_prefix);
    815   hash_code=(short *) RelinquishMagickMemory(hash_code);
    816   packet=(unsigned char *) RelinquishMagickMemory(packet);
    817   return(MagickTrue);
    818 }
    819 
    820 /*
    822 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    823 %                                                                             %
    824 %                                                                             %
    825 %                                                                             %
    826 %   I s G I F                                                                 %
    827 %                                                                             %
    828 %                                                                             %
    829 %                                                                             %
    830 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    831 %
    832 %  IsGIF() returns MagickTrue if the image format type, identified by the
    833 %  magick string, is GIF.
    834 %
    835 %  The format of the IsGIF method is:
    836 %
    837 %      MagickBooleanType IsGIF(const unsigned char *magick,const size_t length)
    838 %
    839 %  A description of each parameter follows:
    840 %
    841 %    o magick: compare image format pattern against these bytes.
    842 %
    843 %    o length: Specifies the length of the magick string.
    844 %
    845 */
    846 static MagickBooleanType IsGIF(const unsigned char *magick,const size_t length)
    847 {
    848   if (length < 4)
    849     return(MagickFalse);
    850   if (LocaleNCompare((char *) magick,"GIF8",4) == 0)
    851     return(MagickTrue);
    852   return(MagickFalse);
    853 }
    854 
    855 /*
    857 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    858 %                                                                             %
    859 %                                                                             %
    860 %                                                                             %
    861 +  R e a d B l o b B l o c k                                                  %
    862 %                                                                             %
    863 %                                                                             %
    864 %                                                                             %
    865 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    866 %
    867 %  ReadBlobBlock() reads data from the image file and returns it.  The
    868 %  amount of data is determined by first reading a count byte.  The number
    869 %  of bytes read is returned.
    870 %
    871 %  The format of the ReadBlobBlock method is:
    872 %
    873 %      ssize_t ReadBlobBlock(Image *image,unsigned char *data)
    874 %
    875 %  A description of each parameter follows:
    876 %
    877 %    o image: the image.
    878 %
    879 %    o data:  Specifies an area to place the information requested from
    880 %      the file.
    881 %
    882 */
    883 static ssize_t ReadBlobBlock(Image *image,unsigned char *data)
    884 {
    885   ssize_t
    886     count;
    887 
    888   unsigned char
    889     block_count;
    890 
    891   assert(image != (Image *) NULL);
    892   assert(image->signature == MagickCoreSignature);
    893   assert(data != (unsigned char *) NULL);
    894   count=ReadBlob(image,1,&block_count);
    895   if (count != 1)
    896     return(0);
    897   count=ReadBlob(image,(size_t) block_count,data);
    898   if (count != (ssize_t) block_count)
    899     return(0);
    900   return(count);
    901 }
    902 
    903 /*
    905 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    906 %                                                                             %
    907 %                                                                             %
    908 %                                                                             %
    909 %   R e a d G I F I m a g e                                                   %
    910 %                                                                             %
    911 %                                                                             %
    912 %                                                                             %
    913 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    914 %
    915 %  ReadGIFImage() reads a Compuserve Graphics image file and returns it.
    916 %  It allocates the memory necessary for the new Image structure and returns a
    917 %  pointer to the new image.
    918 %
    919 %  The format of the ReadGIFImage method is:
    920 %
    921 %      Image *ReadGIFImage(const ImageInfo *image_info,ExceptionInfo *exception)
    922 %
    923 %  A description of each parameter follows:
    924 %
    925 %    o image_info: the image info.
    926 %
    927 %    o exception: return any errors or warnings in this structure.
    928 %
    929 */
    930 
    931 static void *DestroyGIFProfile(void *profile)
    932 {
    933   return((void *) DestroyStringInfo((StringInfo *) profile));
    934 }
    935 
    936 static MagickBooleanType PingGIFImage(Image *image,ExceptionInfo *exception)
    937 {
    938   unsigned char
    939     buffer[256],
    940     length,
    941     data_size;
    942 
    943   assert(image != (Image *) NULL);
    944   assert(image->signature == MagickCoreSignature);
    945   if (image->debug != MagickFalse)
    946     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
    947   if (ReadBlob(image,1,&data_size) != 1)
    948     ThrowBinaryException(CorruptImageError,"CorruptImage",image->filename);
    949   if (data_size > MaximumLZWBits)
    950     ThrowBinaryException(CorruptImageError,"CorruptImage",image->filename);
    951   if (ReadBlob(image,1,&length) != 1)
    952     ThrowBinaryException(CorruptImageError,"CorruptImage",image->filename);
    953   while (length != 0)
    954   {
    955     if (ReadBlob(image,length,buffer) != (ssize_t) length)
    956       ThrowBinaryException(CorruptImageError,"CorruptImage",image->filename);
    957     if (ReadBlob(image,1,&length) != 1)
    958       ThrowBinaryException(CorruptImageError,"CorruptImage",image->filename);
    959   }
    960   return(MagickTrue);
    961 }
    962 
    963 static Image *ReadGIFImage(const ImageInfo *image_info,ExceptionInfo *exception)
    964 {
    965 #define BitSet(byte,bit)  (((byte) & (bit)) == (bit))
    966 #define LSBFirstOrder(x,y)  (((y) << 8) | (x))
    967 #define ThrowGIFException(exception,message) \
    968 { \
    969   if (profiles != (LinkedListInfo *) NULL) \
    970     profiles=DestroyLinkedList(profiles,DestroyGIFProfile); \
    971   if (global_colormap != (unsigned char *) NULL) \
    972     global_colormap=(unsigned char *) RelinquishMagickMemory(global_colormap); \
    973   if (meta_image != (Image *) NULL) \
    974     meta_image=DestroyImage(meta_image); \
    975   ThrowReaderException((exception),(message)); \
    976 }
    977 
    978   Image
    979     *image,
    980     *meta_image;
    981 
    982   LinkedListInfo
    983     *profiles;
    984 
    985   MagickBooleanType
    986     status;
    987 
    988   register ssize_t
    989     i;
    990 
    991   register unsigned char
    992     *p;
    993 
    994   size_t
    995     duration,
    996     global_colors,
    997     image_count,
    998     local_colors,
    999     one;
   1000 
   1001   ssize_t
   1002     count,
   1003     opacity;
   1004 
   1005   unsigned char
   1006     background,
   1007     buffer[257],
   1008     c,
   1009     flag,
   1010     *global_colormap;
   1011 
   1012   /*
   1013     Open image file.
   1014   */
   1015   assert(image_info != (const ImageInfo *) NULL);
   1016   assert(image_info->signature == MagickCoreSignature);
   1017   if (image_info->debug != MagickFalse)
   1018     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
   1019       image_info->filename);
   1020   assert(exception != (ExceptionInfo *) NULL);
   1021   assert(exception->signature == MagickCoreSignature);
   1022   image=AcquireImage(image_info,exception);
   1023   status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
   1024   if (status == MagickFalse)
   1025     {
   1026       image=DestroyImageList(image);
   1027       return((Image *) NULL);
   1028     }
   1029   /*
   1030     Determine if this a GIF file.
   1031   */
   1032   count=ReadBlob(image,6,buffer);
   1033   if ((count != 6) || ((LocaleNCompare((char *) buffer,"GIF87",5) != 0) &&
   1034       (LocaleNCompare((char *) buffer,"GIF89",5) != 0)))
   1035     ThrowReaderException(CorruptImageError,"ImproperImageHeader");
   1036   (void) memset(buffer,0,sizeof(buffer));
   1037   meta_image=AcquireImage(image_info,exception);  /* metadata container */
   1038   meta_image->page.width=ReadBlobLSBShort(image);
   1039   meta_image->page.height=ReadBlobLSBShort(image);
   1040   flag=(unsigned char) ReadBlobByte(image);
   1041   profiles=(LinkedListInfo *) NULL;
   1042   background=(unsigned char) ReadBlobByte(image);
   1043   c=(unsigned char) ReadBlobByte(image);  /* reserved */
   1044   one=1;
   1045   global_colors=one << (((size_t) flag & 0x07)+1);
   1046   global_colormap=(unsigned char *) AcquireQuantumMemory((size_t)
   1047     MagickMax(global_colors,256),3UL*sizeof(*global_colormap));
   1048   if (global_colormap == (unsigned char *) NULL)
   1049     ThrowGIFException(ResourceLimitError,"MemoryAllocationFailed");
   1050   (void) memset(global_colormap,0,3*MagickMax(global_colors,256)*
   1051     sizeof(*global_colormap));
   1052   if (BitSet((int) flag,0x80) != 0)
   1053     {
   1054       count=ReadBlob(image,(size_t) (3*global_colors),global_colormap);
   1055       if (count != (ssize_t) (3*global_colors))
   1056         ThrowGIFException(CorruptImageError,"InsufficientImageDataInFile");
   1057     }
   1058   duration=0;
   1059   opacity=(-1);
   1060   image_count=0;
   1061   for ( ; ; )
   1062   {
   1063     count=ReadBlob(image,1,&c);
   1064     if (count != 1)
   1065       break;
   1066     if (c == (unsigned char) ';')
   1067       break;  /* terminator */
   1068     if (c == (unsigned char) '!')
   1069       {
   1070         /*
   1071           GIF Extension block.
   1072         */
   1073         (void) memset(buffer,0,sizeof(buffer));
   1074         count=ReadBlob(image,1,&c);
   1075         if (count != 1)
   1076           ThrowGIFException(CorruptImageError,"UnableToReadExtensionBlock");
   1077         switch (c)
   1078         {
   1079           case 0xf9:
   1080           {
   1081             /*
   1082               Read graphics control extension.
   1083             */
   1084             while (ReadBlobBlock(image,buffer) != 0) ;
   1085             meta_image->dispose=(DisposeType) ((buffer[0] >> 2) & 0x07);
   1086             meta_image->delay=((size_t) buffer[2] << 8) | buffer[1];
   1087             if ((ssize_t) (buffer[0] & 0x01) == 0x01)
   1088               opacity=(ssize_t) buffer[3];
   1089             break;
   1090           }
   1091           case 0xfe:
   1092           {
   1093             char
   1094               *comments;
   1095 
   1096             size_t
   1097               extent,
   1098               offset;
   1099 
   1100             comments=AcquireString((char *) NULL);
   1101             extent=MagickPathExtent;
   1102             for (offset=0; ; offset+=count)
   1103             {
   1104               count=ReadBlobBlock(image,buffer);
   1105               if (count == 0)
   1106                 break;
   1107               buffer[count]='\0';
   1108               if (((ssize_t) count+offset+MagickPathExtent) >= (ssize_t) extent)
   1109                 {
   1110                   extent<<=1;
   1111                   comments=(char *) ResizeQuantumMemory(comments,extent+
   1112                     MagickPathExtent,sizeof(*comments));
   1113                   if (comments == (char *) NULL)
   1114                     ThrowGIFException(ResourceLimitError,
   1115                       "MemoryAllocationFailed");
   1116                 }
   1117               (void) CopyMagickString(&comments[offset],(char *) buffer,extent-
   1118                 offset);
   1119             }
   1120             (void) SetImageProperty(meta_image,"comment",comments,exception);
   1121             comments=DestroyString(comments);
   1122             break;
   1123           }
   1124           case 0xff:
   1125           {
   1126             MagickBooleanType
   1127               loop;
   1128 
   1129             /*
   1130               Read Netscape Loop extension.
   1131             */
   1132             loop=MagickFalse;
   1133             if (ReadBlobBlock(image,buffer) != 0)
   1134               loop=LocaleNCompare((char *) buffer,"NETSCAPE2.0",11) == 0 ?
   1135                 MagickTrue : MagickFalse;
   1136             if (loop != MagickFalse)
   1137               while (ReadBlobBlock(image,buffer) != 0)
   1138               {
   1139                 meta_image->iterations=((size_t) buffer[2] << 8) | buffer[1];
   1140                 if (meta_image->iterations != 0)
   1141                   meta_image->iterations++;
   1142               }
   1143             else
   1144               {
   1145                 char
   1146                   name[MagickPathExtent];
   1147 
   1148                 int
   1149                   block_length,
   1150                   info_length,
   1151                   reserved_length;
   1152 
   1153                 MagickBooleanType
   1154                   i8bim,
   1155                   icc,
   1156                   iptc,
   1157                   magick;
   1158 
   1159                 StringInfo
   1160                   *profile;
   1161 
   1162                 unsigned char
   1163                   *info;
   1164 
   1165                 /*
   1166                   Store GIF application extension as a generic profile.
   1167                 */
   1168                 icc=LocaleNCompare((char *) buffer,"ICCRGBG1012",11) == 0 ?
   1169                   MagickTrue : MagickFalse;
   1170                 magick=LocaleNCompare((char *) buffer,"ImageMagick",11) == 0 ?
   1171                   MagickTrue : MagickFalse;
   1172                 i8bim=LocaleNCompare((char *) buffer,"MGK8BIM0000",11) == 0 ?
   1173                   MagickTrue : MagickFalse;
   1174                 iptc=LocaleNCompare((char *) buffer,"MGKIPTC0000",11) == 0 ?
   1175                   MagickTrue : MagickFalse;
   1176                 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   1177                   "    Reading GIF application extension");
   1178                 info=(unsigned char *) AcquireQuantumMemory(255UL,
   1179                   sizeof(*info));
   1180                 if (info == (unsigned char *) NULL)
   1181                   ThrowGIFException(ResourceLimitError,
   1182                     "MemoryAllocationFailed");
   1183                 (void) memset(info,0,255UL*sizeof(*info));
   1184                 reserved_length=255;
   1185                 for (info_length=0; ; )
   1186                 {
   1187                   block_length=(int) ReadBlobBlock(image,&info[info_length]);
   1188                   if (block_length == 0)
   1189                     break;
   1190                   info_length+=block_length;
   1191                   if (info_length > (reserved_length-255))
   1192                     {
   1193                       reserved_length+=4096;
   1194                       info=(unsigned char *) ResizeQuantumMemory(info,(size_t)
   1195                         reserved_length,sizeof(*info));
   1196                       if (info == (unsigned char *) NULL)
   1197                         {
   1198                           info=(unsigned char *) RelinquishMagickMemory(info);
   1199                           ThrowGIFException(ResourceLimitError,
   1200                             "MemoryAllocationFailed");
   1201                         }
   1202                     }
   1203                 }
   1204                 profile=BlobToStringInfo(info,(size_t) info_length);
   1205                 if (profile == (StringInfo *) NULL)
   1206                   {
   1207                     info=(unsigned char *) RelinquishMagickMemory(info);
   1208                     ThrowGIFException(ResourceLimitError,
   1209                       "MemoryAllocationFailed");
   1210                   }
   1211                 if (i8bim != MagickFalse)
   1212                   (void) CopyMagickString(name,"8bim",sizeof(name));
   1213                 else if (icc != MagickFalse)
   1214                   (void) CopyMagickString(name,"icc",sizeof(name));
   1215                 else if (iptc != MagickFalse)
   1216                   (void) CopyMagickString(name,"iptc",sizeof(name));
   1217                 else if (magick != MagickFalse)
   1218                   {
   1219                     (void) CopyMagickString(name,"magick",sizeof(name));
   1220                     meta_image->gamma=StringToDouble((char *) info+6,
   1221                       (char **) NULL);
   1222                   }
   1223                 else
   1224                   (void) FormatLocaleString(name,sizeof(name),"gif:%.11s",
   1225                     buffer);
   1226                 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   1227                   "      profile name=%s",name);
   1228                 info=(unsigned char *) RelinquishMagickMemory(info);
   1229                 if (magick != MagickFalse)
   1230                   profile=DestroyStringInfo(profile);
   1231                 else
   1232                   {
   1233                     if (profiles == (LinkedListInfo *) NULL)
   1234                       profiles=NewLinkedList(0);
   1235                     SetStringInfoName(profile,name);
   1236                     (void) AppendValueToLinkedList(profiles,profile);
   1237                   }
   1238               }
   1239             break;
   1240           }
   1241           default:
   1242           {
   1243             while (ReadBlobBlock(image,buffer) != 0) ;
   1244             break;
   1245           }
   1246         }
   1247       }
   1248     if (c != (unsigned char) ',')
   1249       continue;
   1250     image_count++;
   1251     if (image_count != 1)
   1252       {
   1253         /*
   1254           Allocate next image structure.
   1255         */
   1256         AcquireNextImage(image_info,image,exception);
   1257         if (GetNextImageInList(image) == (Image *) NULL)
   1258           {
   1259             status=MagickFalse;
   1260             break;
   1261           }
   1262         image=SyncNextImageInList(image);
   1263       }
   1264     /*
   1265       Read image attributes.
   1266     */
   1267     meta_image->page.x=(ssize_t) ReadBlobLSBShort(image);
   1268     meta_image->page.y=(ssize_t) ReadBlobLSBShort(image);
   1269     meta_image->scene=image->scene;
   1270     (void) CloneImageProperties(image,meta_image);
   1271     DestroyImageProperties(meta_image);
   1272     image->storage_class=PseudoClass;
   1273     image->compression=LZWCompression;
   1274     image->columns=ReadBlobLSBShort(image);
   1275     image->rows=ReadBlobLSBShort(image);
   1276     image->depth=8;
   1277     flag=(unsigned char) ReadBlobByte(image);
   1278     image->interlace=BitSet((int) flag,0x40) != 0 ? GIFInterlace : NoInterlace;
   1279     local_colors=BitSet((int) flag,0x80) == 0 ? global_colors : one <<
   1280       ((size_t) (flag & 0x07)+1);
   1281     image->colors=local_colors;
   1282     if (opacity >= (ssize_t) image->colors)
   1283       {
   1284         image->colors++;
   1285         opacity=(-1);
   1286       }
   1287     image->ticks_per_second=100;
   1288     image->alpha_trait=opacity >= 0 ? BlendPixelTrait : UndefinedPixelTrait;
   1289     if ((image->columns == 0) || (image->rows == 0))
   1290       ThrowGIFException(CorruptImageError,"NegativeOrZeroImageSize");
   1291     /*
   1292       Inititialize colormap.
   1293     */
   1294     if (AcquireImageColormap(image,image->colors,exception) == MagickFalse)
   1295       ThrowGIFException(ResourceLimitError,"MemoryAllocationFailed");
   1296     if (BitSet((int) flag,0x80) == 0)
   1297       {
   1298         /*
   1299           Use global colormap.
   1300         */
   1301         p=global_colormap;
   1302         for (i=0; i < (ssize_t) image->colors; i++)
   1303         {
   1304           image->colormap[i].red=(double) ScaleCharToQuantum(*p++);
   1305           image->colormap[i].green=(double) ScaleCharToQuantum(*p++);
   1306           image->colormap[i].blue=(double) ScaleCharToQuantum(*p++);
   1307           if (i == opacity)
   1308             {
   1309               image->colormap[i].alpha=(double) TransparentAlpha;
   1310               image->transparent_color=image->colormap[opacity];
   1311             }
   1312         }
   1313         image->background_color=image->colormap[MagickMin((ssize_t) background,
   1314           (ssize_t) image->colors-1)];
   1315       }
   1316     else
   1317       {
   1318         unsigned char
   1319           *colormap;
   1320 
   1321         /*
   1322           Read local colormap.
   1323         */
   1324         colormap=(unsigned char *) AcquireQuantumMemory((size_t)
   1325           MagickMax(local_colors,256),3UL*sizeof(*colormap));
   1326         if (colormap == (unsigned char *) NULL)
   1327           ThrowGIFException(ResourceLimitError,"MemoryAllocationFailed");
   1328         (void) memset(colormap,0,3*MagickMax(local_colors,256)*
   1329           sizeof(*colormap));
   1330         count=ReadBlob(image,(3*local_colors)*sizeof(*colormap),colormap);
   1331         if (count != (ssize_t) (3*local_colors))
   1332           {
   1333             colormap=(unsigned char *) RelinquishMagickMemory(colormap);
   1334             ThrowGIFException(CorruptImageError,"InsufficientImageDataInFile");
   1335           }
   1336         p=colormap;
   1337         for (i=0; i < (ssize_t) image->colors; i++)
   1338         {
   1339           image->colormap[i].red=(double) ScaleCharToQuantum(*p++);
   1340           image->colormap[i].green=(double) ScaleCharToQuantum(*p++);
   1341           image->colormap[i].blue=(double) ScaleCharToQuantum(*p++);
   1342           if (i == opacity)
   1343             image->colormap[i].alpha=(double) TransparentAlpha;
   1344         }
   1345         colormap=(unsigned char *) RelinquishMagickMemory(colormap);
   1346       }
   1347     if (image->gamma == 1.0)
   1348       {
   1349         for (i=0; i < (ssize_t) image->colors; i++)
   1350           if (IsPixelInfoGray(image->colormap+i) == MagickFalse)
   1351             break;
   1352         (void) SetImageColorspace(image,i == (ssize_t) image->colors ?
   1353           GRAYColorspace : RGBColorspace,exception);
   1354       }
   1355     if ((image_info->ping != MagickFalse) && (image_info->number_scenes != 0))
   1356       if (image->scene >= (image_info->scene+image_info->number_scenes-1))
   1357         break;
   1358     status=SetImageExtent(image,image->columns,image->rows,exception);
   1359     if (status == MagickFalse)
   1360       {
   1361         if (profiles != (LinkedListInfo *) NULL)
   1362           profiles=DestroyLinkedList(profiles,DestroyGIFProfile);
   1363         global_colormap=(unsigned char *) RelinquishMagickMemory(
   1364           global_colormap);
   1365         meta_image=DestroyImage(meta_image);
   1366         return(DestroyImageList(image));
   1367       }
   1368     /*
   1369       Decode image.
   1370     */
   1371     if (image_info->ping != MagickFalse)
   1372       status=PingGIFImage(image,exception);
   1373     else
   1374       status=DecodeImage(image,opacity,exception);
   1375     if ((image_info->ping == MagickFalse) && (status == MagickFalse))
   1376       ThrowGIFException(CorruptImageError,"CorruptImage");
   1377     if (profiles != (LinkedListInfo *) NULL)
   1378       {
   1379         StringInfo
   1380           *profile;
   1381 
   1382         /*
   1383           Set image profiles.
   1384         */
   1385         ResetLinkedListIterator(profiles);
   1386         profile=(StringInfo *) GetNextValueInLinkedList(profiles);
   1387         while (profile != (StringInfo *) NULL)
   1388         {
   1389           (void) SetImageProfile(image,GetStringInfoName(profile),profile,
   1390             exception);
   1391           profile=(StringInfo *) GetNextValueInLinkedList(profiles);
   1392         }
   1393         profiles=DestroyLinkedList(profiles,DestroyGIFProfile);
   1394       }
   1395     duration+=image->delay*image->iterations;
   1396     if (image_info->number_scenes != 0)
   1397       if (image->scene >= (image_info->scene+image_info->number_scenes-1))
   1398         break;
   1399     opacity=(-1);
   1400     status=SetImageProgress(image,LoadImageTag,(MagickOffsetType)
   1401       image->scene-1,image->scene);
   1402     if (status == MagickFalse)
   1403       break;
   1404   }
   1405   image->duration=duration;
   1406   if (profiles != (LinkedListInfo *) NULL)
   1407     profiles=DestroyLinkedList(profiles,DestroyGIFProfile);
   1408   meta_image=DestroyImage(meta_image);
   1409   global_colormap=(unsigned char *) RelinquishMagickMemory(global_colormap);
   1410   if ((image->columns == 0) || (image->rows == 0))
   1411     ThrowReaderException(CorruptImageError,"NegativeOrZeroImageSize");
   1412   (void) CloseBlob(image);
   1413   if (status == MagickFalse)
   1414     return(DestroyImageList(image));
   1415   return(GetFirstImageInList(image));
   1416 }
   1417 
   1418 /*
   1420 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
   1421 %                                                                             %
   1422 %                                                                             %
   1423 %                                                                             %
   1424 %   R e g i s t e r G I F I m a g e                                           %
   1425 %                                                                             %
   1426 %                                                                             %
   1427 %                                                                             %
   1428 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
   1429 %
   1430 %  RegisterGIFImage() adds properties for the GIF image format to
   1431 %  the list of supported formats.  The properties include the image format
   1432 %  tag, a method to read and/or write the format, whether the format
   1433 %  supports the saving of more than one frame to the same file or blob,
   1434 %  whether the format supports native in-memory I/O, and a brief
   1435 %  description of the format.
   1436 %
   1437 %  The format of the RegisterGIFImage method is:
   1438 %
   1439 %      size_t RegisterGIFImage(void)
   1440 %
   1441 */
   1442 ModuleExport size_t RegisterGIFImage(void)
   1443 {
   1444   MagickInfo
   1445     *entry;
   1446 
   1447   entry=AcquireMagickInfo("GIF","GIF",
   1448     "CompuServe graphics interchange format");
   1449   entry->decoder=(DecodeImageHandler *) ReadGIFImage;
   1450   entry->encoder=(EncodeImageHandler *) WriteGIFImage;
   1451   entry->magick=(IsImageFormatHandler *) IsGIF;
   1452   entry->mime_type=ConstantString("image/gif");
   1453   (void) RegisterMagickInfo(entry);
   1454   entry=AcquireMagickInfo("GIF","GIF87",
   1455     "CompuServe graphics interchange format");
   1456   entry->decoder=(DecodeImageHandler *) ReadGIFImage;
   1457   entry->encoder=(EncodeImageHandler *) WriteGIFImage;
   1458   entry->magick=(IsImageFormatHandler *) IsGIF;
   1459   entry->flags^=CoderAdjoinFlag;
   1460   entry->version=ConstantString("version 87a");
   1461   entry->mime_type=ConstantString("image/gif");
   1462   (void) RegisterMagickInfo(entry);
   1463   return(MagickImageCoderSignature);
   1464 }
   1465 
   1466 /*
   1468 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
   1469 %                                                                             %
   1470 %                                                                             %
   1471 %                                                                             %
   1472 %   U n r e g i s t e r G I F I m a g e                                       %
   1473 %                                                                             %
   1474 %                                                                             %
   1475 %                                                                             %
   1476 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
   1477 %
   1478 %  UnregisterGIFImage() removes format registrations made by the
   1479 %  GIF module from the list of supported formats.
   1480 %
   1481 %  The format of the UnregisterGIFImage method is:
   1482 %
   1483 %      UnregisterGIFImage(void)
   1484 %
   1485 */
   1486 ModuleExport void UnregisterGIFImage(void)
   1487 {
   1488   (void) UnregisterMagickInfo("GIF");
   1489   (void) UnregisterMagickInfo("GIF87");
   1490 }
   1491 
   1492 /*
   1494 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
   1495 %                                                                             %
   1496 %                                                                             %
   1497 %                                                                             %
   1498 %   W r i t e G I F I m a g e                                                 %
   1499 %                                                                             %
   1500 %                                                                             %
   1501 %                                                                             %
   1502 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
   1503 %
   1504 %  WriteGIFImage() writes an image to a file in the Compuserve Graphics
   1505 %  image format.
   1506 %
   1507 %  The format of the WriteGIFImage method is:
   1508 %
   1509 %      MagickBooleanType WriteGIFImage(const ImageInfo *image_info,
   1510 %        Image *image,ExceptionInfo *exception)
   1511 %
   1512 %  A description of each parameter follows.
   1513 %
   1514 %    o image_info: the image info.
   1515 %
   1516 %    o image:  The image.
   1517 %
   1518 %    o exception: return any errors or warnings in this structure.
   1519 %
   1520 */
   1521 static MagickBooleanType WriteGIFImage(const ImageInfo *image_info,Image *image,
   1522   ExceptionInfo *exception)
   1523 {
   1524   int
   1525     c;
   1526 
   1527   ImageInfo
   1528     *write_info;
   1529 
   1530   MagickBooleanType
   1531     status;
   1532 
   1533   MagickOffsetType
   1534     scene;
   1535 
   1536   RectangleInfo
   1537     page;
   1538 
   1539   register ssize_t
   1540     i;
   1541 
   1542   register unsigned char
   1543     *q;
   1544 
   1545   size_t
   1546     bits_per_pixel,
   1547     delay,
   1548     imageListLength,
   1549     length,
   1550     one;
   1551 
   1552   ssize_t
   1553     j,
   1554     opacity;
   1555 
   1556   unsigned char
   1557     *colormap,
   1558     *global_colormap;
   1559 
   1560   /*
   1561     Open output image file.
   1562   */
   1563   assert(image_info != (const ImageInfo *) NULL);
   1564   assert(image_info->signature == MagickCoreSignature);
   1565   assert(image != (Image *) NULL);
   1566   assert(image->signature == MagickCoreSignature);
   1567   if (image->debug != MagickFalse)
   1568     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
   1569   assert(exception != (ExceptionInfo *) NULL);
   1570   assert(exception->signature == MagickCoreSignature);
   1571   status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
   1572   if (status == MagickFalse)
   1573     return(status);
   1574   /*
   1575     Allocate colormap.
   1576   */
   1577   global_colormap=(unsigned char *) AcquireQuantumMemory(768UL,
   1578     sizeof(*global_colormap));
   1579   colormap=(unsigned char *) AcquireQuantumMemory(768UL,sizeof(*colormap));
   1580   if ((global_colormap == (unsigned char *) NULL) ||
   1581       (colormap == (unsigned char *) NULL))
   1582     {
   1583       if (global_colormap != (unsigned char *) NULL)
   1584         global_colormap=(unsigned char *) RelinquishMagickMemory(
   1585           global_colormap);
   1586       if (colormap != (unsigned char *) NULL)
   1587         colormap=(unsigned char *) RelinquishMagickMemory(colormap);
   1588       ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
   1589     }
   1590   for (i=0; i < 768; i++)
   1591     colormap[i]=(unsigned char) 0;
   1592   /*
   1593     Write GIF header.
   1594   */
   1595   write_info=CloneImageInfo(image_info);
   1596   if (LocaleCompare(write_info->magick,"GIF87") != 0)
   1597     (void) WriteBlob(image,6,(unsigned char *) "GIF89a");
   1598   else
   1599     {
   1600       (void) WriteBlob(image,6,(unsigned char *) "GIF87a");
   1601       write_info->adjoin=MagickFalse;
   1602     }
   1603   /*
   1604     Determine image bounding box.
   1605   */
   1606   page.width=image->columns;
   1607   if (image->page.width > page.width)
   1608     page.width=image->page.width;
   1609   page.height=image->rows;
   1610   if (image->page.height > page.height)
   1611     page.height=image->page.height;
   1612   page.x=image->page.x;
   1613   page.y=image->page.y;
   1614   (void) WriteBlobLSBShort(image,(unsigned short) page.width);
   1615   (void) WriteBlobLSBShort(image,(unsigned short) page.height);
   1616   /*
   1617     Write images to file.
   1618   */
   1619   if ((write_info->adjoin != MagickFalse) &&
   1620       (GetNextImageInList(image) != (Image *) NULL))
   1621     write_info->interlace=NoInterlace;
   1622   scene=0;
   1623   one=1;
   1624   imageListLength=GetImageListLength(image);
   1625   do
   1626   {
   1627     (void) TransformImageColorspace(image,sRGBColorspace,exception);
   1628     opacity=(-1);
   1629     if (IsImageOpaque(image,exception) != MagickFalse)
   1630       {
   1631         if ((image->storage_class == DirectClass) || (image->colors > 256))
   1632           (void) SetImageType(image,PaletteType,exception);
   1633       }
   1634     else
   1635       {
   1636         double
   1637           alpha,
   1638           beta;
   1639 
   1640         /*
   1641           Identify transparent colormap index.
   1642         */
   1643         if ((image->storage_class == DirectClass) || (image->colors > 256))
   1644           (void) SetImageType(image,PaletteBilevelAlphaType,exception);
   1645         for (i=0; i < (ssize_t) image->colors; i++)
   1646           if (image->colormap[i].alpha != OpaqueAlpha)
   1647             {
   1648               if (opacity < 0)
   1649                 {
   1650                   opacity=i;
   1651                   continue;
   1652                 }
   1653               alpha=fabs(image->colormap[i].alpha-TransparentAlpha);
   1654               beta=fabs(image->colormap[opacity].alpha-TransparentAlpha);
   1655               if (alpha < beta)
   1656                 opacity=i;
   1657             }
   1658         if (opacity == -1)
   1659           {
   1660             (void) SetImageType(image,PaletteBilevelAlphaType,exception);
   1661             for (i=0; i < (ssize_t) image->colors; i++)
   1662               if (image->colormap[i].alpha != OpaqueAlpha)
   1663                 {
   1664                   if (opacity < 0)
   1665                     {
   1666                       opacity=i;
   1667                       continue;
   1668                     }
   1669                   alpha=fabs(image->colormap[i].alpha-TransparentAlpha);
   1670                   beta=fabs(image->colormap[opacity].alpha-TransparentAlpha);
   1671                   if (alpha < beta)
   1672                     opacity=i;
   1673                 }
   1674           }
   1675         if (opacity >= 0)
   1676           {
   1677             image->colormap[opacity].red=image->transparent_color.red;
   1678             image->colormap[opacity].green=image->transparent_color.green;
   1679             image->colormap[opacity].blue=image->transparent_color.blue;
   1680           }
   1681       }
   1682     if ((image->storage_class == DirectClass) || (image->colors > 256))
   1683       ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
   1684     for (bits_per_pixel=1; bits_per_pixel < 8; bits_per_pixel++)
   1685       if ((one << bits_per_pixel) >= image->colors)
   1686         break;
   1687     q=colormap;
   1688     for (i=0; i < (ssize_t) image->colors; i++)
   1689     {
   1690       *q++=ScaleQuantumToChar(ClampToQuantum(image->colormap[i].red));
   1691       *q++=ScaleQuantumToChar(ClampToQuantum(image->colormap[i].green));
   1692       *q++=ScaleQuantumToChar(ClampToQuantum(image->colormap[i].blue));
   1693     }
   1694     for ( ; i < (ssize_t) (one << bits_per_pixel); i++)
   1695     {
   1696       *q++=(unsigned char) 0x0;
   1697       *q++=(unsigned char) 0x0;
   1698       *q++=(unsigned char) 0x0;
   1699     }
   1700     if ((GetPreviousImageInList(image) == (Image *) NULL) ||
   1701         (write_info->adjoin == MagickFalse))
   1702       {
   1703         /*
   1704           Write global colormap.
   1705         */
   1706         c=0x80;
   1707         c|=(8-1) << 4;  /* color resolution */
   1708         c|=(bits_per_pixel-1);   /* size of global colormap */
   1709         (void) WriteBlobByte(image,(unsigned char) c);
   1710         for (j=0; j < (ssize_t) image->colors; j++)
   1711           if (IsPixelInfoEquivalent(&image->background_color,image->colormap+j))
   1712             break;
   1713         (void) WriteBlobByte(image,(unsigned char)
   1714           (j == (ssize_t) image->colors ? 0 : j));  /* background color */
   1715         (void) WriteBlobByte(image,(unsigned char) 0x00);  /* reserved */
   1716         length=(size_t) (3*(one << bits_per_pixel));
   1717         (void) WriteBlob(image,length,colormap);
   1718         for (j=0; j < 768; j++)
   1719           global_colormap[j]=colormap[j];
   1720       }
   1721     if (LocaleCompare(write_info->magick,"GIF87") != 0)
   1722       {
   1723         const char
   1724           *value;
   1725 
   1726         /*
   1727           Write graphics control extension.
   1728         */
   1729         (void) WriteBlobByte(image,(unsigned char) 0x21);
   1730         (void) WriteBlobByte(image,(unsigned char) 0xf9);
   1731         (void) WriteBlobByte(image,(unsigned char) 0x04);
   1732         c=image->dispose << 2;
   1733         if (opacity >= 0)
   1734           c|=0x01;
   1735         (void) WriteBlobByte(image,(unsigned char) c);
   1736         delay=(size_t) (100*image->delay/MagickMax((size_t)
   1737           image->ticks_per_second,1));
   1738         (void) WriteBlobLSBShort(image,(unsigned short) delay);
   1739         (void) WriteBlobByte(image,(unsigned char) (opacity >= 0 ? opacity :
   1740           0));
   1741         (void) WriteBlobByte(image,(unsigned char) 0x00);
   1742         value=GetImageProperty(image,"comment",exception);
   1743         if (value != (const char *) NULL)
   1744           {
   1745             register const char
   1746               *p;
   1747 
   1748             size_t
   1749               count;
   1750 
   1751             /*
   1752               Write comment extension.
   1753             */
   1754             (void) WriteBlobByte(image,(unsigned char) 0x21);
   1755             (void) WriteBlobByte(image,(unsigned char) 0xfe);
   1756             for (p=value; *p != '\0'; )
   1757             {
   1758               count=MagickMin(strlen(p),255);
   1759               (void) WriteBlobByte(image,(unsigned char) count);
   1760               for (i=0; i < (ssize_t) count; i++)
   1761                 (void) WriteBlobByte(image,(unsigned char) *p++);
   1762             }
   1763             (void) WriteBlobByte(image,(unsigned char) 0x00);
   1764           }
   1765         if ((GetPreviousImageInList(image) == (Image *) NULL) &&
   1766             (GetNextImageInList(image) != (Image *) NULL) &&
   1767             (image->iterations != 1))
   1768           {
   1769             /*
   1770               Write Netscape Loop extension.
   1771             */
   1772             (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   1773                "  Writing GIF Extension %s","NETSCAPE2.0");
   1774             (void) WriteBlobByte(image,(unsigned char) 0x21);
   1775             (void) WriteBlobByte(image,(unsigned char) 0xff);
   1776             (void) WriteBlobByte(image,(unsigned char) 0x0b);
   1777             (void) WriteBlob(image,11,(unsigned char *) "NETSCAPE2.0");
   1778             (void) WriteBlobByte(image,(unsigned char) 0x03);
   1779             (void) WriteBlobByte(image,(unsigned char) 0x01);
   1780             (void) WriteBlobLSBShort(image,(unsigned short) (image->iterations ?
   1781               image->iterations-1 : 0));
   1782             (void) WriteBlobByte(image,(unsigned char) 0x00);
   1783           }
   1784         if ((image->gamma != 1.0f/2.2f))
   1785           {
   1786             char
   1787               attributes[MagickPathExtent];
   1788 
   1789             ssize_t
   1790               count;
   1791 
   1792             /*
   1793               Write ImageMagick extension.
   1794             */
   1795             (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   1796                "  Writing GIF Extension %s","ImageMagick");
   1797             (void) WriteBlobByte(image,(unsigned char) 0x21);
   1798             (void) WriteBlobByte(image,(unsigned char) 0xff);
   1799             (void) WriteBlobByte(image,(unsigned char) 0x0b);
   1800             (void) WriteBlob(image,11,(unsigned char *) "ImageMagick");
   1801             count=FormatLocaleString(attributes,MagickPathExtent,"gamma=%g",
   1802               image->gamma);
   1803             (void) WriteBlobByte(image,(unsigned char) count);
   1804             (void) WriteBlob(image,(size_t) count,(unsigned char *) attributes);
   1805             (void) WriteBlobByte(image,(unsigned char) 0x00);
   1806           }
   1807         ResetImageProfileIterator(image);
   1808         for ( ; ; )
   1809         {
   1810           char
   1811             *name;
   1812 
   1813           const StringInfo
   1814             *profile;
   1815 
   1816           name=GetNextImageProfile(image);
   1817           if (name == (const char *) NULL)
   1818             break;
   1819           profile=GetImageProfile(image,name);
   1820           if (profile != (StringInfo *) NULL)
   1821           {
   1822             if ((LocaleCompare(name,"ICC") == 0) ||
   1823                 (LocaleCompare(name,"ICM") == 0) ||
   1824                 (LocaleCompare(name,"IPTC") == 0) ||
   1825                 (LocaleCompare(name,"8BIM") == 0) ||
   1826                 (LocaleNCompare(name,"gif:",4) == 0))
   1827             {
   1828                ssize_t
   1829                  offset;
   1830 
   1831                unsigned char
   1832                  *datum;
   1833 
   1834                datum=GetStringInfoDatum(profile);
   1835                length=GetStringInfoLength(profile);
   1836                (void) WriteBlobByte(image,(unsigned char) 0x21);
   1837                (void) WriteBlobByte(image,(unsigned char) 0xff);
   1838                (void) WriteBlobByte(image,(unsigned char) 0x0b);
   1839                if ((LocaleCompare(name,"ICC") == 0) ||
   1840                    (LocaleCompare(name,"ICM") == 0))
   1841                  {
   1842                    /*
   1843                      Write ICC extension.
   1844                    */
   1845                    (void) WriteBlob(image,11,(unsigned char *) "ICCRGBG1012");
   1846                    (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   1847                      "  Writing GIF Extension %s","ICCRGBG1012");
   1848                  }
   1849                else
   1850                  if ((LocaleCompare(name,"IPTC") == 0))
   1851                    {
   1852                      /*
   1853                        Write IPTC extension.
   1854                      */
   1855                      (void) WriteBlob(image,11,(unsigned char *) "MGKIPTC0000");
   1856                      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   1857                        "  Writing GIF Extension %s","MGKIPTC0000");
   1858                    }
   1859                  else
   1860                    if ((LocaleCompare(name,"8BIM") == 0))
   1861                      {
   1862                        /*
   1863                          Write 8BIM extension.
   1864                        */
   1865                         (void) WriteBlob(image,11,(unsigned char *)
   1866                           "MGK8BIM0000");
   1867                         (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   1868                           "  Writing GIF Extension %s","MGK8BIM0000");
   1869                      }
   1870                    else
   1871                      {
   1872                        char
   1873                          extension[MagickPathExtent];
   1874 
   1875                        /*
   1876                          Write generic extension.
   1877                        */
   1878                        (void) CopyMagickString(extension,name+4,
   1879                          sizeof(extension));
   1880                        (void) WriteBlob(image,11,(unsigned char *) extension);
   1881                        (void) LogMagickEvent(CoderEvent,GetMagickModule(),
   1882                          "  Writing GIF Extension %s",name);
   1883                      }
   1884                offset=0;
   1885                while ((ssize_t) length > offset)
   1886                {
   1887                  size_t
   1888                    block_length;
   1889 
   1890                  if ((length-offset) < 255)
   1891                    block_length=length-offset;
   1892                  else
   1893                    block_length=255;
   1894                  (void) WriteBlobByte(image,(unsigned char) block_length);
   1895                  (void) WriteBlob(image,(size_t) block_length,datum+offset);
   1896                  offset+=(ssize_t) block_length;
   1897                }
   1898                (void) WriteBlobByte(image,(unsigned char) 0x00);
   1899             }
   1900           }
   1901         }
   1902       }
   1903     (void) WriteBlobByte(image,',');  /* image separator */
   1904     /*
   1905       Write the image header.
   1906     */
   1907     page.x=image->page.x;
   1908     page.y=image->page.y;
   1909     if ((image->page.width != 0) && (image->page.height != 0))
   1910       page=image->page;
   1911     (void) WriteBlobLSBShort(image,(unsigned short) (page.x < 0 ? 0 : page.x));
   1912     (void) WriteBlobLSBShort(image,(unsigned short) (page.y < 0 ? 0 : page.y));
   1913     (void) WriteBlobLSBShort(image,(unsigned short) image->columns);
   1914     (void) WriteBlobLSBShort(image,(unsigned short) image->rows);
   1915     c=0x00;
   1916     if (write_info->interlace != NoInterlace)
   1917       c|=0x40;  /* pixel data is interlaced */
   1918     for (j=0; j < (ssize_t) (3*image->colors); j++)
   1919       if (colormap[j] != global_colormap[j])
   1920         break;
   1921     if (j == (ssize_t) (3*image->colors))
   1922       (void) WriteBlobByte(image,(unsigned char) c);
   1923     else
   1924       {
   1925         c|=0x80;
   1926         c|=(bits_per_pixel-1);   /* size of local colormap */
   1927         (void) WriteBlobByte(image,(unsigned char) c);
   1928         length=(size_t) (3*(one << bits_per_pixel));
   1929         (void) WriteBlob(image,length,colormap);
   1930       }
   1931     /*
   1932       Write the image data.
   1933     */
   1934     c=(int) MagickMax(bits_per_pixel,2);
   1935     (void) WriteBlobByte(image,(unsigned char) c);
   1936     status=EncodeImage(write_info,image,(size_t) MagickMax(bits_per_pixel,2)+1,
   1937       exception);
   1938     if (status == MagickFalse)
   1939       {
   1940         global_colormap=(unsigned char *) RelinquishMagickMemory(
   1941           global_colormap);
   1942         colormap=(unsigned char *) RelinquishMagickMemory(colormap);
   1943         write_info=DestroyImageInfo(write_info);
   1944         ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
   1945       }
   1946     (void) WriteBlobByte(image,(unsigned char) 0x00);
   1947     if (GetNextImageInList(image) == (Image *) NULL)
   1948       break;
   1949     image=SyncNextImageInList(image);
   1950     scene++;
   1951     status=SetImageProgress(image,SaveImagesTag,scene,imageListLength);
   1952     if (status == MagickFalse)
   1953       break;
   1954   } while (write_info->adjoin != MagickFalse);
   1955   (void) WriteBlobByte(image,';'); /* terminator */
   1956   global_colormap=(unsigned char *) RelinquishMagickMemory(global_colormap);
   1957   colormap=(unsigned char *) RelinquishMagickMemory(colormap);
   1958   write_info=DestroyImageInfo(write_info);
   1959   (void) CloseBlob(image);
   1960   return(MagickTrue);
   1961 }
   1962