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