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