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