1 /****************************************************************************** 2 3 egif_lib.c - GIF encoding 4 5 The functions here and in dgif_lib.c are partitioned carefully so that 6 if you only require one of read and write capability, only one of these 7 two modules will be linked. Preserve this property! 8 9 *****************************************************************************/ 10 11 #include <unistd.h> 12 #include <stdint.h> 13 #include <stdlib.h> 14 #include <stdio.h> 15 #include <string.h> 16 #include <fcntl.h> 17 18 #ifdef _WIN32 19 #include <io.h> 20 #else 21 #include <sys/types.h> 22 #endif /* _WIN32 */ 23 #include <sys/stat.h> 24 25 #include "gif_lib.h" 26 #include "gif_lib_private.h" 27 28 /* Masks given codes to BitsPerPixel, to make sure all codes are in range: */ 29 /*@+charint@*/ 30 static const GifPixelType CodeMask[] = { 31 0x00, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff 32 }; 33 /*@-charint@*/ 34 35 static int EGifPutWord(int Word, GifFileType * GifFile); 36 static int EGifSetupCompress(GifFileType * GifFile); 37 static int EGifCompressLine(GifFileType * GifFile, GifPixelType * Line, 38 int LineLen); 39 static int EGifCompressOutput(GifFileType * GifFile, int Code); 40 static int EGifBufferedOutput(GifFileType * GifFile, GifByteType * Buf, 41 int c); 42 43 /* extract bytes from an unsigned word */ 44 #define LOBYTE(x) ((x) & 0xff) 45 #define HIBYTE(x) (((x) >> 8) & 0xff) 46 47 /****************************************************************************** 48 Open a new GIF file for write, specified by name. If TestExistance then 49 if the file exists this routines fails (returns NULL). 50 Returns a dynamically allocated GifFileType pointer which serves as the GIF 51 info record. The Error member is cleared if successful. 52 ******************************************************************************/ 53 GifFileType * 54 EGifOpenFileName(const char *FileName, const bool TestExistence, int *Error) 55 { 56 57 int FileHandle; 58 GifFileType *GifFile; 59 60 if (TestExistence) 61 /* android-changed: changed "S_IREAD | S_IWRITE" to "S_IRUSR | S_IWUSR" */ 62 FileHandle = open(FileName, O_WRONLY | O_CREAT | O_EXCL, 63 S_IRUSR | S_IWUSR); 64 else 65 /* android-changed: changed "S_IREAD | S_IWRITE" to "S_IRUSR | S_IWUSR" */ 66 FileHandle = open(FileName, O_WRONLY | O_CREAT | O_TRUNC, 67 S_IRUSR | S_IWUSR); 68 69 if (FileHandle == -1) { 70 if (Error != NULL) 71 *Error = E_GIF_ERR_OPEN_FAILED; 72 return NULL; 73 } 74 GifFile = EGifOpenFileHandle(FileHandle, Error); 75 if (GifFile == (GifFileType *) NULL) 76 (void)close(FileHandle); 77 return GifFile; 78 } 79 80 /****************************************************************************** 81 Update a new GIF file, given its file handle, which must be opened for 82 write in binary mode. 83 Returns dynamically allocated a GifFileType pointer which serves as the GIF 84 info record. 85 Only fails on a memory allocation error. 86 ******************************************************************************/ 87 GifFileType * 88 EGifOpenFileHandle(const int FileHandle, int *Error) 89 { 90 GifFileType *GifFile; 91 GifFilePrivateType *Private; 92 FILE *f; 93 94 GifFile = (GifFileType *) malloc(sizeof(GifFileType)); 95 if (GifFile == NULL) { 96 return NULL; 97 } 98 99 memset(GifFile, '\0', sizeof(GifFileType)); 100 101 Private = (GifFilePrivateType *)malloc(sizeof(GifFilePrivateType)); 102 if (Private == NULL) { 103 free(GifFile); 104 if (Error != NULL) 105 *Error = E_GIF_ERR_NOT_ENOUGH_MEM; 106 return NULL; 107 } 108 /*@i1@*/memset(Private, '\0', sizeof(GifFilePrivateType)); 109 if ((Private->HashTable = _InitHashTable()) == NULL) { 110 free(GifFile); 111 free(Private); 112 if (Error != NULL) 113 *Error = E_GIF_ERR_NOT_ENOUGH_MEM; 114 return NULL; 115 } 116 117 #ifdef _WIN32 118 _setmode(FileHandle, O_BINARY); /* Make sure it is in binary mode. */ 119 #endif /* _WIN32 */ 120 121 f = fdopen(FileHandle, "wb"); /* Make it into a stream: */ 122 123 GifFile->Private = (void *)Private; 124 Private->FileHandle = FileHandle; 125 Private->File = f; 126 Private->FileState = FILE_STATE_WRITE; 127 Private->gif89 = false; 128 129 Private->Write = (OutputFunc) 0; /* No user write routine (MRB) */ 130 GifFile->UserData = (void *)NULL; /* No user write handle (MRB) */ 131 132 GifFile->Error = 0; 133 134 return GifFile; 135 } 136 137 /****************************************************************************** 138 Output constructor that takes user supplied output function. 139 Basically just a copy of EGifOpenFileHandle. (MRB) 140 ******************************************************************************/ 141 GifFileType * 142 EGifOpen(void *userData, OutputFunc writeFunc, int *Error) 143 { 144 GifFileType *GifFile; 145 GifFilePrivateType *Private; 146 147 GifFile = (GifFileType *)malloc(sizeof(GifFileType)); 148 if (GifFile == NULL) { 149 if (Error != NULL) 150 *Error = E_GIF_ERR_NOT_ENOUGH_MEM; 151 return NULL; 152 } 153 154 memset(GifFile, '\0', sizeof(GifFileType)); 155 156 Private = (GifFilePrivateType *)malloc(sizeof(GifFilePrivateType)); 157 if (Private == NULL) { 158 free(GifFile); 159 if (Error != NULL) 160 *Error = E_GIF_ERR_NOT_ENOUGH_MEM; 161 return NULL; 162 } 163 164 memset(Private, '\0', sizeof(GifFilePrivateType)); 165 166 Private->HashTable = _InitHashTable(); 167 if (Private->HashTable == NULL) { 168 free (GifFile); 169 free (Private); 170 if (Error != NULL) 171 *Error = E_GIF_ERR_NOT_ENOUGH_MEM; 172 return NULL; 173 } 174 175 GifFile->Private = (void *)Private; 176 Private->FileHandle = 0; 177 Private->File = (FILE *) 0; 178 Private->FileState = FILE_STATE_WRITE; 179 180 Private->Write = writeFunc; /* User write routine (MRB) */ 181 GifFile->UserData = userData; /* User write handle (MRB) */ 182 183 Private->gif89 = false; /* initially, write GIF87 */ 184 185 GifFile->Error = 0; 186 187 return GifFile; 188 } 189 190 /****************************************************************************** 191 Routine to compute the GIF version that will be written on output. 192 ******************************************************************************/ 193 const char * 194 EGifGetGifVersion(GifFileType *GifFile) 195 { 196 GifFilePrivateType *Private = (GifFilePrivateType *) GifFile->Private; 197 int i, j; 198 199 /* 200 * Bulletproofing - always write GIF89 if we need to. 201 * Note, we don't clear the gif89 flag here because 202 * users of the sequential API might have called EGifSetGifVersion() 203 * in order to set that flag. 204 */ 205 for (i = 0; i < GifFile->ImageCount; i++) { 206 for (j = 0; j < GifFile->SavedImages[i].ExtensionBlockCount; j++) { 207 int function = 208 GifFile->SavedImages[i].ExtensionBlocks[j].Function; 209 210 if (function == COMMENT_EXT_FUNC_CODE 211 || function == GRAPHICS_EXT_FUNC_CODE 212 || function == PLAINTEXT_EXT_FUNC_CODE 213 || function == APPLICATION_EXT_FUNC_CODE) 214 Private->gif89 = true; 215 } 216 } 217 for (i = 0; i < GifFile->ExtensionBlockCount; i++) { 218 int function = GifFile->ExtensionBlocks[i].Function; 219 220 if (function == COMMENT_EXT_FUNC_CODE 221 || function == GRAPHICS_EXT_FUNC_CODE 222 || function == PLAINTEXT_EXT_FUNC_CODE 223 || function == APPLICATION_EXT_FUNC_CODE) 224 Private->gif89 = true; 225 } 226 227 if (Private->gif89) 228 return GIF89_STAMP; 229 else 230 return GIF87_STAMP; 231 } 232 233 /****************************************************************************** 234 Set the GIF version. In the extremely unlikely event that there is ever 235 another version, replace the bool argument with an enum in which the 236 GIF87 value is 0 (numerically the same as bool false) and the GIF89 value 237 is 1 (numerically the same as bool true). That way we'll even preserve 238 object-file compatibility! 239 ******************************************************************************/ 240 void EGifSetGifVersion(GifFileType *GifFile, const bool gif89) 241 { 242 GifFilePrivateType *Private = (GifFilePrivateType *) GifFile->Private; 243 244 Private->gif89 = gif89; 245 } 246 247 /****************************************************************************** 248 All writes to the GIF should go through this. 249 ******************************************************************************/ 250 static int InternalWrite(GifFileType *GifFileOut, 251 const unsigned char *buf, size_t len) 252 { 253 GifFilePrivateType *Private = (GifFilePrivateType*)GifFileOut->Private; 254 if (Private->Write) 255 return Private->Write(GifFileOut,buf,len); 256 else 257 return fwrite(buf, 1, len, Private->File); 258 } 259 260 /****************************************************************************** 261 This routine should be called before any other EGif calls, immediately 262 following the GIF file opening. 263 ******************************************************************************/ 264 int 265 EGifPutScreenDesc(GifFileType *GifFile, 266 const int Width, 267 const int Height, 268 const int ColorRes, 269 const int BackGround, 270 const ColorMapObject *ColorMap) 271 { 272 GifByteType Buf[3]; 273 GifFilePrivateType *Private = (GifFilePrivateType *) GifFile->Private; 274 const char *write_version; 275 276 if (Private->FileState & FILE_STATE_SCREEN) { 277 /* If already has screen descriptor - something is wrong! */ 278 GifFile->Error = E_GIF_ERR_HAS_SCRN_DSCR; 279 return GIF_ERROR; 280 } 281 if (!IS_WRITEABLE(Private)) { 282 /* This file was NOT open for writing: */ 283 GifFile->Error = E_GIF_ERR_NOT_WRITEABLE; 284 return GIF_ERROR; 285 } 286 287 write_version = EGifGetGifVersion(GifFile); 288 289 /* First write the version prefix into the file. */ 290 if (InternalWrite(GifFile, (unsigned char *)write_version, 291 strlen(write_version)) != strlen(write_version)) { 292 GifFile->Error = E_GIF_ERR_WRITE_FAILED; 293 return GIF_ERROR; 294 } 295 296 GifFile->SWidth = Width; 297 GifFile->SHeight = Height; 298 GifFile->SColorResolution = ColorRes; 299 GifFile->SBackGroundColor = BackGround; 300 if (ColorMap) { 301 GifFile->SColorMap = GifMakeMapObject(ColorMap->ColorCount, 302 ColorMap->Colors); 303 if (GifFile->SColorMap == NULL) { 304 GifFile->Error = E_GIF_ERR_NOT_ENOUGH_MEM; 305 return GIF_ERROR; 306 } 307 } else 308 GifFile->SColorMap = NULL; 309 310 /* 311 * Put the logical screen descriptor into the file: 312 */ 313 /* Logical Screen Descriptor: Dimensions */ 314 (void)EGifPutWord(Width, GifFile); 315 (void)EGifPutWord(Height, GifFile); 316 317 /* Logical Screen Descriptor: Packed Fields */ 318 /* Note: We have actual size of the color table default to the largest 319 * possible size (7+1 == 8 bits) because the decoder can use it to decide 320 * how to display the files. 321 */ 322 Buf[0] = (ColorMap ? 0x80 : 0x00) | /* Yes/no global colormap */ 323 ((ColorRes - 1) << 4) | /* Bits allocated to each primary color */ 324 (ColorMap ? ColorMap->BitsPerPixel - 1 : 0x07 ); /* Actual size of the 325 color table. */ 326 if (ColorMap != NULL && ColorMap->SortFlag) 327 Buf[0] |= 0x08; 328 Buf[1] = BackGround; /* Index into the ColorTable for background color */ 329 Buf[2] = GifFile->AspectByte; /* Pixel Aspect Ratio */ 330 InternalWrite(GifFile, Buf, 3); 331 332 /* If we have Global color map - dump it also: */ 333 if (ColorMap != NULL) { 334 int i; 335 for (i = 0; i < ColorMap->ColorCount; i++) { 336 /* Put the ColorMap out also: */ 337 Buf[0] = ColorMap->Colors[i].Red; 338 Buf[1] = ColorMap->Colors[i].Green; 339 Buf[2] = ColorMap->Colors[i].Blue; 340 if (InternalWrite(GifFile, Buf, 3) != 3) { 341 GifFile->Error = E_GIF_ERR_WRITE_FAILED; 342 return GIF_ERROR; 343 } 344 } 345 } 346 347 /* Mark this file as has screen descriptor, and no pixel written yet: */ 348 Private->FileState |= FILE_STATE_SCREEN; 349 350 return GIF_OK; 351 } 352 353 /****************************************************************************** 354 This routine should be called before any attempt to dump an image - any 355 call to any of the pixel dump routines. 356 ******************************************************************************/ 357 int 358 EGifPutImageDesc(GifFileType *GifFile, 359 const int Left, 360 const int Top, 361 const int Width, 362 const int Height, 363 const bool Interlace, 364 const ColorMapObject *ColorMap) 365 { 366 GifByteType Buf[3]; 367 GifFilePrivateType *Private = (GifFilePrivateType *)GifFile->Private; 368 369 if (Private->FileState & FILE_STATE_IMAGE && 370 Private->PixelCount > 0xffff0000UL) { 371 /* If already has active image descriptor - something is wrong! */ 372 GifFile->Error = E_GIF_ERR_HAS_IMAG_DSCR; 373 return GIF_ERROR; 374 } 375 if (!IS_WRITEABLE(Private)) { 376 /* This file was NOT open for writing: */ 377 GifFile->Error = E_GIF_ERR_NOT_WRITEABLE; 378 return GIF_ERROR; 379 } 380 GifFile->Image.Left = Left; 381 GifFile->Image.Top = Top; 382 GifFile->Image.Width = Width; 383 GifFile->Image.Height = Height; 384 GifFile->Image.Interlace = Interlace; 385 if (ColorMap) { 386 if (GifFile->Image.ColorMap != NULL) { 387 GifFreeMapObject(GifFile->Image.ColorMap); 388 GifFile->Image.ColorMap = NULL; 389 } 390 GifFile->Image.ColorMap = GifMakeMapObject(ColorMap->ColorCount, 391 ColorMap->Colors); 392 if (GifFile->Image.ColorMap == NULL) { 393 GifFile->Error = E_GIF_ERR_NOT_ENOUGH_MEM; 394 return GIF_ERROR; 395 } 396 } else { 397 GifFile->Image.ColorMap = NULL; 398 } 399 400 /* Put the image descriptor into the file: */ 401 Buf[0] = DESCRIPTOR_INTRODUCER; /* Image separator character. */ 402 InternalWrite(GifFile, Buf, 1); 403 (void)EGifPutWord(Left, GifFile); 404 (void)EGifPutWord(Top, GifFile); 405 (void)EGifPutWord(Width, GifFile); 406 (void)EGifPutWord(Height, GifFile); 407 Buf[0] = (ColorMap ? 0x80 : 0x00) | 408 (Interlace ? 0x40 : 0x00) | 409 (ColorMap ? ColorMap->BitsPerPixel - 1 : 0); 410 InternalWrite(GifFile, Buf, 1); 411 412 /* If we have Global color map - dump it also: */ 413 if (ColorMap != NULL) { 414 int i; 415 for (i = 0; i < ColorMap->ColorCount; i++) { 416 /* Put the ColorMap out also: */ 417 Buf[0] = ColorMap->Colors[i].Red; 418 Buf[1] = ColorMap->Colors[i].Green; 419 Buf[2] = ColorMap->Colors[i].Blue; 420 if (InternalWrite(GifFile, Buf, 3) != 3) { 421 GifFile->Error = E_GIF_ERR_WRITE_FAILED; 422 return GIF_ERROR; 423 } 424 } 425 } 426 if (GifFile->SColorMap == NULL && GifFile->Image.ColorMap == NULL) { 427 GifFile->Error = E_GIF_ERR_NO_COLOR_MAP; 428 return GIF_ERROR; 429 } 430 431 /* Mark this file as has screen descriptor: */ 432 Private->FileState |= FILE_STATE_IMAGE; 433 Private->PixelCount = (long)Width *(long)Height; 434 435 /* Reset compress algorithm parameters. */ 436 (void)EGifSetupCompress(GifFile); 437 438 return GIF_OK; 439 } 440 441 /****************************************************************************** 442 Put one full scanned line (Line) of length LineLen into GIF file. 443 ******************************************************************************/ 444 int 445 EGifPutLine(GifFileType * GifFile, GifPixelType *Line, int LineLen) 446 { 447 int i; 448 GifPixelType Mask; 449 GifFilePrivateType *Private = (GifFilePrivateType *) GifFile->Private; 450 451 if (!IS_WRITEABLE(Private)) { 452 /* This file was NOT open for writing: */ 453 GifFile->Error = E_GIF_ERR_NOT_WRITEABLE; 454 return GIF_ERROR; 455 } 456 457 if (!LineLen) 458 LineLen = GifFile->Image.Width; 459 if (Private->PixelCount < (unsigned)LineLen) { 460 GifFile->Error = E_GIF_ERR_DATA_TOO_BIG; 461 return GIF_ERROR; 462 } 463 Private->PixelCount -= LineLen; 464 465 /* Make sure the codes are not out of bit range, as we might generate 466 * wrong code (because of overflow when we combine them) in this case: */ 467 Mask = CodeMask[Private->BitsPerPixel]; 468 for (i = 0; i < LineLen; i++) 469 Line[i] &= Mask; 470 471 return EGifCompressLine(GifFile, Line, LineLen); 472 } 473 474 /****************************************************************************** 475 Put one pixel (Pixel) into GIF file. 476 ******************************************************************************/ 477 int 478 EGifPutPixel(GifFileType *GifFile, GifPixelType Pixel) 479 { 480 GifFilePrivateType *Private = (GifFilePrivateType *)GifFile->Private; 481 482 if (!IS_WRITEABLE(Private)) { 483 /* This file was NOT open for writing: */ 484 GifFile->Error = E_GIF_ERR_NOT_WRITEABLE; 485 return GIF_ERROR; 486 } 487 488 if (Private->PixelCount == 0) { 489 GifFile->Error = E_GIF_ERR_DATA_TOO_BIG; 490 return GIF_ERROR; 491 } 492 --Private->PixelCount; 493 494 /* Make sure the code is not out of bit range, as we might generate 495 * wrong code (because of overflow when we combine them) in this case: */ 496 Pixel &= CodeMask[Private->BitsPerPixel]; 497 498 return EGifCompressLine(GifFile, &Pixel, 1); 499 } 500 501 /****************************************************************************** 502 Put a comment into GIF file using the GIF89 comment extension block. 503 ******************************************************************************/ 504 int 505 EGifPutComment(GifFileType *GifFile, const char *Comment) 506 { 507 unsigned int length; 508 char *buf; 509 510 length = strlen(Comment); 511 if (length <= 255) { 512 return EGifPutExtension(GifFile, COMMENT_EXT_FUNC_CODE, 513 length, Comment); 514 } else { 515 buf = (char *)Comment; 516 if (EGifPutExtensionLeader(GifFile, COMMENT_EXT_FUNC_CODE) 517 == GIF_ERROR) { 518 return GIF_ERROR; 519 } 520 521 /* Break the comment into 255 byte sub blocks */ 522 while (length > 255) { 523 if (EGifPutExtensionBlock(GifFile, 255, buf) == GIF_ERROR) { 524 return GIF_ERROR; 525 } 526 buf = buf + 255; 527 length -= 255; 528 } 529 /* Output any partial block and the clear code. */ 530 if (length > 0) { 531 if (EGifPutExtensionBlock(GifFile, length, buf) == GIF_ERROR) { 532 return GIF_ERROR; 533 } 534 } 535 if (EGifPutExtensionTrailer(GifFile) == GIF_ERROR) { 536 return GIF_ERROR; 537 } 538 } 539 return GIF_OK; 540 } 541 542 /****************************************************************************** 543 Begin an extension block (see GIF manual). More 544 extensions can be dumped using EGifPutExtensionBlock until 545 EGifPutExtensionTrailer is invoked. 546 ******************************************************************************/ 547 int 548 EGifPutExtensionLeader(GifFileType *GifFile, const int ExtCode) 549 { 550 GifByteType Buf[3]; 551 GifFilePrivateType *Private = (GifFilePrivateType *)GifFile->Private; 552 553 if (!IS_WRITEABLE(Private)) { 554 /* This file was NOT open for writing: */ 555 GifFile->Error = E_GIF_ERR_NOT_WRITEABLE; 556 return GIF_ERROR; 557 } 558 559 Buf[0] = EXTENSION_INTRODUCER; 560 Buf[1] = ExtCode; 561 InternalWrite(GifFile, Buf, 2); 562 563 return GIF_OK; 564 } 565 566 /****************************************************************************** 567 Put extension block data (see GIF manual) into a GIF file. 568 ******************************************************************************/ 569 int 570 EGifPutExtensionBlock(GifFileType *GifFile, 571 const int ExtLen, 572 const void *Extension) 573 { 574 GifByteType Buf; 575 GifFilePrivateType *Private = (GifFilePrivateType *)GifFile->Private; 576 577 if (!IS_WRITEABLE(Private)) { 578 /* This file was NOT open for writing: */ 579 GifFile->Error = E_GIF_ERR_NOT_WRITEABLE; 580 return GIF_ERROR; 581 } 582 583 Buf = ExtLen; 584 InternalWrite(GifFile, &Buf, 1); 585 InternalWrite(GifFile, Extension, ExtLen); 586 587 return GIF_OK; 588 } 589 590 /****************************************************************************** 591 Put a terminating block (see GIF manual) into a GIF file. 592 ******************************************************************************/ 593 int 594 EGifPutExtensionTrailer(GifFileType *GifFile) { 595 596 GifByteType Buf; 597 GifFilePrivateType *Private = (GifFilePrivateType *)GifFile->Private; 598 599 if (!IS_WRITEABLE(Private)) { 600 /* This file was NOT open for writing: */ 601 GifFile->Error = E_GIF_ERR_NOT_WRITEABLE; 602 return GIF_ERROR; 603 } 604 605 /* Write the block terminator */ 606 Buf = 0; 607 InternalWrite(GifFile, &Buf, 1); 608 609 return GIF_OK; 610 } 611 612 /****************************************************************************** 613 Put an extension block (see GIF manual) into a GIF file. 614 Warning: This function is only useful for Extension blocks that have at 615 most one subblock. Extensions with more than one subblock need to use the 616 EGifPutExtension{Leader,Block,Trailer} functions instead. 617 ******************************************************************************/ 618 int 619 EGifPutExtension(GifFileType *GifFile, 620 const int ExtCode, 621 const int ExtLen, 622 const void *Extension) { 623 624 GifByteType Buf[3]; 625 GifFilePrivateType *Private = (GifFilePrivateType *)GifFile->Private; 626 627 if (!IS_WRITEABLE(Private)) { 628 /* This file was NOT open for writing: */ 629 GifFile->Error = E_GIF_ERR_NOT_WRITEABLE; 630 return GIF_ERROR; 631 } 632 633 if (ExtCode == 0) 634 InternalWrite(GifFile, (GifByteType *)&ExtLen, 1); 635 else { 636 Buf[0] = EXTENSION_INTRODUCER; 637 Buf[1] = ExtCode; /* Extension Label */ 638 Buf[2] = ExtLen; /* Extension length */ 639 InternalWrite(GifFile, Buf, 3); 640 } 641 InternalWrite(GifFile, Extension, ExtLen); 642 Buf[0] = 0; 643 InternalWrite(GifFile, Buf, 1); 644 645 return GIF_OK; 646 } 647 648 /****************************************************************************** 649 Render a Graphics Control Block as raw extension data 650 ******************************************************************************/ 651 652 size_t EGifGCBToExtension(const GraphicsControlBlock *GCB, 653 GifByteType *GifExtension) 654 { 655 GifExtension[0] = 0; 656 GifExtension[0] |= (GCB->TransparentColor == NO_TRANSPARENT_COLOR) ? 0x00 : 0x01; 657 GifExtension[0] |= GCB->UserInputFlag ? 0x02 : 0x00; 658 GifExtension[0] |= ((GCB->DisposalMode & 0x07) << 2); 659 GifExtension[1] = LOBYTE(GCB->DelayTime); 660 GifExtension[2] = HIBYTE(GCB->DelayTime); 661 GifExtension[3] = (char)GCB->TransparentColor; 662 return 4; 663 } 664 665 /****************************************************************************** 666 Replace the Graphics Control Block for a saved image, if it exists. 667 ******************************************************************************/ 668 669 int EGifGCBToSavedExtension(const GraphicsControlBlock *GCB, 670 GifFileType *GifFile, int ImageIndex) 671 { 672 int i; 673 size_t Len; 674 GifByteType buf[sizeof(GraphicsControlBlock)]; /* a bit dodgy... */ 675 676 if (ImageIndex < 0 || ImageIndex > GifFile->ImageCount - 1) 677 return GIF_ERROR; 678 679 for (i = 0; i < GifFile->SavedImages[ImageIndex].ExtensionBlockCount; i++) { 680 ExtensionBlock *ep = &GifFile->SavedImages[ImageIndex].ExtensionBlocks[i]; 681 if (ep->Function == GRAPHICS_EXT_FUNC_CODE) { 682 EGifGCBToExtension(GCB, ep->Bytes); 683 return GIF_OK; 684 } 685 } 686 687 Len = EGifGCBToExtension(GCB, (GifByteType *)buf); 688 if (GifAddExtensionBlock(&GifFile->SavedImages[ImageIndex].ExtensionBlockCount, 689 &GifFile->SavedImages[ImageIndex].ExtensionBlocks, 690 GRAPHICS_EXT_FUNC_CODE, 691 Len, 692 (unsigned char *)buf) == GIF_ERROR) 693 return (GIF_ERROR); 694 695 return (GIF_OK); 696 } 697 698 /****************************************************************************** 699 Put the image code in compressed form. This routine can be called if the 700 information needed to be piped out as is. Obviously this is much faster 701 than decoding and encoding again. This routine should be followed by calls 702 to EGifPutCodeNext, until NULL block is given. 703 The block should NOT be freed by the user (not dynamically allocated). 704 ******************************************************************************/ 705 int 706 EGifPutCode(GifFileType *GifFile, int CodeSize, const GifByteType *CodeBlock) 707 { 708 GifFilePrivateType *Private = (GifFilePrivateType *)GifFile->Private; 709 710 if (!IS_WRITEABLE(Private)) { 711 /* This file was NOT open for writing: */ 712 GifFile->Error = E_GIF_ERR_NOT_WRITEABLE; 713 return GIF_ERROR; 714 } 715 716 /* No need to dump code size as Compression set up does any for us: */ 717 /* 718 * Buf = CodeSize; 719 * if (InternalWrite(GifFile, &Buf, 1) != 1) { 720 * GifFile->Error = E_GIF_ERR_WRITE_FAILED; 721 * return GIF_ERROR; 722 * } 723 */ 724 725 return EGifPutCodeNext(GifFile, CodeBlock); 726 } 727 728 /****************************************************************************** 729 Continue to put the image code in compressed form. This routine should be 730 called with blocks of code as read via DGifGetCode/DGifGetCodeNext. If 731 given buffer pointer is NULL, empty block is written to mark end of code. 732 ******************************************************************************/ 733 int 734 EGifPutCodeNext(GifFileType *GifFile, const GifByteType *CodeBlock) 735 { 736 GifByteType Buf; 737 GifFilePrivateType *Private = (GifFilePrivateType *)GifFile->Private; 738 739 if (CodeBlock != NULL) { 740 if (InternalWrite(GifFile, CodeBlock, CodeBlock[0] + 1) 741 != (unsigned)(CodeBlock[0] + 1)) { 742 GifFile->Error = E_GIF_ERR_WRITE_FAILED; 743 return GIF_ERROR; 744 } 745 } else { 746 Buf = 0; 747 if (InternalWrite(GifFile, &Buf, 1) != 1) { 748 GifFile->Error = E_GIF_ERR_WRITE_FAILED; 749 return GIF_ERROR; 750 } 751 Private->PixelCount = 0; /* And local info. indicate image read. */ 752 } 753 754 return GIF_OK; 755 } 756 757 /****************************************************************************** 758 This routine should be called last, to close the GIF file. 759 ******************************************************************************/ 760 int 761 EGifCloseFile(GifFileType *GifFile, int *ErrorCode) 762 { 763 GifByteType Buf; 764 GifFilePrivateType *Private; 765 FILE *File; 766 767 if (GifFile == NULL) 768 return GIF_ERROR; 769 770 Private = (GifFilePrivateType *) GifFile->Private; 771 if (Private == NULL) 772 return GIF_ERROR; 773 if (!IS_WRITEABLE(Private)) { 774 /* This file was NOT open for writing: */ 775 if (ErrorCode != NULL) 776 *ErrorCode = E_GIF_ERR_NOT_WRITEABLE; 777 free(GifFile); 778 return GIF_ERROR; 779 } 780 781 File = Private->File; 782 783 Buf = TERMINATOR_INTRODUCER; 784 InternalWrite(GifFile, &Buf, 1); 785 786 if (GifFile->Image.ColorMap) { 787 GifFreeMapObject(GifFile->Image.ColorMap); 788 GifFile->Image.ColorMap = NULL; 789 } 790 if (GifFile->SColorMap) { 791 GifFreeMapObject(GifFile->SColorMap); 792 GifFile->SColorMap = NULL; 793 } 794 if (Private) { 795 if (Private->HashTable) { 796 free((char *) Private->HashTable); 797 } 798 free((char *) Private); 799 } 800 801 if (File && fclose(File) != 0) { 802 if (ErrorCode != NULL) 803 *ErrorCode = E_GIF_ERR_CLOSE_FAILED; 804 free(GifFile); 805 return GIF_ERROR; 806 } 807 808 free(GifFile); 809 if (ErrorCode != NULL) 810 *ErrorCode = E_GIF_SUCCEEDED; 811 return GIF_OK; 812 } 813 814 /****************************************************************************** 815 Put 2 bytes (a word) into the given file in little-endian order: 816 ******************************************************************************/ 817 static int 818 EGifPutWord(int Word, GifFileType *GifFile) 819 { 820 unsigned char c[2]; 821 822 c[0] = LOBYTE(Word); 823 c[1] = HIBYTE(Word); 824 if (InternalWrite(GifFile, c, 2) == 2) 825 return GIF_OK; 826 else 827 return GIF_ERROR; 828 } 829 830 /****************************************************************************** 831 Setup the LZ compression for this image: 832 ******************************************************************************/ 833 static int 834 EGifSetupCompress(GifFileType *GifFile) 835 { 836 int BitsPerPixel; 837 GifByteType Buf; 838 GifFilePrivateType *Private = (GifFilePrivateType *) GifFile->Private; 839 840 /* Test and see what color map to use, and from it # bits per pixel: */ 841 if (GifFile->Image.ColorMap) 842 BitsPerPixel = GifFile->Image.ColorMap->BitsPerPixel; 843 else if (GifFile->SColorMap) 844 BitsPerPixel = GifFile->SColorMap->BitsPerPixel; 845 else { 846 GifFile->Error = E_GIF_ERR_NO_COLOR_MAP; 847 return GIF_ERROR; 848 } 849 850 Buf = BitsPerPixel = (BitsPerPixel < 2 ? 2 : BitsPerPixel); 851 InternalWrite(GifFile, &Buf, 1); /* Write the Code size to file. */ 852 853 Private->Buf[0] = 0; /* Nothing was output yet. */ 854 Private->BitsPerPixel = BitsPerPixel; 855 Private->ClearCode = (1 << BitsPerPixel); 856 Private->EOFCode = Private->ClearCode + 1; 857 Private->RunningCode = Private->EOFCode + 1; 858 Private->RunningBits = BitsPerPixel + 1; /* Number of bits per code. */ 859 Private->MaxCode1 = 1 << Private->RunningBits; /* Max. code + 1. */ 860 Private->CrntCode = FIRST_CODE; /* Signal that this is first one! */ 861 Private->CrntShiftState = 0; /* No information in CrntShiftDWord. */ 862 Private->CrntShiftDWord = 0; 863 864 /* Clear hash table and send Clear to make sure the decoder do the same. */ 865 _ClearHashTable(Private->HashTable); 866 867 if (EGifCompressOutput(GifFile, Private->ClearCode) == GIF_ERROR) { 868 GifFile->Error = E_GIF_ERR_DISK_IS_FULL; 869 return GIF_ERROR; 870 } 871 return GIF_OK; 872 } 873 874 /****************************************************************************** 875 The LZ compression routine: 876 This version compresses the given buffer Line of length LineLen. 877 This routine can be called a few times (one per scan line, for example), in 878 order to complete the whole image. 879 ******************************************************************************/ 880 static int 881 EGifCompressLine(GifFileType *GifFile, 882 GifPixelType *Line, 883 const int LineLen) 884 { 885 int i = 0, CrntCode, NewCode; 886 unsigned long NewKey; 887 GifPixelType Pixel; 888 GifHashTableType *HashTable; 889 GifFilePrivateType *Private = (GifFilePrivateType *) GifFile->Private; 890 891 HashTable = Private->HashTable; 892 893 if (Private->CrntCode == FIRST_CODE) /* Its first time! */ 894 CrntCode = Line[i++]; 895 else 896 CrntCode = Private->CrntCode; /* Get last code in compression. */ 897 898 while (i < LineLen) { /* Decode LineLen items. */ 899 Pixel = Line[i++]; /* Get next pixel from stream. */ 900 /* Form a new unique key to search hash table for the code combines 901 * CrntCode as Prefix string with Pixel as postfix char. 902 */ 903 NewKey = (((uint32_t) CrntCode) << 8) + Pixel; 904 if ((NewCode = _ExistsHashTable(HashTable, NewKey)) >= 0) { 905 /* This Key is already there, or the string is old one, so 906 * simple take new code as our CrntCode: 907 */ 908 CrntCode = NewCode; 909 } else { 910 /* Put it in hash table, output the prefix code, and make our 911 * CrntCode equal to Pixel. 912 */ 913 if (EGifCompressOutput(GifFile, CrntCode) == GIF_ERROR) { 914 GifFile->Error = E_GIF_ERR_DISK_IS_FULL; 915 return GIF_ERROR; 916 } 917 CrntCode = Pixel; 918 919 /* If however the HashTable if full, we send a clear first and 920 * Clear the hash table. 921 */ 922 if (Private->RunningCode >= LZ_MAX_CODE) { 923 /* Time to do some clearance: */ 924 if (EGifCompressOutput(GifFile, Private->ClearCode) 925 == GIF_ERROR) { 926 GifFile->Error = E_GIF_ERR_DISK_IS_FULL; 927 return GIF_ERROR; 928 } 929 Private->RunningCode = Private->EOFCode + 1; 930 Private->RunningBits = Private->BitsPerPixel + 1; 931 Private->MaxCode1 = 1 << Private->RunningBits; 932 _ClearHashTable(HashTable); 933 } else { 934 /* Put this unique key with its relative Code in hash table: */ 935 _InsertHashTable(HashTable, NewKey, Private->RunningCode++); 936 } 937 } 938 939 } 940 941 /* Preserve the current state of the compression algorithm: */ 942 Private->CrntCode = CrntCode; 943 944 if (Private->PixelCount == 0) { 945 /* We are done - output last Code and flush output buffers: */ 946 if (EGifCompressOutput(GifFile, CrntCode) == GIF_ERROR) { 947 GifFile->Error = E_GIF_ERR_DISK_IS_FULL; 948 return GIF_ERROR; 949 } 950 if (EGifCompressOutput(GifFile, Private->EOFCode) == GIF_ERROR) { 951 GifFile->Error = E_GIF_ERR_DISK_IS_FULL; 952 return GIF_ERROR; 953 } 954 if (EGifCompressOutput(GifFile, FLUSH_OUTPUT) == GIF_ERROR) { 955 GifFile->Error = E_GIF_ERR_DISK_IS_FULL; 956 return GIF_ERROR; 957 } 958 } 959 960 return GIF_OK; 961 } 962 963 /****************************************************************************** 964 The LZ compression output routine: 965 This routine is responsible for the compression of the bit stream into 966 8 bits (bytes) packets. 967 Returns GIF_OK if written successfully. 968 ******************************************************************************/ 969 static int 970 EGifCompressOutput(GifFileType *GifFile, 971 const int Code) 972 { 973 GifFilePrivateType *Private = (GifFilePrivateType *) GifFile->Private; 974 int retval = GIF_OK; 975 976 if (Code == FLUSH_OUTPUT) { 977 while (Private->CrntShiftState > 0) { 978 /* Get Rid of what is left in DWord, and flush it. */ 979 if (EGifBufferedOutput(GifFile, Private->Buf, 980 Private->CrntShiftDWord & 0xff) == GIF_ERROR) 981 retval = GIF_ERROR; 982 Private->CrntShiftDWord >>= 8; 983 Private->CrntShiftState -= 8; 984 } 985 Private->CrntShiftState = 0; /* For next time. */ 986 if (EGifBufferedOutput(GifFile, Private->Buf, 987 FLUSH_OUTPUT) == GIF_ERROR) 988 retval = GIF_ERROR; 989 } else { 990 Private->CrntShiftDWord |= ((long)Code) << Private->CrntShiftState; 991 Private->CrntShiftState += Private->RunningBits; 992 while (Private->CrntShiftState >= 8) { 993 /* Dump out full bytes: */ 994 if (EGifBufferedOutput(GifFile, Private->Buf, 995 Private->CrntShiftDWord & 0xff) == GIF_ERROR) 996 retval = GIF_ERROR; 997 Private->CrntShiftDWord >>= 8; 998 Private->CrntShiftState -= 8; 999 } 1000 } 1001 1002 /* If code cannt fit into RunningBits bits, must raise its size. Note */ 1003 /* however that codes above 4095 are used for special signaling. */ 1004 if (Private->RunningCode >= Private->MaxCode1 && Code <= 4095) { 1005 Private->MaxCode1 = 1 << ++Private->RunningBits; 1006 } 1007 1008 return retval; 1009 } 1010 1011 /****************************************************************************** 1012 This routines buffers the given characters until 255 characters are ready 1013 to be output. If Code is equal to -1 the buffer is flushed (EOF). 1014 The buffer is Dumped with first byte as its size, as GIF format requires. 1015 Returns GIF_OK if written successfully. 1016 ******************************************************************************/ 1017 static int 1018 EGifBufferedOutput(GifFileType *GifFile, 1019 GifByteType *Buf, 1020 int c) 1021 { 1022 if (c == FLUSH_OUTPUT) { 1023 /* Flush everything out. */ 1024 if (Buf[0] != 0 1025 && InternalWrite(GifFile, Buf, Buf[0] + 1) != (unsigned)(Buf[0] + 1)) { 1026 GifFile->Error = E_GIF_ERR_WRITE_FAILED; 1027 return GIF_ERROR; 1028 } 1029 /* Mark end of compressed data, by an empty block (see GIF doc): */ 1030 Buf[0] = 0; 1031 if (InternalWrite(GifFile, Buf, 1) != 1) { 1032 GifFile->Error = E_GIF_ERR_WRITE_FAILED; 1033 return GIF_ERROR; 1034 } 1035 } else { 1036 if (Buf[0] == 255) { 1037 /* Dump out this buffer - it is full: */ 1038 if (InternalWrite(GifFile, Buf, Buf[0] + 1) != (unsigned)(Buf[0] + 1)) { 1039 GifFile->Error = E_GIF_ERR_WRITE_FAILED; 1040 return GIF_ERROR; 1041 } 1042 Buf[0] = 0; 1043 } 1044 Buf[++Buf[0]] = c; 1045 } 1046 1047 return GIF_OK; 1048 } 1049 1050 /****************************************************************************** 1051 This routine writes to disk an in-core representation of a GIF previously 1052 created by DGifSlurp(). 1053 ******************************************************************************/ 1054 1055 static int 1056 EGifWriteExtensions(GifFileType *GifFileOut, 1057 ExtensionBlock *ExtensionBlocks, 1058 int ExtensionBlockCount) 1059 { 1060 if (ExtensionBlocks) { 1061 ExtensionBlock *ep; 1062 int j; 1063 1064 for (j = 0; j < ExtensionBlockCount; j++) { 1065 ep = &ExtensionBlocks[j]; 1066 if (ep->Function != CONTINUE_EXT_FUNC_CODE) 1067 if (EGifPutExtensionLeader(GifFileOut, ep->Function) == GIF_ERROR) 1068 return (GIF_ERROR); 1069 if (EGifPutExtensionBlock(GifFileOut, ep->ByteCount, ep->Bytes) == GIF_ERROR) 1070 return (GIF_ERROR); 1071 if (j == ExtensionBlockCount - 1 || (ep+1)->Function != CONTINUE_EXT_FUNC_CODE) 1072 if (EGifPutExtensionTrailer(GifFileOut) == GIF_ERROR) 1073 return (GIF_ERROR); 1074 } 1075 } 1076 1077 return (GIF_OK); 1078 } 1079 1080 int 1081 EGifSpew(GifFileType *GifFileOut) 1082 { 1083 int i, j; 1084 1085 if (EGifPutScreenDesc(GifFileOut, 1086 GifFileOut->SWidth, 1087 GifFileOut->SHeight, 1088 GifFileOut->SColorResolution, 1089 GifFileOut->SBackGroundColor, 1090 GifFileOut->SColorMap) == GIF_ERROR) { 1091 return (GIF_ERROR); 1092 } 1093 1094 for (i = 0; i < GifFileOut->ImageCount; i++) { 1095 SavedImage *sp = &GifFileOut->SavedImages[i]; 1096 int SavedHeight = sp->ImageDesc.Height; 1097 int SavedWidth = sp->ImageDesc.Width; 1098 1099 /* this allows us to delete images by nuking their rasters */ 1100 if (sp->RasterBits == NULL) 1101 continue; 1102 1103 if (EGifWriteExtensions(GifFileOut, 1104 sp->ExtensionBlocks, 1105 sp->ExtensionBlockCount) == GIF_ERROR) 1106 return (GIF_ERROR); 1107 1108 if (EGifPutImageDesc(GifFileOut, 1109 sp->ImageDesc.Left, 1110 sp->ImageDesc.Top, 1111 SavedWidth, 1112 SavedHeight, 1113 sp->ImageDesc.Interlace, 1114 sp->ImageDesc.ColorMap) == GIF_ERROR) 1115 return (GIF_ERROR); 1116 1117 if (sp->ImageDesc.Interlace) { 1118 /* 1119 * The way an interlaced image should be written - 1120 * offsets and jumps... 1121 */ 1122 int InterlacedOffset[] = { 0, 4, 2, 1 }; 1123 int InterlacedJumps[] = { 8, 8, 4, 2 }; 1124 int k; 1125 /* Need to perform 4 passes on the images: */ 1126 for (k = 0; k < 4; k++) 1127 for (j = InterlacedOffset[k]; 1128 j < SavedHeight; 1129 j += InterlacedJumps[k]) { 1130 if (EGifPutLine(GifFileOut, 1131 sp->RasterBits + j * SavedWidth, 1132 SavedWidth) == GIF_ERROR) 1133 return (GIF_ERROR); 1134 } 1135 } else { 1136 for (j = 0; j < SavedHeight; j++) { 1137 if (EGifPutLine(GifFileOut, 1138 sp->RasterBits + j * SavedWidth, 1139 SavedWidth) == GIF_ERROR) 1140 return (GIF_ERROR); 1141 } 1142 } 1143 } 1144 1145 if (EGifWriteExtensions(GifFileOut, 1146 GifFileOut->ExtensionBlocks, 1147 GifFileOut->ExtensionBlockCount) == GIF_ERROR) 1148 return (GIF_ERROR); 1149 1150 if (EGifCloseFile(GifFileOut, NULL) == GIF_ERROR) 1151 return (GIF_ERROR); 1152 1153 return (GIF_OK); 1154 } 1155 1156 /* end */ 1157