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