00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041 #include <stdlib.h>
00042 #include <stdio.h>
00043 #include <setjmp.h>
00044 #include <string.h>
00045 #include <ctype.h>
00046
00047 #include "OSGConfig.h"
00048
00049 #ifdef OSG_SGI_LIB
00050 #include <limits>
00051 #endif
00052 #include "OSGGIFImageFileType.h"
00053 #include <OSGLog.h>
00054
00055 #include <iostream>
00056
00057 #ifndef OSG_DO_DOC
00058 # ifdef OSG_WITH_GIF
00059 # define OSG_GIF_ARG(ARG) ARG
00060 # else
00061 # define OSG_GIF_ARG(ARG)
00062 # endif
00063 #else
00064 # define OSG_GIF_ARG(ARG) ARG
00065 #endif
00066
00067 #ifdef OSG_WITH_GIF
00068
00069
00085
00086 #define GIF_MAXCOLORS 256
00087
00088 typedef enum
00089 {
00090 gif_image,
00091 gif_comment,
00092 gif_text
00093 } GIFStreamType;
00094
00095 typedef enum
00096 {
00097 gif_no_disposal = 0,
00098 gif_keep_disposal = 1,
00099 gif_color_restore = 2,
00100 gif_image_restore = 3
00101 }
00102 GIFDisposalType;
00103
00104 typedef struct
00105 {
00106 int transparent;
00107 int delayTime;
00108 int inputFlag;
00109 GIFDisposalType disposal;
00110 } GIF89info;
00111
00112 typedef struct GIFData
00113 {
00114 GIF89info info;
00115 int x, y;
00116 int width, height;
00117 GIFStreamType type;
00118 union
00119 {
00120 struct
00121 {
00122 int cmapSize;
00123 unsigned char cmapData[GIF_MAXCOLORS][3];
00124 unsigned char *data;
00125 int interlaced;
00126 } image;
00127 struct
00128 {
00129 int fg, bg;
00130 int cellWidth, cellHeight;
00131 int len;
00132 char *text;
00133 } text;
00134 struct
00135 {
00136 int len;
00137 char *text;
00138 } comment;
00139 } data;
00140
00141 struct GIFData *next;
00142 } GIFData;
00143
00144 typedef struct
00145 {
00146 int width, height;
00147
00148 int colorResolution;
00149 int colorMapSize;
00150 int cmapSize;
00151 unsigned char cmapData[GIF_MAXCOLORS][3];
00152
00153 int background;
00154 int aspectRatio;
00155
00156 GIFData *data;
00157 } GIFStream;
00158
00159
00160 static GIFStream *GIFRead (std::istream &is);
00161 int GIFTest (char *);
00162 int GIFWrite (char *, GIFStream *, int);
00163 static int GIFWriteFP(FILE *, GIFStream *, int);
00164 static int GIFFree (GIFStream *);
00165
00166 #endif
00167
00168
00169 OSG_USING_NAMESPACE
00170
00171
00172
00173
00174
00175
00176
00177
00178 static const Char8 *suffixArray[] = {
00179 "gif"
00180 };
00181
00182 GIFImageFileType GIFImageFileType::_the ( "image/gif",
00183 suffixArray, sizeof(suffixArray) );
00184
00185
00186
00190 GIFImageFileType& GIFImageFileType::the (void)
00191 {
00192 return _the;
00193 }
00194
00195
00200 bool GIFImageFileType::read(ImagePtr &OSG_GIF_ARG(image), std::istream &OSG_GIF_ARG(is),
00201 const std::string &OSG_GIF_ARG(mimetype))
00202 {
00203 bool retCode = false;
00204
00205 #ifdef OSG_WITH_GIF
00206 Image::PixelFormat pixelFormat = osg::Image::OSG_INVALID_PF;
00207 GIFStream *gifStream = GIFRead(is);
00208 GIFData *gifData = 0;
00209 bool isColor;
00210 int i, j, destI, lineSize, lineEnd;
00211 unsigned red, green, blue;
00212 int transparentIndex;
00213 int width = 0, height = 0, channel = 0, xOff = 0, yOff = 0;
00214 unsigned char *srcData = 0, *destData = 0;
00215 int colorIndex;
00216 unsigned frameCount = 0, currentFrame = 0;
00217 unsigned char *colorMap = 0;
00218
00219
00220 int colorMapSize;
00221 Time frameDelay;
00222
00223 if(gifStream)
00224 {
00225 frameCount = 0;
00226 for(gifData = gifStream->data; gifData; gifData = gifData->next)
00227 {
00228 if(gifData->type == gif_image)
00229 frameCount++;
00230 }
00231 }
00232
00233 FDEBUG(("GIF Frames: %d\n", frameCount));
00234
00235 if(gifStream)
00236 {
00237 for(gifData = gifStream->data; gifData; gifData = gifData->next)
00238 {
00239 switch(gifData->type)
00240 {
00241 case gif_image:
00242 if(frameCount)
00243 {
00244 FDEBUG(("Try to copy GIF Anim Frame %d/%d\n",
00245 (currentFrame + 1), frameCount));
00246 }
00247
00248
00249 transparentIndex = gifData->info.transparent;
00250 frameDelay = float(gifData->info.delayTime) / 100.0f;
00251 width = gifData->width;
00252 height = gifData->height;
00253 xOff = gifData->x;
00254 yOff = gifData->y;
00255
00256
00257 isColor = false;
00258 if(gifData->data.image.cmapSize > 0)
00259 {
00260 colorMapSize = gifData->data.image.cmapSize;
00261 colorMap = (unsigned char *) gifData->data.image.cmapData;
00262
00263
00264 }
00265 else if(gifStream->cmapSize > 0)
00266 {
00267 colorMapSize = gifStream->cmapSize;
00268 colorMap = (unsigned char *) gifStream->cmapData;
00269
00270
00271 }
00272 else
00273 {
00274 FWARNING(("Bad color map in GIFImageFileType::read()\n"));
00275 colorMapSize = 0;
00276 }
00277
00278 for(i = 0; i < colorMapSize; i++)
00279 {
00280 if(i != transparentIndex)
00281 {
00282 red = colorMap[i * 3 + 0];
00283 green = colorMap[i * 3 + 1];
00284 blue = colorMap[i * 3 + 2];
00285 if(red != green || red != blue)
00286 {
00287 isColor = true;
00288 break;
00289 }
00290 }
00291 }
00292
00293
00294 channel = (isColor ? 3 : 1) + (transparentIndex >= 0 ? 1 : 0);
00295
00296 if(currentFrame)
00297 {
00298
00299 if((channel == image->getBpp()) &&
00300 (width == image->getWidth()) &&
00301 (height == image->getHeight()))
00302 {
00303 destData = image->getData(0, currentFrame);
00304 }
00305 else
00306 {
00307 destData = image->getData(0, currentFrame);
00308
00309
00310 switch(gifData->info.disposal)
00311 {
00312 case gif_no_disposal:
00313 break;
00314
00315 case gif_keep_disposal:
00316 memcpy(destData,
00317 image->getData(0, currentFrame - 1),
00318 image->getWidth () *
00319 image->getHeight() *
00320 channel);
00321 break;
00322
00323 case gif_color_restore:
00324 {
00325 unsigned char r,g,b,a;
00326 UInt32 bgindex = gifStream->background;
00327 unsigned char *d = destData;
00328
00329 r = colorMap[bgindex * 3 + 0];
00330 g = colorMap[bgindex * 3 + 1];
00331 b = colorMap[bgindex * 3 + 2];
00332 a = (bgindex == transparentIndex) ? 0 : 255;
00333
00334 for(UInt32 pixel = image->getWidth () *
00335 image->getHeight();
00336 pixel > 0; --pixel, d += channel)
00337 {
00338 d[0] = r;
00339 d[1] = g;
00340 d[2] = b;
00341 if(channel == 4)
00342 d[3] = a;
00343 }
00344 }
00345 break;
00346
00347 case gif_image_restore:
00348 memcpy(destData,
00349 image->getData(0, (currentFrame >= 2) ?
00350 (currentFrame - 2):0),
00351 image->getWidth () *
00352 image->getHeight() *
00353 channel);
00354 break;
00355 default:
00356 FWARNING(("Unknown GIF disposal mode %d\n",
00357 gifData->info.disposal));
00358 break;
00359 }
00360
00361
00362 }
00363 }
00364 else
00365 {
00366 switch(channel)
00367 {
00368 case 1:
00369 pixelFormat = Image::OSG_L_PF;
00370 break;
00371 case 2:
00372 pixelFormat = Image::OSG_LA_PF;
00373 break;
00374 case 3:
00375 pixelFormat = Image::OSG_RGB_PF;
00376 break;
00377 case 4:
00378 pixelFormat = Image::OSG_RGBA_PF;
00379 break;
00380 };
00381 image->set(pixelFormat, width, height, 1, 1, frameCount,
00382 frameDelay);
00383 destData = image->getData();
00384 }
00385
00386
00387 lineSize = image->getWidth() * channel;
00388 lineEnd = width * channel + xOff * channel;
00389 srcData = gifData->data.image.data;
00390 destData = destData + ((image->getHeight() - yOff - 1) * lineSize);
00391
00392 switch(channel)
00393 {
00394 case 1:
00395 destI = 0;
00396 for(i = width * height; i--;)
00397 {
00398 destData[destI++] = colorMap[*srcData++ *3];
00399 if(destI >= lineSize)
00400 {
00401 destI = 0;
00402 destData -= lineSize;
00403 }
00404 }
00405 break;
00406
00407 case 2:
00408 destI = 0;
00409 for(i = width * height; i--;)
00410 {
00411 colorIndex = *srcData++;
00412 if(colorIndex == transparentIndex)
00413 {
00414 destData[destI++] = 0;
00415 destData[destI++] = 0;
00416 }
00417 else
00418 {
00419 destData[destI++] = colorMap[colorIndex * 3];
00420 destData[destI++] = 255;
00421 }
00422
00423 if(destI >= lineSize)
00424 {
00425 destI = 0;
00426 destData -= lineSize;
00427 }
00428 }
00429 break;
00430
00431 case 3:
00432 destI = 0;
00433 for(i = width * height; i--;)
00434 {
00435 colorIndex = *srcData++;
00436 for(j = 0; j < 3; j++)
00437 {
00438 destData[destI++] = colorMap[colorIndex * 3 + j];
00439 }
00440
00441 if(destI >= lineSize)
00442 {
00443 destI = 0;
00444 destData -= lineSize;
00445 }
00446 }
00447 break;
00448
00449 case 4:
00450 destI = xOff * 4;
00451
00452 for(i = width * height; i--;)
00453 {
00454 colorIndex = *srcData++;
00455 if(colorIndex == transparentIndex)
00456 {
00457
00458
00459
00460
00461
00462 destI += 4;
00463 }
00464 else
00465 {
00466 for(j = 0; j < 3; j++)
00467 {
00468 destData[destI++] =
00469 colorMap[colorIndex * 3 + j];
00470 }
00471
00472 destData[destI++] = 255;
00473 }
00474
00475 if(destI >= lineEnd)
00476 {
00477 destI = xOff * 4;
00478 destData -= lineSize;
00479 }
00480 }
00481 break;
00482 }
00483
00484 retCode = true;
00485
00486 currentFrame++;
00487
00488 break;
00489 case gif_comment:
00490 break;
00491 case gif_text:
00492 break;
00493 }
00494 }
00495
00496 GIFFree(gifStream);
00497 }
00498 else
00499 retCode = false;
00500 #endif
00501 return retCode;
00502 }
00503
00504
00510 std::string GIFImageFileType::determineMimetypeFromStream(std::istream &is)
00511 {
00512 char filecode[4];
00513 is.read(filecode, 4);
00514 is.seekg(-4, std::ios::cur);
00515 return strncmp(filecode, "GIF8", 4) == 0 ?
00516 std::string(getMimeType()) : std::string();
00517 }
00518
00519
00520
00521 bool GIFImageFileType::validateHeader( const Char8 *fileName, bool &implemented)
00522 {
00523 implemented = true;
00524
00525 if(fileName == NULL)
00526 return false;
00527
00528 FILE *file = fopen(fileName, "rb");
00529 if(file == NULL)
00530 return false;
00531
00532 std::string magic;
00533 magic.resize(4);
00534 fread((void *) &magic[0], 4, 1, file);
00535 fclose(file);
00536
00537 if(magic == "GIF8")
00538 {
00539 return true;
00540 }
00541
00542 return false;
00543 }
00544
00545
00549 GIFImageFileType::GIFImageFileType(const Char8 *mimeType,
00550 const Char8 *suffixArray[],
00551 UInt16 suffixByteCount) :
00552 ImageFileType(mimeType, suffixArray, suffixByteCount)
00553 {}
00554
00555
00559 GIFImageFileType::~GIFImageFileType(void) {}
00560
00561
00562
00563
00564
00565
00566
00567
00568
00569
00570
00571 #ifdef OSG_WITH_GIF
00572
00573
00574
00575
00576
00577
00578
00579
00580
00581
00582
00583
00584
00585
00586
00587
00588
00589
00590
00591
00592
00593
00594
00595
00596
00597
00598 #define GIF_TRUE 1
00599 #define GIF_FALSE 0
00600
00601 #define MAX_LWZ_BITS 12
00602
00603 #define INTERLACE 0x40
00604 #define LOCALCOLORMAP 0x80
00605
00606 #define BitSet(byte, bit) (((byte) & (bit)) == (bit))
00607 #define ReadOK(is, buffer, len) (is.read(reinterpret_cast<char*>(buffer), len).gcount() == len)
00608 #define MKINT(a, b) (((b) << 8) | (a))
00609 #define NEW(x) ((x *) malloc(sizeof(x)))
00610
00611
00612
00613
00614
00615
00616
00617 #if 0
00618 #define INFO_MSG(fmt) pm_message fmt
00619 #define ERROR(str) pm_error(str)
00620 #else
00621 #if 0
00622 #define INFO_MSG(fmt)
00623 #define ERROR(str) do { RWSetMsg(str); longjmp(setjmp_buffer, 1); } while(0)
00624 #else
00625 #define INFO_MSG(fmt) { FINFO(("Info loading gif: '%s'!\n", fmt)); }
00626 #define GIF_ERROR(str) { FWARNING(("Error loading gif: '%s'!\n", str)); \
00627 longjmp(setjmp_buffer, 1); }
00628 #endif
00629 #endif
00630
00631
00632
00633 static int readColorMap(std::istream &, int, unsigned char [GIF_MAXCOLORS][3]);
00634 static int GetDataBlock(std::istream &, unsigned char *);
00635 static void readImage(std::istream &, int, int, int, unsigned char *);
00636
00637 static jmp_buf setjmp_buffer;
00638
00639 static int verbose = GIF_FALSE;
00640
00641
00642
00643 static GIFStream *GIFRead(std::istream &is)
00644 {
00645 unsigned char buf[256];
00646 unsigned char c;
00647 GIFStream *gifStream = 0;
00648 GIFData *cur, **end;
00649 GIF89info info = {0};
00650 int resetInfo = GIF_TRUE;
00651 int n;
00652
00653 if(setjmp(setjmp_buffer))
00654 goto out;
00655
00656 if(!ReadOK(is, buf, 6))
00657 {
00658 GIF_ERROR("error reading magic number");
00659 }
00660
00661 if(strncmp((char *) buf, "GIF", 3) != 0)
00662 GIF_ERROR("not a GIF file");
00663
00664 if((strncmp(((char *) (buf)) + 3, "87a", 3) != 0) &&
00665 (strncmp(((char *) (buf)) + 3, "89a", 3) != 0))
00666 {
00667 GIF_ERROR("bad version number, not '87a' or '89a'");
00668 }
00669
00670 if(!ReadOK(is, buf, 7))
00671 {
00672 GIF_ERROR("failed to read screen descriptor");
00673 }
00674
00675 gifStream = NEW(GIFStream);
00676
00677 gifStream->width = MKINT(buf[0], buf[1]);
00678 gifStream->height = MKINT(buf[2], buf[3]);
00679
00680 gifStream->cmapSize = 2 << (buf[4] & 0x07);
00681 gifStream->colorMapSize = gifStream->cmapSize;
00682 gifStream->colorResolution = ((int) (buf[4] & 0x70) >> 3) + 1;
00683 gifStream->background = buf[5];
00684 gifStream->aspectRatio = buf[6];
00685
00686 gifStream->data = NULL;
00687
00688 end = &gifStream->data;
00689
00690
00691
00692
00693 if(BitSet(buf[4], LOCALCOLORMAP))
00694 {
00695 if(readColorMap(is, gifStream->cmapSize, gifStream->cmapData))
00696 {
00697 GIF_ERROR("unable to get global colormap");
00698 }
00699 }
00700 else
00701 {
00702 gifStream->cmapSize = 0;
00703 gifStream->background = -1;
00704 }
00705
00706 if(gifStream->aspectRatio != 0 && gifStream->aspectRatio != 49)
00707 {
00708 INFO_MSG(("warning - non-square pixels"));
00709 }
00710
00711 while(ReadOK(is, &c, 1) && c != ';')
00712 {
00713 if(resetInfo)
00714 {
00715 info.disposal = (GIFDisposalType) 0;
00716 info.inputFlag = 0;
00717 info.delayTime = 0;
00718 info.transparent = -1;
00719 resetInfo = GIF_FALSE;
00720 }
00721
00722 cur = NULL;
00723
00724 if(c == '!')
00725 {
00726 if(!ReadOK(is, &c, 1))
00727 {
00728 GIF_ERROR("EOF / read error on extention function code");
00729 }
00730
00731 if(c == 0xf9)
00732 {
00733 (void) GetDataBlock(is, buf);
00734 info.disposal = (GIFDisposalType) ((buf[0] >> 2) & 0x7);
00735 info.inputFlag = (buf[0] >> 1) & 0x1;
00736 info.delayTime = MKINT(buf[1], buf[2]);
00737 if(BitSet(buf[0], 0x1))
00738 info.transparent = buf[3];
00739
00740 while(GetDataBlock(is, buf) != 0)
00741 ;
00742 }
00743 else if(c == 0xfe || c == 0x01)
00744 {
00745 int len = 0;
00746 int size = 256;
00747 char *text = NULL;
00748
00749
00750
00751
00752 cur = NEW(GIFData);
00753
00754 if(c == 0x01)
00755 {
00756 (void) GetDataBlock(is, buf);
00757
00758 cur->type = gif_text;
00759 cur->info = info;
00760 cur->x = MKINT(buf[0], buf[1]);
00761 cur->y = MKINT(buf[2], buf[3]);
00762 cur->width = MKINT(buf[4], buf[5]);
00763 cur->height = MKINT(buf[6], buf[7]);
00764
00765 cur->data.text.cellWidth = buf[8];
00766 cur->data.text.cellHeight = buf[9];
00767 cur->data.text.fg = buf[10];
00768 cur->data.text.bg = buf[11];
00769
00770 resetInfo = GIF_TRUE;
00771 }
00772 else
00773 {
00774 cur->type = gif_comment;
00775 }
00776
00777 text = (char *) malloc(size);
00778
00779 while((n = GetDataBlock(is, buf)) != 0)
00780 {
00781 if(n + len >= size)
00782 {
00783 text = (char *) realloc(text, size += 256);
00784 }
00785
00786 memcpy(text + len, buf, n);
00787 len += n;
00788 }
00789
00790 if(c == 0x01)
00791 {
00792 cur->data.text.len = len;
00793 cur->data.text.text = text;
00794 }
00795 else
00796 {
00797 cur->data.comment.len = len;
00798 cur->data.comment.text = text;
00799 }
00800 }
00801 else
00802 {
00803
00804
00805
00806 while(GetDataBlock(is, buf) > 0)
00807 ;
00808 }
00809 }
00810 else if(c == ',')
00811 {
00812 if(!ReadOK(is, buf, 9))
00813 {
00814 GIF_ERROR("couldn't read left/top/width/height");
00815 }
00816
00817 cur = NEW(GIFData);
00818
00819 cur->type = gif_image;
00820 cur->info = info;
00821 cur->x = MKINT(buf[0], buf[1]);
00822 cur->y = MKINT(buf[2], buf[3]);
00823 cur->width = MKINT(buf[4], buf[5]);
00824 cur->height = MKINT(buf[6], buf[7]);
00825 cur->data.image.cmapSize = 1 << ((buf[8] & 0x07) + 1);
00826 if(BitSet(buf[8], LOCALCOLORMAP))
00827 {
00828 if(readColorMap(is, cur->data.image.cmapSize,
00829 cur->data.image.cmapData))
00830 {
00831 GIF_ERROR("unable to get local colormap");
00832 }
00833 }
00834 else
00835 {
00836 cur->data.image.cmapSize = 0;
00837 }
00838
00839 cur->data.image.data = (unsigned char *)
00840 malloc(cur->width * cur->height);
00841 cur->data.image.interlaced = BitSet(buf[8], INTERLACE);
00842 readImage(is, BitSet(buf[8], INTERLACE), cur->width, cur->height,
00843 cur->data.image.data);
00844
00845 resetInfo = GIF_TRUE;
00846 }
00847 else
00848 {
00849 INFO_MSG(("bogus character 0x%02x, ignoring", (int) c));
00850 }
00851
00852 if(cur != NULL)
00853 {
00854 *end = cur;
00855 end = &cur->next;
00856 cur->next = NULL;
00857 }
00858 }
00859
00860 if(c != ';')
00861 GIF_ERROR("EOF / data stream");
00862
00863 out:
00864 return gifStream;
00865 }
00866
00867
00868 static int GIFFreeData(GIFData *gifData)
00869 {
00870 int retCode = 0;
00871
00872 if(gifData)
00873 {
00874 switch(gifData->type)
00875 {
00876 case gif_image:
00877 if(gifData->data.image.data)
00878 {
00879 free(gifData->data.image.data);
00880 }
00881 break;
00882 case gif_comment:
00883 if(gifData->data.comment.text)
00884 {
00885 free(gifData->data.comment.text);
00886 }
00887 break;
00888 case gif_text:
00889 if(gifData->data.text.text)
00890 {
00891 free(gifData->data.text.text);
00892 }
00893 break;
00894 }
00895
00896 retCode = 1;
00897 }
00898 else
00899 retCode = 0;
00900
00901 return retCode;
00902 }
00903
00904
00905 static int GIFFree(GIFStream *gifStream)
00906 {
00907 int retCode = 1;
00908 GIFData *gifData, *gifNext;
00909
00910 if(gifStream)
00911 {
00912 gifData = gifStream->data;
00913 while(gifData)
00914 {
00915 gifNext = gifData->next;
00916 GIFFreeData(gifData);
00917 free(gifData);
00918 gifData = gifNext;
00919 }
00920 }
00921
00922 return retCode;
00923 }
00924
00925
00926 static int readColorMap(std::istream &is, int size, unsigned char data[GIF_MAXCOLORS][3])
00927 {
00928 int i;
00929 unsigned char rgb[3 * GIF_MAXCOLORS];
00930 unsigned char *cp = rgb;
00931
00932 if(!ReadOK(is, rgb, size * 3))
00933 return GIF_TRUE;
00934
00935 for(i = 0; i < size; i++)
00936 {
00937 data[i][0] = *cp++;
00938 data[i][1] = *cp++;
00939 data[i][2] = *cp++;
00940 }
00941
00942 return GIF_FALSE;
00943 }
00944
00945
00946
00947
00948 static int ZeroDataBlock = GIF_FALSE;
00949
00950
00951
00952 static int GetDataBlock(std::istream &is, unsigned char *buf)
00953 {
00954 unsigned char count;
00955
00956 if(!ReadOK(is, &count, 1))
00957 {
00958 INFO_MSG(("error in getting DataBlock size"));
00959 return -1;
00960 }
00961
00962 ZeroDataBlock = count == 0;
00963
00964 if((count != 0) && (!ReadOK(is, buf, count)))
00965 {
00966 INFO_MSG(("error in reading DataBlock"));
00967 return -1;
00968 }
00969
00970 return count;
00971 }
00972
00973
00974
00975
00976
00977
00978
00979
00980 static int curbit, lastbit, get_done, last_byte;
00981 static int return_clear;
00982
00983
00984
00985
00986 static int stack[(1 << (MAX_LWZ_BITS)) * 2], *sp;
00987 static int code_size, set_code_size;
00988 static int max_code, max_code_size;
00989 static int clear_code, end_code;
00990
00991
00992
00993 static void initLWZ(int input_code_size)
00994 {
00995
00996
00997 set_code_size = input_code_size;
00998 code_size = set_code_size + 1;
00999 clear_code = 1 << set_code_size ;
01000 end_code = clear_code + 1;
01001 max_code_size = 2 * clear_code;
01002 max_code = clear_code + 2;
01003
01004 curbit = lastbit = 0;
01005 last_byte = 2;
01006 get_done = GIF_FALSE;
01007
01008 return_clear = GIF_TRUE;
01009
01010 sp = stack;
01011 }
01012
01013
01014 static int nextCode(std::istream &is, int code_size)
01015 {
01016 static unsigned char buf[280];
01017 static int maskTbl[16] =
01018 {
01019 0x0000,
01020 0x0001,
01021 0x0003,
01022 0x0007,
01023 0x000f,
01024 0x001f,
01025 0x003f,
01026 0x007f,
01027 0x00ff,
01028 0x01ff,
01029 0x03ff,
01030 0x07ff,
01031 0x0fff,
01032 0x1fff,
01033 0x3fff,
01034 0x7fff,
01035 };
01036 int i, j, ret, end;
01037
01038 if(return_clear)
01039 {
01040 return_clear = GIF_FALSE;
01041 return clear_code;
01042 }
01043
01044 end = curbit + code_size;
01045
01046 if(end >= lastbit)
01047 {
01048 int count;
01049
01050 if(get_done)
01051 {
01052 if(curbit >= lastbit)
01053 {
01054 GIF_ERROR("ran off the end of my bits");
01055 }
01056
01057 return -1;
01058 }
01059
01060 buf[0] = buf[last_byte - 2];
01061 buf[1] = buf[last_byte - 1];
01062
01063 if((count = GetDataBlock(is, &buf[2])) == 0)
01064 get_done = GIF_TRUE;
01065
01066 last_byte = 2 + count;
01067 curbit = (curbit - lastbit) + 16;
01068 lastbit = (2 + count) * 8;
01069
01070 end = curbit + code_size;
01071 }
01072
01073 j = end / 8;
01074 i = curbit / 8;
01075
01076 if(i == j)
01077 ret = buf[i];
01078 else if(i + 1 == j)
01079 ret = buf[i] | (buf[i + 1] << 8);
01080 else
01081 {
01082 ret = buf[i] | (buf[i + 1] << 8) | (buf[i + 2] << 16);
01083 }
01084
01085 ret = (ret >> (curbit % 8)) & maskTbl[code_size];
01086
01087 curbit += code_size;
01088
01089 return ret;
01090 }
01091
01092 #define readLWZ(fd) ((sp > stack) ? *--sp : nextLWZ(fd))
01093
01094
01095 static int nextLWZ(std::istream &is)
01096 {
01097 static int table[2][(1 << MAX_LWZ_BITS)];
01098 static int firstcode, oldcode;
01099 int code, incode;
01100 register int i;
01101
01102 while((code = nextCode(is, code_size)) >= 0)
01103 {
01104 if(code == clear_code)
01105 {
01106 for(i = 0; i < clear_code; ++i)
01107 {
01108 table[0][i] = 0;
01109 table[1][i] = i;
01110 }
01111
01112 for(; i < (1 << MAX_LWZ_BITS); ++i)
01113 table[0][i] = table[1][i] = 0;
01114 code_size = set_code_size + 1;
01115 max_code_size = 2 * clear_code;
01116 max_code = clear_code + 2;
01117 sp = stack;
01118 do
01119 {
01120 firstcode = oldcode = nextCode(is, code_size);
01121 } while(firstcode == clear_code);
01122
01123 return firstcode;
01124 }
01125
01126 if(code == end_code)
01127 {
01128 int count;
01129 unsigned char buf[260];
01130
01131 if(ZeroDataBlock)
01132 return -2;
01133
01134 while((count = GetDataBlock(is, buf)) > 0)
01135 ;
01136
01137 if(count != 0)
01138 {
01139 INFO_MSG(("missing EOD in data stream"));
01140 }
01141
01142 return -2;
01143 }
01144
01145 incode = code;
01146
01147 if(code >= max_code)
01148 {
01149 *sp++ = firstcode;
01150 code = oldcode;
01151 }
01152
01153 while(code >= clear_code)
01154 {
01155 *sp++ = table[1][code];
01156 if(code == table[0][code])
01157 {
01158 GIF_ERROR("circular table entry BIG ERROR");
01159 }
01160
01161 code = table[0][code];
01162 }
01163
01164 *sp++ = firstcode = table[1][code];
01165
01166 if((code = max_code) < (1 << MAX_LWZ_BITS))
01167 {
01168 table[0][code] = oldcode;
01169 table[1][code] = firstcode;
01170 ++max_code;
01171 if((max_code >= max_code_size) &&
01172 (max_code_size < (1 << MAX_LWZ_BITS)))
01173 {
01174 max_code_size *= 2;
01175 ++code_size;
01176 }
01177 }
01178
01179 oldcode = incode;
01180
01181 if(sp > stack)
01182 return *--sp;
01183 }
01184
01185 return code;
01186 }
01187
01188
01189 static void readImage(std::istream &is, int interlace, int width, int height,
01190 unsigned char *data)
01191 {
01192 unsigned char *dp, c;
01193
01194 int v, xpos = 0, ypos = 0;
01195
01196
01197
01198
01199
01200 if(!ReadOK(is, &c, 1))
01201 {
01202 GIF_ERROR("EOF / read error on image data");
01203 }
01204
01205 initLWZ(c);
01206
01207 if(verbose)
01208 {
01209 INFO_MSG(("reading %d by %d%s GIF image", width, height, interlace ?
01210 " interlaced" : ""));
01211 }
01212
01213 if(interlace)
01214 {
01215 int i;
01216 int pass = 0, step = 8;
01217
01218 for(i = 0; i < height; i++)
01219 {
01220 dp = &data[width * ypos];
01221 for(xpos = 0; xpos < width; xpos++)
01222 {
01223 if((v = readLWZ(is)) < 0)
01224 goto fini;
01225
01226 *dp++ = v;
01227 }
01228
01229 if((ypos += step) >= height)
01230 {
01231 do
01232 {
01233 if(pass++ > 0)
01234 step /= 2;
01235 ypos = step / 2;
01236 } while(ypos > height);
01237 }
01238 }
01239 }
01240 else
01241 {
01242 dp = data;
01243 for(ypos = 0; ypos < height; ypos++)
01244 {
01245 for(xpos = 0; xpos < width; xpos++)
01246 {
01247 if((v = readLWZ(is)) < 0)
01248 goto fini;
01249
01250 *dp++ = v;
01251 }
01252 }
01253 }
01254
01255 fini:
01256 if(readLWZ(is) >= 0)
01257 {
01258 INFO_MSG(("too much input data, ignoring extra..."));
01259 }
01260
01261 return;
01262 }
01263
01264
01265
01266
01267
01268
01269
01270
01271
01272
01273
01274
01275
01276
01277
01278
01279
01280
01281
01282
01283
01284
01285
01286
01287
01288
01289
01290
01291
01292
01293
01294
01295
01296
01297
01298
01299
01300
01301
01302
01303
01304
01305
01306
01307
01308
01309
01310
01311
01312 #define GIF_TRUE 1
01313 #define GIF_FALSE 0
01314
01315 #define PUTBYTE(v, fp) putc(v, fp)
01316 #define PUTWORD(v, fp) \
01317 do \
01318 { \
01319 putc(((v) & 0xff), fp); \
01320 putc((((v) >> 8) & 0xff), fp); \
01321 } while(0)
01322
01323
01324
01325 typedef int code_int;
01326
01327 typedef long int count_int;
01328
01329 static void putImage(FILE *, int, int, int, int, unsigned char *);
01330 static void putColorMap(FILE *, int, unsigned char[GIF_MAXCOLORS][3]);
01331 static void putDataBlocks(FILE *fp, int, unsigned char *);
01332 static void putGif89Info(FILE *, GIF89info *);
01333
01334 static void output(code_int code);
01335 static void cl_block(void);
01336 static void cl_hash(count_int hsize);
01337 static void char_init(void);
01338 static void char_out(int c);
01339 static void flush_char(void);
01340
01341
01342
01343
01344 struct cval
01345 {
01346 int idx, cnt;
01347 };
01348
01349
01350 static int cvalCMP(struct cval *a, struct cval *b)
01351 {
01352 return b->cnt - a->cnt;
01353 }
01354
01355
01356 static int optimizeCMAP(GIFStream *stream)
01357 {
01358 GIFData *cur = 0, *img = 0;
01359 int count = 0;
01360
01361 for(cur = stream->data; cur != NULL; cur = cur->next)
01362 {
01363 if(cur->type == gif_image)
01364 {
01365 img = cur;
01366 count++;
01367 }
01368 }
01369
01370
01371
01372
01373
01374 if(count == 0 || count > 1)
01375 return 0;
01376
01377
01378
01379
01380
01381
01382 {
01383 int size;
01384 unsigned char *dp = img->data.image.data;
01385 unsigned char *ep = dp + img->width * img->height;
01386 struct cval vals[256];
01387 int i;
01388
01389
01390 unsigned char tmap[256][3], rmap[256];
01391
01392 if((size = img->data.image.cmapSize) == 0)
01393 size = stream->cmapSize;
01394
01395 for(i = 0; i < size; i++)
01396 {
01397 vals[i].idx = i;
01398 vals[i].cnt = 0;
01399 }
01400
01401 for(dp = img->data.image.data, i = 0; dp < ep; i++, dp++)
01402 vals[*dp].cnt++;
01403
01404
01405
01406
01407 qsort(vals, size, sizeof(vals[0]),
01408 (int(*) (const void *, const void *)) cvalCMP);
01409
01410 for(i = 0; i < size; i++)
01411 if(vals[i].idx != i)
01412 break;
01413
01414
01415
01416
01417 if(i == size)
01418 return 1;
01419 for(i = 0; i < size; i++)
01420 rmap[vals[i].idx] = i;
01421
01422
01423
01424
01425 for(dp = img->data.image.data, i = 0; dp < ep; i++, dp++)
01426 *dp = rmap[*dp];
01427 if(img->info.transparent != -1)
01428 {
01429 img->info.transparent = rmap[img->info.transparent];
01430 }
01431
01432
01433
01434
01435 if(img->data.image.cmapSize != 0)
01436 {
01437 for(i = 0; i < size; i++)
01438 {
01439 stream->cmapData[i][0] = img->data.image.cmapData[i][0];
01440 stream->cmapData[i][1] = img->data.image.cmapData[i][1];
01441 stream->cmapData[i][2] = img->data.image.cmapData[i][2];
01442 }
01443
01444 img->data.image.cmapSize = 0;
01445 stream->cmapSize = size;
01446 }
01447
01448
01449
01450
01451 for(i = 0; i < size; i++)
01452 {
01453 tmap[i][0] = stream->cmapData[i][0];
01454 tmap[i][1] = stream->cmapData[i][1];
01455 tmap[i][2] = stream->cmapData[i][2];
01456 }
01457
01458 for(i = 0; i < size; i++)
01459 {
01460 stream->cmapData[rmap[i]][0] = tmap[i][0];
01461 stream->cmapData[rmap[i]][1] = tmap[i][1];
01462 stream->cmapData[rmap[i]][2] = tmap[i][2];
01463 }
01464 }
01465
01466 return 1;
01467 }
01468
01469
01470
01471
01472 static int binaryLog(int val)
01473 {
01474 int i;
01475
01476 if(val == 0)
01477 return 0;
01478
01479 for(i = 1; i <= 8; i++)
01480 if(val <= (1 << i))
01481 return i;
01482 return 8;
01483 }
01484
01485 #ifdef __sgi
01486 #pragma set woff 1209
01487 #endif
01488
01489
01490 static int GIFWriteFP(FILE *fp, GIFStream *stream, int optimize)
01491 {
01492 GIFData *cur;
01493 int flag = GIF_FALSE;
01494 int c;
01495 int globalBitsPP = 0;
01496 int resolution;
01497
01498 if(fp == NULL)
01499 return GIF_TRUE;
01500 if(stream == NULL)
01501 return GIF_FALSE;
01502
01503
01504
01505
01506
01507 resolution = binaryLog(stream->cmapSize) - 1;
01508 for(cur = stream->data; !flag && cur != NULL; cur = cur->next)
01509 {
01510 if(cur->type == gif_text || cur->type == gif_comment)
01511 {
01512 flag = GIF_TRUE;
01513 }
01514 else if(cur->type == gif_image)
01515 {
01516 int v = binaryLog(cur->data.image.cmapSize);
01517
01518 if(v > resolution)
01519 resolution = v;
01520
01521
01522
01523
01524 if(cur->info.transparent != -1 ||
01525 cur->info.delayTime != 0 ||
01526 cur->info.inputFlag != 0 ||
01527 cur->info.disposal != 0)
01528 flag = GIF_TRUE;
01529 }
01530 }
01531
01532
01533
01534
01535 if(optimize)
01536 optimize = optimizeCMAP(stream);
01537
01538 fwrite(flag ? "GIF89a" : "GIF87a", 1, 6, fp);
01539
01540 PUTWORD(stream->width, fp);
01541 PUTWORD(stream->height, fp);
01542
01543
01544
01545
01546 c = ((resolution & 0x07) << 5) | 0x00;
01547 if(stream->cmapSize != 0)
01548 {
01549 globalBitsPP = binaryLog(stream->cmapSize);
01550 c |= 0x80;
01551 c |= globalBitsPP - 1;
01552 }
01553
01554
01555
01556
01557 if(optimize)
01558 c |= 0x08;
01559 PUTBYTE(c, fp);
01560
01561 PUTBYTE(stream->background, fp);
01562 PUTBYTE(stream->aspectRatio, fp);
01563
01564 putColorMap(fp, stream->cmapSize, stream->cmapData);
01565
01566 for(cur = stream->data; cur != NULL; cur = cur->next)
01567 {
01568 if(cur->type == gif_image)
01569 {
01570 int bpp;
01571
01572 putGif89Info(fp, &cur->info);
01573
01574 PUTBYTE(0x2c, fp);
01575 PUTWORD(cur->x, fp);
01576 PUTWORD(cur->y, fp);
01577 PUTWORD(cur->width, fp);
01578 PUTWORD(cur->height, fp);
01579
01580 c = cur->data.image.interlaced ? 0x40 : 0x00;
01581 if(cur->data.image.cmapSize != 0)
01582 {
01583 bpp = binaryLog(cur->data.image.cmapSize);
01584 c |= 0x80;
01585 c |= bpp;
01586 }
01587 else
01588 {
01589 bpp = globalBitsPP;
01590 }
01591
01592 PUTBYTE(c, fp);
01593
01594 putColorMap(fp, cur->data.image.cmapSize, cur->data.image.cmapData);
01595
01596 putImage(fp, cur->data.image.interlaced, bpp, cur->width,
01597 cur->height, cur->data.image.data);
01598 }
01599 else if(cur->type == gif_comment)
01600 {
01601 PUTBYTE('!', fp);
01602 PUTBYTE(0xfe, fp);
01603 putDataBlocks(fp, cur->data.comment.len,
01604 (unsigned char *) cur->data.comment.text);
01605 }
01606 else if(cur->type == gif_text)
01607 {
01608 putGif89Info(fp, &cur->info);
01609
01610 PUTBYTE('!', fp);
01611 PUTBYTE(0x01, fp);
01612
01613 PUTWORD(cur->x, fp);
01614 PUTWORD(cur->y, fp);
01615 PUTWORD(cur->width, fp);
01616 PUTWORD(cur->height, fp);
01617
01618 PUTBYTE(cur->data.text.cellWidth, fp);
01619 PUTBYTE(cur->data.text.cellHeight, fp);
01620 PUTBYTE(cur->data.text.fg, fp);
01621 PUTBYTE(cur->data.text.bg, fp);
01622
01623 putDataBlocks(fp, cur->data.text.len,
01624 (unsigned char *) cur->data.text.text);
01625 }
01626 }
01627
01628
01629
01630
01631 PUTBYTE(';', fp);
01632
01633 return GIF_FALSE;
01634 }
01635
01636 #ifdef __sgi
01637 #pragma reset woff 1209
01638 #endif
01639
01640
01641 int GIFWrite(char *file, GIFStream *stream, int optimize)
01642 {
01643 if(stream != NULL)
01644 {
01645 FILE *fp = fopen(file, "wb");
01646
01647 if(fp != NULL)
01648 {
01649 int s = GIFWriteFP(fp, stream, optimize);
01650 fclose(fp);
01651 return s;
01652 }
01653 }
01654
01655 return GIF_TRUE;
01656 }
01657
01658
01659 static void putColorMap(FILE *fp, int size, unsigned char data[GIF_MAXCOLORS][3])
01660 {
01661 int i;
01662
01663 for(i = 0; i < size; i++)
01664 {
01665 PUTBYTE(data[i][0], fp);
01666 PUTBYTE(data[i][1], fp);
01667 PUTBYTE(data[i][2], fp);
01668 }
01669 }
01670
01671
01672 static void putDataBlocks(FILE *fp, int size, unsigned char *data)
01673 {
01674 int n;
01675
01676 while(size > 0)
01677 {
01678 n = size > 255 ? 255 : size;
01679
01680 PUTBYTE(n, fp);
01681 fwrite(data, 1, n, fp);
01682 data += n;
01683 size -= n;
01684 }
01685
01686 PUTBYTE(0, fp);
01687 }
01688
01689 #ifdef __sgi
01690 #pragma set woff 1209
01691 #endif
01692
01693
01694 static void putGif89Info(FILE *fp, GIF89info *info)
01695 {
01696 unsigned char c;
01697
01698 if(info->transparent == -1 &&
01699 info->delayTime == 0 &&
01700 info->inputFlag == 0 &&
01701 info->disposal == 0)
01702 return;
01703
01704 PUTBYTE('!', fp);
01705 PUTBYTE(0xf9, fp);
01706 PUTBYTE(4, fp);
01707 c = (info->inputFlag ? 0x02 : 0x00) | ((info->disposal & 0x07) << 2) | ((info->transparent != -1) ? 0x01 : 0x00);
01708 PUTBYTE(c, fp);
01709 PUTWORD(info->delayTime, fp);
01710 PUTBYTE(info->transparent, fp);
01711
01712
01713
01714
01715 PUTBYTE(0, fp);
01716 }
01717
01718 #ifdef __sgi
01719 #pragma reset woff 1209
01720 #endif
01721
01722
01723
01724
01725
01726
01727
01728
01729
01730
01731
01732
01733
01734 #define BITS 12
01735
01736 #define HSIZE 5003
01737
01738 #ifdef NO_UCHAR
01739 typedef char char_type;
01740 #else
01741 typedef unsigned char char_type;
01742 #endif
01743
01744
01745
01746
01747
01748
01749
01750
01751
01752
01753
01754
01755
01756
01757
01758 #define ARGVAL() (*++(*argv) || (--argc && *++argv))
01759 static int n_bits;
01760 static int maxbits;
01761 static code_int maxcode;
01762 static code_int maxmaxcode;
01763 #define MAXCODE(n_bits) (((code_int) 1 << (n_bits)) - 1)
01764 static count_int htab[HSIZE];
01765 static unsigned short codetab[HSIZE];
01766 #define HashTabOf(i) htab[i]
01767 #define CodeTabOf(i) codetab[i]
01768
01769 static code_int hsize;
01770
01771 static unsigned long cur_accum;
01772 static int cur_bits;
01773
01774
01775
01776
01777
01778
01779
01780
01781
01782 #define tab_prefixof(i) CodeTabOf(i)
01783 #define tab_suffixof(i) ((char_type *) (htab))[i]
01784 #define de_stack ((char_type *) &tab_suffixof((code_int) 1 << BITS))
01785 static code_int free_ent;
01786
01787
01788
01789
01790
01791 static int clear_flg;
01792
01793
01794
01795
01796
01797
01798
01799
01800
01801
01802
01803
01804
01805
01806
01807
01808
01809 static int g_init_bits;
01810 static FILE *g_outfile;
01811
01812 static int ClearCode;
01813 static int EOFCode;
01814
01815
01816
01817 #ifdef __sgi
01818 #pragma set woff 1209
01819 #endif
01820
01821 static void putImage(FILE *fp, int interlaced, int bpp, int width, int height,
01822 unsigned char *data)
01823 {
01824
01825 int left = interlaced ? width : width * height;
01826 int cury = 0, pass = 0;
01827 unsigned char *dp = data;
01828 long fcode;
01829 code_int v, i, ent, disp, hsize_reg;
01830 int c, hshift;
01831
01832
01833 if(bpp <= 1)
01834 {
01835 g_init_bits = 3;
01836 PUTBYTE(2, fp);
01837 }
01838 else
01839 {
01840 g_init_bits = bpp + 1;
01841 PUTBYTE(bpp, fp);
01842 }
01843
01844
01845
01846
01847
01848 g_outfile = fp;
01849
01850
01851
01852
01853
01854 clear_flg = GIF_FALSE;
01855 maxbits = BITS;
01856 maxmaxcode = 1 << BITS;
01857 maxcode = MAXCODE(n_bits = g_init_bits);
01858 hsize = HSIZE;
01859 cur_accum = 0;
01860 cur_bits = 0;
01861
01862 ClearCode = (1 << (g_init_bits - 1));
01863 EOFCode = ClearCode + 1;
01864 free_ent = ClearCode + 2;
01865
01866 char_init();
01867
01868 hshift = 0;
01869 for(fcode = (long) hsize; fcode < 65536; fcode *= 2)
01870 ++hshift;
01871 hshift = 8 - hshift;
01872
01873 hsize_reg = hsize;
01874 cl_hash((count_int) hsize);
01875
01876 output((code_int) ClearCode);
01877
01878 ent = *dp++;
01879 do
01880 {
01881 again:
01882
01883
01884
01885 c = *dp++;
01886 if(--left == 0)
01887 {
01888 if(interlaced)
01889 {
01890 do
01891 {
01892 switch(pass)
01893 {
01894 case 0:
01895 cury += 8;
01896 if(cury >= height)
01897 {
01898 pass++;
01899 cury = 4;
01900 }
01901 break;
01902 case 1:
01903 cury += 8;
01904 if(cury >= height)
01905 {
01906 pass++;
01907 cury = 2;
01908 }
01909 break;
01910 case 2:
01911 cury += 4;
01912 if(cury >= height)
01913 {
01914 pass++;
01915 cury = 1;
01916 }
01917 break;
01918 case 3:
01919 cury += 2;
01920 break;
01921 }
01922 } while(pass < 3 && cury >= height);
01923 if(cury >= height)
01924 goto done;
01925 dp = data + cury * width;
01926 left = width;
01927 c = *dp++;
01928 }
01929 else
01930 {
01931 goto done;
01932 }
01933 }
01934
01935
01936
01937
01938 fcode = (long) (((long) c << maxbits) + ent);
01939
01940 i = (((code_int) c << hshift) ^ ent);
01941 v = HashTabOf(i);
01942
01943 if(v == fcode)
01944 {
01945 ent = CodeTabOf(i);
01946 goto again;
01947 }
01948 else if(v >= 0)
01949 {
01950
01951
01952
01953 disp = hsize_reg - i;
01954 if(i == 0)
01955 disp = 1;
01956 do
01957 {
01958 if((i -= disp) < 0)
01959 i += hsize_reg;
01960
01961 v = HashTabOf(i);
01962 if(v == fcode)
01963 {
01964 ent = CodeTabOf(i);
01965 goto again;
01966 }
01967 } while(v > 0);
01968 }
01969
01970 output((code_int) ent);
01971 ent = c;
01972 if(free_ent < maxmaxcode)
01973 {
01974 CodeTabOf(i) = free_ent++;
01975 HashTabOf(i) = fcode;
01976 }
01977 else
01978 {
01979 cl_block();
01980 }
01981 } while(1);
01982 done:
01983
01984
01985
01986 output((code_int) ent);
01987 output((code_int) EOFCode);
01988
01989
01990
01991
01992 PUTBYTE(0x00, fp);
01993 }
01994
01995 #ifdef __sgi
01996 #pragma reset woff 1209
01997 #endif
01998
01999
02000
02001
02002
02003
02004
02005
02006
02007
02008
02009
02010
02011
02012
02013
02014
02015
02016 static unsigned long masks[] = { 0x0000,
02017 0x0001, 0x0003, 0x0007, 0x000F,
02018 0x001F, 0x003F, 0x007F, 0x00FF,
02019 0x01FF, 0x03FF, 0x07FF, 0x0FFF,
02020 0x1FFF, 0x3FFF, 0x7FFF, 0xFFFF };
02021
02022 static void output(code_int code)
02023 {
02024 cur_accum &= masks[cur_bits];
02025
02026 if(cur_bits > 0)
02027 {
02028 cur_accum |= ((long) code << cur_bits);
02029 }
02030 else
02031 cur_accum = code;
02032
02033 cur_bits += n_bits;
02034
02035 while(cur_bits >= 8)
02036 {
02037 char_out((unsigned int) (cur_accum & 0xff));
02038 cur_accum >>= 8;
02039 cur_bits -= 8;
02040 }
02041
02042
02043
02044
02045
02046 if(free_ent > maxcode || clear_flg)
02047 {
02048 if(clear_flg)
02049 {
02050 maxcode = MAXCODE(n_bits = g_init_bits);
02051 clear_flg = GIF_FALSE;
02052 }
02053 else
02054 {
02055 ++n_bits;
02056 if(n_bits == maxbits)
02057 maxcode = maxmaxcode;
02058 else
02059 maxcode = MAXCODE(n_bits);
02060 }
02061 }
02062
02063 if(code == EOFCode)
02064 {
02065
02066
02067
02068 while(cur_bits > 0)
02069 {
02070 char_out((unsigned int) (cur_accum & 0xff));
02071 cur_accum >>= 8;
02072 cur_bits -= 8;
02073 }
02074
02075 flush_char();
02076
02077 fflush(g_outfile);
02078 }
02079 }
02080
02081
02082
02083
02084 static void cl_block(void)
02085 {
02086 cl_hash((count_int) hsize);
02087 free_ent = ClearCode + 2;
02088 clear_flg = GIF_TRUE;
02089
02090 output((code_int) ClearCode);
02091 }
02092
02093
02094 static void cl_hash(count_int hsize)
02095 {
02096 int i;
02097
02098 for(i = 0; i < hsize; i++)
02099 htab[i] = -1;
02100 }
02101
02102
02103
02104
02105
02106
02107
02108
02109
02110 static int a_count;
02111
02112
02113
02114
02115 static char accum[256];
02116
02117
02118
02119
02120 static void char_init(void)
02121 {
02122 a_count = 0;
02123 }
02124
02125
02126
02127
02128
02129 static void char_out(int c)
02130 {
02131 accum[a_count++] = c;
02132 if(a_count == 255)
02133 flush_char();
02134 }
02135
02136
02137
02138
02139 static void flush_char(void)
02140 {
02141 if(a_count != 0)
02142 {
02143 PUTBYTE(a_count, g_outfile);
02144 fwrite(accum, 1, a_count, g_outfile);
02145 a_count = 0;
02146 }
02147 }
02148
02149
02150 #endif