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