]> granicus.if.org Git - imagemagick/blob - coders/gif.c
...
[imagemagick] / coders / gif.c
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-2018 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://www.imagemagick.org/script/license.php                           %
27 %                                                                             %
28 %  Unless required by applicable law or agreed to in writing, software        %
29 %  distributed under the License is distributed on an "AS IS" BASIS,          %
30 %  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
31 %  See the License for the specific language governing permissions and        %
32 %  limitations under the License.                                             %
33 %                                                                             %
34 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
35 %
36 %
37 */
38 \f
39 /*
40   Include declarations.
41 */
42 #include "MagickCore/studio.h"
43 #include "MagickCore/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 \f
74 /*
75   Define declarations.
76 */
77 #define MaximumLZWBits  12
78 #define MaximumLZWCode  (1UL << MaximumLZWBits)
79 \f
80 /*
81   Typdef declarations.
82 */
83 typedef 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
96 typedef struct _LZWStack
97 {
98   size_t
99     *codes,
100     *index,
101     *top;
102 } LZWStack;
103
104 typedef 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 \f
131 /*
132   Forward declarations.
133 */
134 static inline int
135   GetNextLZWCode(LZWInfo *,const size_t);
136
137 static MagickBooleanType
138   WriteGIFImage(const ImageInfo *,Image *,ExceptionInfo *);
139
140 static ssize_t
141   ReadBlobBlock(Image *,unsigned char *);
142 \f
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
168 static 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
187 static 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
199 static 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
260 static 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
303 static 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
311 static 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
319 static 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
390 static 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 \f
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 */
531 static 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|=(size_t) (code) << bits; \
545   else \
546     datum=(size_t) (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(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(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 \f
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 */
833 static 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 \f
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 */
869 static 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 \f
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 */
915 static 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
942 static 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   register ssize_t
958     i;
959
960   register unsigned char
961     *p;
962
963   size_t
964     duration,
965     global_colors,
966     image_count,
967     local_colors,
968     one;
969
970   ssize_t
971     count,
972     opacity;
973
974   unsigned char
975     background,
976     buffer[257],
977     c,
978     flag,
979     *global_colormap;
980
981   /*
982     Open image file.
983   */
984   assert(image_info != (const ImageInfo *) NULL);
985   assert(image_info->signature == MagickCoreSignature);
986   if (image_info->debug != MagickFalse)
987     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
988       image_info->filename);
989   assert(exception != (ExceptionInfo *) NULL);
990   assert(exception->signature == MagickCoreSignature);
991   image=AcquireImage(image_info,exception);
992   status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
993   if (status == MagickFalse)
994     {
995       image=DestroyImageList(image);
996       return((Image *) NULL);
997     }
998   /*
999     Determine if this a GIF file.
1000   */
1001   count=ReadBlob(image,6,buffer);
1002   if ((count != 6) || ((LocaleNCompare((char *) buffer,"GIF87",5) != 0) &&
1003       (LocaleNCompare((char *) buffer,"GIF89",5) != 0)))
1004     ThrowReaderException(CorruptImageError,"ImproperImageHeader");
1005   (void) ResetMagickMemory(buffer,0,sizeof(buffer));
1006   meta_image=AcquireImage(image_info,exception);  /* metadata container */
1007   meta_image->page.width=ReadBlobLSBShort(image);
1008   meta_image->page.height=ReadBlobLSBShort(image);
1009   flag=(unsigned char) ReadBlobByte(image);
1010   background=(unsigned char) ReadBlobByte(image);
1011   c=(unsigned char) ReadBlobByte(image);  /* reserved */
1012   one=1;
1013   global_colors=one << (((size_t) flag & 0x07)+1);
1014   global_colormap=(unsigned char *) AcquireQuantumMemory((size_t)
1015     MagickMax(global_colors,256),3UL*sizeof(*global_colormap));
1016   if (global_colormap == (unsigned char *) NULL)
1017     {
1018       meta_image=DestroyImage(meta_image);
1019       ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1020     }
1021   (void) ResetMagickMemory(global_colormap,0,3*MagickMax(global_colors,256)*
1022     sizeof(*global_colormap));
1023   if (BitSet((int) flag,0x80) != 0)
1024     {
1025       count=ReadBlob(image,(size_t) (3*global_colors),global_colormap);
1026       if (count != (ssize_t) (3*global_colors))
1027         {
1028           global_colormap=(unsigned char *) RelinquishMagickMemory(
1029             global_colormap);
1030           meta_image=DestroyImage(meta_image);
1031           ThrowReaderException(CorruptImageError,"InsufficientImageDataInFile");
1032         }
1033     }
1034   duration=0;
1035   opacity=(-1);
1036   image_count=0;
1037   for ( ; ; )
1038   {
1039     count=ReadBlob(image,1,&c);
1040     if (count != 1)
1041       break;
1042     if (c == (unsigned char) ';')
1043       break;  /* terminator */
1044     if (c == (unsigned char) '!')
1045       {
1046         /*
1047           GIF Extension block.
1048         */
1049         count=ReadBlob(image,1,&c);
1050         if (count != 1)
1051           {
1052             global_colormap=(unsigned char *) RelinquishMagickMemory(
1053               global_colormap);
1054             meta_image=DestroyImage(meta_image);
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             meta_image->dispose=(DisposeType) ((buffer[0] >> 2) & 0x07);
1067             meta_image->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               while (ReadBlobBlock(image,buffer) != 0)
1110               {
1111                 meta_image->iterations=((size_t) buffer[2] << 8) | buffer[1];
1112                 if (meta_image->iterations != 0)
1113                   meta_image->iterations++;
1114               }
1115             else
1116               {
1117                 char
1118                   name[MagickPathExtent];
1119
1120                 int
1121                   block_length,
1122                   info_length,
1123                   reserved_length;
1124
1125                 MagickBooleanType
1126                   i8bim,
1127                   icc,
1128                   iptc,
1129                   magick;
1130
1131                 StringInfo
1132                   *profile;
1133
1134                 unsigned char
1135                   *info;
1136
1137                 /*
1138                   Store GIF application extension as a generic profile.
1139                 */
1140                 icc=LocaleNCompare((char *) buffer,"ICCRGBG1012",11) == 0 ?
1141                   MagickTrue : MagickFalse;
1142                 magick=LocaleNCompare((char *) buffer,"ImageMagick",11) == 0 ?
1143                   MagickTrue : MagickFalse;
1144                 i8bim=LocaleNCompare((char *) buffer,"MGK8BIM0000",11) == 0 ?
1145                   MagickTrue : MagickFalse;
1146                 iptc=LocaleNCompare((char *) buffer,"MGKIPTC0000",11) == 0 ?
1147                   MagickTrue : MagickFalse;
1148                 number_extensionss++;
1149                 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1150                   "    Reading GIF application extension");
1151                 info=(unsigned char *) AcquireQuantumMemory(255UL,
1152                   sizeof(*info));
1153                 if (info == (unsigned char *) NULL)
1154                   {
1155                     meta_image=DestroyImage(meta_image);
1156                     global_colormap=(unsigned char *) RelinquishMagickMemory(
1157                       global_colormap);
1158                     ThrowReaderException(ResourceLimitError,
1159                       "MemoryAllocationFailed");
1160                   }
1161                 (void) ResetMagickMemory(info,0,255UL*sizeof(*info));
1162                 reserved_length=255;
1163                 for (info_length=0; ; )
1164                 {
1165                   block_length=(int) ReadBlobBlock(image,&info[info_length]);
1166                   if (block_length == 0)
1167                     break;
1168                   info_length+=block_length;
1169                   if (info_length > (reserved_length-255))
1170                     {
1171                       reserved_length+=4096;
1172                       info=(unsigned char *) ResizeQuantumMemory(info,(size_t)
1173                         reserved_length,sizeof(*info));
1174                       if (info == (unsigned char *) NULL)
1175                         {
1176                           meta_image=DestroyImage(meta_image);
1177                           global_colormap=(unsigned char *)
1178                             RelinquishMagickMemory(global_colormap);
1179                           ThrowReaderException(ResourceLimitError,
1180                             "MemoryAllocationFailed");
1181                         }
1182                     }
1183                 }
1184                 profile=BlobToStringInfo(info,(size_t) info_length);
1185                 if (profile == (StringInfo *) NULL)
1186                   {
1187                     meta_image=DestroyImage(meta_image);
1188                     global_colormap=(unsigned char *) RelinquishMagickMemory(
1189                       global_colormap);
1190                     info=(unsigned char *) RelinquishMagickMemory(info);
1191                     ThrowReaderException(ResourceLimitError,
1192                       "MemoryAllocationFailed");
1193                   }
1194                 if (i8bim != MagickFalse)
1195                   (void) CopyMagickString(name,"8bim",sizeof(name));
1196                 else if (icc != MagickFalse)
1197                   (void) CopyMagickString(name,"icc",sizeof(name));
1198                 else if (iptc != MagickFalse)
1199                   (void) CopyMagickString(name,"iptc",sizeof(name));
1200                 else if (magick != MagickFalse)
1201                   {
1202                     (void) CopyMagickString(name,"magick",sizeof(name));
1203                     meta_image->gamma=StringToDouble((char *) info+6,
1204                       (char **) NULL);
1205                   }
1206                 else
1207                   (void) FormatLocaleString(name,sizeof(name),"gif:%.11s",
1208                     buffer);
1209                 info=(unsigned char *) RelinquishMagickMemory(info);
1210                 if (magick == MagickFalse)
1211                   (void) SetImageProfile(meta_image,name,profile,exception);
1212                 profile=DestroyStringInfo(profile);
1213                 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1214                   "      profile name=%s",name);
1215               }
1216             break;
1217           }
1218           default:
1219           {
1220             while (ReadBlobBlock(image,buffer) != 0) ;
1221             break;
1222           }
1223         }
1224       }
1225     if (c != (unsigned char) ',')
1226       continue;
1227     if (image_count != 0)
1228       {
1229         /*
1230           Allocate next image structure.
1231         */
1232         AcquireNextImage(image_info,image,exception);
1233         if (GetNextImageInList(image) == (Image *) NULL)
1234           {
1235             image=DestroyImageList(image);
1236             global_colormap=(unsigned char *) RelinquishMagickMemory(
1237               global_colormap);
1238             return((Image *) NULL);
1239           }
1240         image=SyncNextImageInList(image);
1241       }
1242     image_count++;
1243     /*
1244       Read image attributes.
1245     */
1246     meta_image->page.x=(ssize_t) ReadBlobLSBShort(image);
1247     meta_image->page.y=(ssize_t) ReadBlobLSBShort(image);
1248     meta_image->scene=image->scene;
1249     (void) CloneImageProperties(image,meta_image);
1250     DestroyImageProperties(meta_image);
1251     (void) CloneImageProfiles(image,meta_image);
1252     DestroyImageProfiles(meta_image);
1253     image->storage_class=PseudoClass;
1254     image->compression=LZWCompression;
1255     image->columns=ReadBlobLSBShort(image);
1256     image->rows=ReadBlobLSBShort(image);
1257     image->depth=8;
1258     flag=(unsigned char) ReadBlobByte(image);
1259     image->interlace=BitSet((int) flag,0x40) != 0 ? GIFInterlace : NoInterlace;
1260     local_colors=BitSet((int) flag,0x80) == 0 ? global_colors : one <<
1261       ((size_t) (flag & 0x07)+1);
1262     image->colors=local_colors;
1263     if (opacity >= (ssize_t) image->colors)
1264       image->colors=(size_t) (opacity+1);
1265     image->ticks_per_second=100;
1266     image->alpha_trait=opacity >= 0 ? BlendPixelTrait : UndefinedPixelTrait;
1267     if ((image->columns == 0) || (image->rows == 0))
1268       {
1269         global_colormap=(unsigned char *) RelinquishMagickMemory(
1270           global_colormap);
1271         meta_image=DestroyImage(meta_image);
1272         ThrowReaderException(CorruptImageError,"NegativeOrZeroImageSize");
1273       }
1274     /*
1275       Inititialize colormap.
1276     */
1277     if (AcquireImageColormap(image,image->colors,exception) == MagickFalse)
1278       {
1279         global_colormap=(unsigned char *) RelinquishMagickMemory(
1280           global_colormap);
1281         meta_image=DestroyImage(meta_image);
1282         ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1283       }
1284     if (BitSet((int) flag,0x80) == 0)
1285       {
1286         /*
1287           Use global colormap.
1288         */
1289         p=global_colormap;
1290         for (i=0; i < (ssize_t) image->colors; i++)
1291         {
1292           image->colormap[i].red=(double) ScaleCharToQuantum(*p++);
1293           image->colormap[i].green=(double) ScaleCharToQuantum(*p++);
1294           image->colormap[i].blue=(double) ScaleCharToQuantum(*p++);
1295           if (i == opacity)
1296             {
1297               image->colormap[i].alpha=(double) TransparentAlpha;
1298               image->transparent_color=image->colormap[opacity];
1299             }
1300         }
1301         image->background_color=image->colormap[MagickMin((ssize_t) background,
1302           (ssize_t) image->colors-1)];
1303       }
1304     else
1305       {
1306         unsigned char
1307           *colormap;
1308
1309         /*
1310           Read local colormap.
1311         */
1312         colormap=(unsigned char *) AcquireQuantumMemory((size_t)
1313           MagickMax(local_colors,256),3UL*sizeof(*colormap));
1314         if (colormap == (unsigned char *) NULL)
1315           {
1316             global_colormap=(unsigned char *) RelinquishMagickMemory(
1317               global_colormap);
1318             meta_image=DestroyImage(meta_image);
1319             ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1320           }
1321         (void) ResetMagickMemory(colormap,0,3*MagickMax(local_colors,256)*
1322           sizeof(*colormap));
1323         count=ReadBlob(image,(3*local_colors)*sizeof(*colormap),colormap);
1324         if (count != (ssize_t) (3*local_colors))
1325           {
1326             global_colormap=(unsigned char *) RelinquishMagickMemory(
1327               global_colormap);
1328             colormap=(unsigned char *) RelinquishMagickMemory(colormap);
1329             meta_image=DestroyImage(meta_image);
1330             ThrowReaderException(CorruptImageError,
1331               "InsufficientImageDataInFile");
1332           }
1333         p=colormap;
1334         for (i=0; i < (ssize_t) image->colors; i++)
1335         {
1336           image->colormap[i].red=(double) ScaleCharToQuantum(*p++);
1337           image->colormap[i].green=(double) ScaleCharToQuantum(*p++);
1338           image->colormap[i].blue=(double) ScaleCharToQuantum(*p++);
1339           if (i == opacity)
1340             image->colormap[i].alpha=(double) TransparentAlpha;
1341         }
1342         colormap=(unsigned char *) RelinquishMagickMemory(colormap);
1343       }
1344     if (image->gamma == 1.0)
1345       {
1346         for (i=0; i < (ssize_t) image->colors; i++)
1347           if (IsPixelInfoGray(image->colormap+i) == MagickFalse)
1348             break;
1349         (void) SetImageColorspace(image,i == (ssize_t) image->colors ?
1350           GRAYColorspace : RGBColorspace,exception);
1351       }
1352     if ((image_info->ping != MagickFalse) && (image_info->number_scenes != 0))
1353       if (image->scene >= (image_info->scene+image_info->number_scenes-1))
1354         break;
1355     status=SetImageExtent(image,image->columns,image->rows,exception);
1356     if (status == MagickFalse)
1357       {
1358         global_colormap=(unsigned char *) RelinquishMagickMemory(
1359           global_colormap);
1360         meta_image=DestroyImage(meta_image);
1361         return(DestroyImageList(image));
1362       }
1363     /*
1364       Decode image.
1365     */
1366     if (image_info->ping != MagickFalse)
1367       status=PingGIFImage(image,exception);
1368     else
1369       status=DecodeImage(image,opacity,exception);
1370     if ((image_info->ping == MagickFalse) && (status == MagickFalse))
1371       {
1372         global_colormap=(unsigned char *) RelinquishMagickMemory(
1373           global_colormap);
1374         meta_image=DestroyImage(meta_image);
1375         ThrowReaderException(CorruptImageError,"CorruptImage");
1376       }
1377     duration+=image->delay*image->iterations;
1378     if (image_info->number_scenes != 0)
1379       if (image->scene >= (image_info->scene+image_info->number_scenes-1))
1380         break;
1381     opacity=(-1);
1382     status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) image->scene-
1383       1,image->scene);
1384     if (status == MagickFalse)
1385       break;
1386   }
1387   image->duration=duration;
1388   meta_image=DestroyImage(meta_image);
1389   global_colormap=(unsigned char *) RelinquishMagickMemory(global_colormap);
1390   if ((image->columns == 0) || (image->rows == 0))
1391     ThrowReaderException(CorruptImageError,"NegativeOrZeroImageSize");
1392   (void) CloseBlob(image);
1393   return(GetFirstImageInList(image));
1394 }
1395 \f
1396 /*
1397 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1398 %                                                                             %
1399 %                                                                             %
1400 %                                                                             %
1401 %   R e g i s t e r G I F I m a g e                                           %
1402 %                                                                             %
1403 %                                                                             %
1404 %                                                                             %
1405 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1406 %
1407 %  RegisterGIFImage() adds properties for the GIF image format to
1408 %  the list of supported formats.  The properties include the image format
1409 %  tag, a method to read and/or write the format, whether the format
1410 %  supports the saving of more than one frame to the same file or blob,
1411 %  whether the format supports native in-memory I/O, and a brief
1412 %  description of the format.
1413 %
1414 %  The format of the RegisterGIFImage method is:
1415 %
1416 %      size_t RegisterGIFImage(void)
1417 %
1418 */
1419 ModuleExport size_t RegisterGIFImage(void)
1420 {
1421   MagickInfo
1422     *entry;
1423
1424   entry=AcquireMagickInfo("GIF","GIF",
1425     "CompuServe graphics interchange format");
1426   entry->decoder=(DecodeImageHandler *) ReadGIFImage;
1427   entry->encoder=(EncodeImageHandler *) WriteGIFImage;
1428   entry->magick=(IsImageFormatHandler *) IsGIF;
1429   entry->mime_type=ConstantString("image/gif");
1430   (void) RegisterMagickInfo(entry);
1431   entry=AcquireMagickInfo("GIF","GIF87",
1432     "CompuServe graphics interchange format");
1433   entry->decoder=(DecodeImageHandler *) ReadGIFImage;
1434   entry->encoder=(EncodeImageHandler *) WriteGIFImage;
1435   entry->magick=(IsImageFormatHandler *) IsGIF;
1436   entry->flags^=CoderAdjoinFlag;
1437   entry->version=ConstantString("version 87a");
1438   entry->mime_type=ConstantString("image/gif");
1439   (void) RegisterMagickInfo(entry);
1440   return(MagickImageCoderSignature);
1441 }
1442 \f
1443 /*
1444 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1445 %                                                                             %
1446 %                                                                             %
1447 %                                                                             %
1448 %   U n r e g i s t e r G I F I m a g e                                       %
1449 %                                                                             %
1450 %                                                                             %
1451 %                                                                             %
1452 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1453 %
1454 %  UnregisterGIFImage() removes format registrations made by the
1455 %  GIF module from the list of supported formats.
1456 %
1457 %  The format of the UnregisterGIFImage method is:
1458 %
1459 %      UnregisterGIFImage(void)
1460 %
1461 */
1462 ModuleExport void UnregisterGIFImage(void)
1463 {
1464   (void) UnregisterMagickInfo("GIF");
1465   (void) UnregisterMagickInfo("GIF87");
1466 }
1467 \f
1468 /*
1469 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1470 %                                                                             %
1471 %                                                                             %
1472 %                                                                             %
1473 %   W r i t e G I F I m a g e                                                 %
1474 %                                                                             %
1475 %                                                                             %
1476 %                                                                             %
1477 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1478 %
1479 %  WriteGIFImage() writes an image to a file in the Compuserve Graphics
1480 %  image format.
1481 %
1482 %  The format of the WriteGIFImage method is:
1483 %
1484 %      MagickBooleanType WriteGIFImage(const ImageInfo *image_info,
1485 %        Image *image,ExceptionInfo *exception)
1486 %
1487 %  A description of each parameter follows.
1488 %
1489 %    o image_info: the image info.
1490 %
1491 %    o image:  The image.
1492 %
1493 %    o exception: return any errors or warnings in this structure.
1494 %
1495 */
1496 static MagickBooleanType WriteGIFImage(const ImageInfo *image_info,Image *image,
1497   ExceptionInfo *exception)
1498 {
1499   int
1500     c;
1501
1502   ImageInfo
1503     *write_info;
1504
1505   MagickBooleanType
1506     status;
1507
1508   MagickOffsetType
1509     scene;
1510
1511   RectangleInfo
1512     page;
1513
1514   register ssize_t
1515     i;
1516
1517   register unsigned char
1518     *q;
1519
1520   size_t
1521     bits_per_pixel,
1522     delay,
1523     length,
1524     one;
1525
1526   ssize_t
1527     j,
1528     opacity;
1529
1530   unsigned char
1531     *colormap,
1532     *global_colormap;
1533
1534   /*
1535     Open output image file.
1536   */
1537   assert(image_info != (const ImageInfo *) NULL);
1538   assert(image_info->signature == MagickCoreSignature);
1539   assert(image != (Image *) NULL);
1540   assert(image->signature == MagickCoreSignature);
1541   if (image->debug != MagickFalse)
1542     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1543   assert(exception != (ExceptionInfo *) NULL);
1544   assert(exception->signature == MagickCoreSignature);
1545   status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
1546   if (status == MagickFalse)
1547     return(status);
1548   /*
1549     Allocate colormap.
1550   */
1551   global_colormap=(unsigned char *) AcquireQuantumMemory(768UL,
1552     sizeof(*global_colormap));
1553   colormap=(unsigned char *) AcquireQuantumMemory(768UL,sizeof(*colormap));
1554   if ((global_colormap == (unsigned char *) NULL) ||
1555       (colormap == (unsigned char *) NULL))
1556     {
1557       if (global_colormap != (unsigned char *) NULL)
1558         global_colormap=(unsigned char *) RelinquishMagickMemory(
1559           global_colormap);
1560       if (colormap != (unsigned char *) NULL)
1561         colormap=(unsigned char *) RelinquishMagickMemory(colormap);
1562       ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
1563     }
1564   for (i=0; i < 768; i++)
1565     colormap[i]=(unsigned char) 0;
1566   /*
1567     Write GIF header.
1568   */
1569   write_info=CloneImageInfo(image_info);
1570   if (LocaleCompare(write_info->magick,"GIF87") != 0)
1571     (void) WriteBlob(image,6,(unsigned char *) "GIF89a");
1572   else
1573     {
1574       (void) WriteBlob(image,6,(unsigned char *) "GIF87a");
1575       write_info->adjoin=MagickFalse;
1576     }
1577   /*
1578     Determine image bounding box.
1579   */
1580   page.width=image->columns;
1581   if (image->page.width > page.width)
1582     page.width=image->page.width;
1583   page.height=image->rows;
1584   if (image->page.height > page.height)
1585     page.height=image->page.height;
1586   page.x=image->page.x;
1587   page.y=image->page.y;
1588   (void) WriteBlobLSBShort(image,(unsigned short) page.width);
1589   (void) WriteBlobLSBShort(image,(unsigned short) page.height);
1590   /*
1591     Write images to file.
1592   */
1593   if ((write_info->adjoin != MagickFalse) &&
1594       (GetNextImageInList(image) != (Image *) NULL))
1595     write_info->interlace=NoInterlace;
1596   scene=0;
1597   one=1;
1598   do
1599   {
1600     (void) TransformImageColorspace(image,sRGBColorspace,exception);
1601     opacity=(-1);
1602     if (IsImageOpaque(image,exception) != MagickFalse)
1603       {
1604         if ((image->storage_class == DirectClass) || (image->colors > 256))
1605           (void) SetImageType(image,PaletteType,exception);
1606       }
1607     else
1608       {
1609         double
1610           alpha,
1611           beta;
1612
1613         /*
1614           Identify transparent colormap index.
1615         */
1616         if ((image->storage_class == DirectClass) || (image->colors > 256))
1617           (void) SetImageType(image,PaletteBilevelAlphaType,exception);
1618         for (i=0; i < (ssize_t) image->colors; i++)
1619           if (image->colormap[i].alpha != OpaqueAlpha)
1620             {
1621               if (opacity < 0)
1622                 {
1623                   opacity=i;
1624                   continue;
1625                 }
1626               alpha=fabs(image->colormap[i].alpha-TransparentAlpha);
1627               beta=fabs(image->colormap[opacity].alpha-TransparentAlpha);
1628               if (alpha < beta)
1629                 opacity=i;
1630             }
1631         if (opacity == -1)
1632           {
1633             (void) SetImageType(image,PaletteBilevelAlphaType,exception);
1634             for (i=0; i < (ssize_t) image->colors; i++)
1635               if (image->colormap[i].alpha != OpaqueAlpha)
1636                 {
1637                   if (opacity < 0)
1638                     {
1639                       opacity=i;
1640                       continue;
1641                     }
1642                   alpha=fabs(image->colormap[i].alpha-TransparentAlpha);
1643                   beta=fabs(image->colormap[opacity].alpha-TransparentAlpha);
1644                   if (alpha < beta)
1645                     opacity=i;
1646                 }
1647           }
1648         if (opacity >= 0)
1649           {
1650             image->colormap[opacity].red=image->transparent_color.red;
1651             image->colormap[opacity].green=image->transparent_color.green;
1652             image->colormap[opacity].blue=image->transparent_color.blue;
1653           }
1654       }
1655     if ((image->storage_class == DirectClass) || (image->colors > 256))
1656       ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
1657     for (bits_per_pixel=1; bits_per_pixel < 8; bits_per_pixel++)
1658       if ((one << bits_per_pixel) >= image->colors)
1659         break;
1660     q=colormap;
1661     for (i=0; i < (ssize_t) image->colors; i++)
1662     {
1663       *q++=ScaleQuantumToChar(ClampToQuantum(image->colormap[i].red));
1664       *q++=ScaleQuantumToChar(ClampToQuantum(image->colormap[i].green));
1665       *q++=ScaleQuantumToChar(ClampToQuantum(image->colormap[i].blue));
1666     }
1667     for ( ; i < (ssize_t) (one << bits_per_pixel); i++)
1668     {
1669       *q++=(unsigned char) 0x0;
1670       *q++=(unsigned char) 0x0;
1671       *q++=(unsigned char) 0x0;
1672     }
1673     if ((GetPreviousImageInList(image) == (Image *) NULL) ||
1674         (write_info->adjoin == MagickFalse))
1675       {
1676         /*
1677           Write global colormap.
1678         */
1679         c=0x80;
1680         c|=(8-1) << 4;  /* color resolution */
1681         c|=(bits_per_pixel-1);   /* size of global colormap */
1682         (void) WriteBlobByte(image,(unsigned char) c);
1683         for (j=0; j < (ssize_t) image->colors; j++)
1684           if (IsPixelInfoEquivalent(&image->background_color,image->colormap+j))
1685             break;
1686         (void) WriteBlobByte(image,(unsigned char)
1687           (j == (ssize_t) image->colors ? 0 : j));  /* background color */
1688         (void) WriteBlobByte(image,(unsigned char) 0x00);  /* reserved */
1689         length=(size_t) (3*(one << bits_per_pixel));
1690         (void) WriteBlob(image,length,colormap);
1691         for (j=0; j < 768; j++)
1692           global_colormap[j]=colormap[j];
1693       }
1694     if (LocaleCompare(write_info->magick,"GIF87") != 0)
1695       {
1696         const char
1697           *value;
1698
1699         /*
1700           Write graphics control extension.
1701         */
1702         (void) WriteBlobByte(image,(unsigned char) 0x21);
1703         (void) WriteBlobByte(image,(unsigned char) 0xf9);
1704         (void) WriteBlobByte(image,(unsigned char) 0x04);
1705         c=image->dispose << 2;
1706         if (opacity >= 0)
1707           c|=0x01;
1708         (void) WriteBlobByte(image,(unsigned char) c);
1709         delay=(size_t) (100*image->delay/MagickMax((size_t)
1710           image->ticks_per_second,1));
1711         (void) WriteBlobLSBShort(image,(unsigned short) delay);
1712         (void) WriteBlobByte(image,(unsigned char) (opacity >= 0 ? opacity :
1713           0));
1714         (void) WriteBlobByte(image,(unsigned char) 0x00);
1715         value=GetImageProperty(image,"comment",exception);
1716         if ((LocaleCompare(write_info->magick,"GIF87") != 0) &&
1717             (value != (const char *) NULL))
1718           {
1719             register const char
1720               *p;
1721
1722             size_t
1723               count;
1724
1725             /*
1726               Write comment extension.
1727             */
1728             (void) WriteBlobByte(image,(unsigned char) 0x21);
1729             (void) WriteBlobByte(image,(unsigned char) 0xfe);
1730             for (p=value; *p != '\0'; )
1731             {
1732               count=MagickMin(strlen(p),255);
1733               (void) WriteBlobByte(image,(unsigned char) count);
1734               for (i=0; i < (ssize_t) count; i++)
1735                 (void) WriteBlobByte(image,(unsigned char) *p++);
1736             }
1737             (void) WriteBlobByte(image,(unsigned char) 0x00);
1738           }
1739         if ((GetPreviousImageInList(image) == (Image *) NULL) &&
1740             (GetNextImageInList(image) != (Image *) NULL) &&
1741             (image->iterations != 1))
1742           {
1743             /*
1744               Write Netscape Loop extension.
1745             */
1746             (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1747                "  Writing GIF Extension %s","NETSCAPE2.0");
1748             (void) WriteBlobByte(image,(unsigned char) 0x21);
1749             (void) WriteBlobByte(image,(unsigned char) 0xff);
1750             (void) WriteBlobByte(image,(unsigned char) 0x0b);
1751             (void) WriteBlob(image,11,(unsigned char *) "NETSCAPE2.0");
1752             (void) WriteBlobByte(image,(unsigned char) 0x03);
1753             (void) WriteBlobByte(image,(unsigned char) 0x01);
1754             (void) WriteBlobLSBShort(image,(unsigned short) (image->iterations ?
1755               image->iterations-1 : 0));
1756             (void) WriteBlobByte(image,(unsigned char) 0x00);
1757           }
1758         if ((image->gamma != 1.0f/2.2f))
1759           {
1760             char
1761               attributes[MagickPathExtent];
1762
1763             ssize_t
1764               count;
1765
1766             /*
1767               Write ImageMagick extension.
1768             */
1769             (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1770                "  Writing GIF Extension %s","ImageMagick");
1771             (void) WriteBlobByte(image,(unsigned char) 0x21);
1772             (void) WriteBlobByte(image,(unsigned char) 0xff);
1773             (void) WriteBlobByte(image,(unsigned char) 0x0b);
1774             (void) WriteBlob(image,11,(unsigned char *) "ImageMagick");
1775             count=FormatLocaleString(attributes,MagickPathExtent,"gamma=%g",
1776               image->gamma);
1777             (void) WriteBlobByte(image,(unsigned char) count);
1778             (void) WriteBlob(image,(size_t) count,(unsigned char *) attributes);
1779             (void) WriteBlobByte(image,(unsigned char) 0x00);
1780           }
1781         ResetImageProfileIterator(image);
1782         for ( ; ; )
1783         {
1784           char
1785             *name;
1786
1787           const StringInfo
1788             *profile;
1789
1790           name=GetNextImageProfile(image);
1791           if (name == (const char *) NULL)
1792             break;
1793           profile=GetImageProfile(image,name);
1794           if (profile != (StringInfo *) NULL)
1795           {
1796             if ((LocaleCompare(name,"ICC") == 0) ||
1797                 (LocaleCompare(name,"ICM") == 0) ||
1798                 (LocaleCompare(name,"IPTC") == 0) ||
1799                 (LocaleCompare(name,"8BIM") == 0) ||
1800                 (LocaleNCompare(name,"gif:",4) == 0))
1801             {
1802                ssize_t
1803                  offset;
1804
1805                unsigned char
1806                  *datum;
1807
1808                datum=GetStringInfoDatum(profile);
1809                length=GetStringInfoLength(profile);
1810                (void) WriteBlobByte(image,(unsigned char) 0x21);
1811                (void) WriteBlobByte(image,(unsigned char) 0xff);
1812                (void) WriteBlobByte(image,(unsigned char) 0x0b);
1813                if ((LocaleCompare(name,"ICC") == 0) ||
1814                    (LocaleCompare(name,"ICM") == 0))
1815                  {
1816                    /*
1817                      Write ICC extension.
1818                    */
1819                    (void) WriteBlob(image,11,(unsigned char *) "ICCRGBG1012");
1820                    (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1821                      "  Writing GIF Extension %s","ICCRGBG1012");
1822                  }
1823                else
1824                  if ((LocaleCompare(name,"IPTC") == 0))
1825                    {
1826                      /*
1827                        Write IPTC extension.
1828                      */
1829                      (void) WriteBlob(image,11,(unsigned char *) "MGKIPTC0000");
1830                      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1831                        "  Writing GIF Extension %s","MGKIPTC0000");
1832                    }
1833                  else
1834                    if ((LocaleCompare(name,"8BIM") == 0))
1835                      {
1836                        /*
1837                          Write 8BIM extension.
1838                        */
1839                         (void) WriteBlob(image,11,(unsigned char *)
1840                           "MGK8BIM0000");
1841                         (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1842                           "  Writing GIF Extension %s","MGK8BIM0000");
1843                      }
1844                    else
1845                      {
1846                        char
1847                          extension[MagickPathExtent];
1848
1849                        /*
1850                          Write generic extension.
1851                        */
1852                        (void) CopyMagickString(extension,name+4,
1853                          sizeof(extension));
1854                        (void) WriteBlob(image,11,(unsigned char *) extension);
1855                        (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1856                          "  Writing GIF Extension %s",name);
1857                      }
1858                offset=0;
1859                while ((ssize_t) length > offset)
1860                {
1861                  size_t
1862                    block_length;
1863
1864                  if ((length-offset) < 255)
1865                    block_length=length-offset;
1866                  else
1867                    block_length=255;
1868                  (void) WriteBlobByte(image,(unsigned char) block_length);
1869                  (void) WriteBlob(image,(size_t) block_length,datum+offset);
1870                  offset+=(ssize_t) block_length;
1871                }
1872                (void) WriteBlobByte(image,(unsigned char) 0x00);
1873             }
1874           }
1875         }
1876       }
1877     (void) WriteBlobByte(image,',');  /* image separator */
1878     /*
1879       Write the image header.
1880     */
1881     page.x=image->page.x;
1882     page.y=image->page.y;
1883     if ((image->page.width != 0) && (image->page.height != 0))
1884       page=image->page;
1885     (void) WriteBlobLSBShort(image,(unsigned short) (page.x < 0 ? 0 : page.x));
1886     (void) WriteBlobLSBShort(image,(unsigned short) (page.y < 0 ? 0 : page.y));
1887     (void) WriteBlobLSBShort(image,(unsigned short) image->columns);
1888     (void) WriteBlobLSBShort(image,(unsigned short) image->rows);
1889     c=0x00;
1890     if (write_info->interlace != NoInterlace)
1891       c|=0x40;  /* pixel data is interlaced */
1892     for (j=0; j < (ssize_t) (3*image->colors); j++)
1893       if (colormap[j] != global_colormap[j])
1894         break;
1895     if (j == (ssize_t) (3*image->colors))
1896       (void) WriteBlobByte(image,(unsigned char) c);
1897     else
1898       {
1899         c|=0x80;
1900         c|=(bits_per_pixel-1);   /* size of local colormap */
1901         (void) WriteBlobByte(image,(unsigned char) c);
1902         length=(size_t) (3*(one << bits_per_pixel));
1903         (void) WriteBlob(image,length,colormap);
1904       }
1905     /*
1906       Write the image data.
1907     */
1908     c=(int) MagickMax(bits_per_pixel,2);
1909     (void) WriteBlobByte(image,(unsigned char) c);
1910     status=EncodeImage(write_info,image,(size_t) MagickMax(bits_per_pixel,2)+1,
1911       exception);
1912     if (status == MagickFalse)
1913       {
1914         global_colormap=(unsigned char *) RelinquishMagickMemory(
1915           global_colormap);
1916         colormap=(unsigned char *) RelinquishMagickMemory(colormap);
1917         write_info=DestroyImageInfo(write_info);
1918         ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
1919       }
1920     (void) WriteBlobByte(image,(unsigned char) 0x00);
1921     if (GetNextImageInList(image) == (Image *) NULL)
1922       break;
1923     image=SyncNextImageInList(image);
1924     scene++;
1925     status=SetImageProgress(image,SaveImagesTag,scene,
1926       GetImageListLength(image));
1927     if (status == MagickFalse)
1928       break;
1929   } while (write_info->adjoin != MagickFalse);
1930   (void) WriteBlobByte(image,';'); /* terminator */
1931   global_colormap=(unsigned char *) RelinquishMagickMemory(global_colormap);
1932   colormap=(unsigned char *) RelinquishMagickMemory(colormap);
1933   write_info=DestroyImageInfo(write_info);
1934   (void) CloseBlob(image);
1935   return(MagickTrue);
1936 }