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