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