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