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