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 #ifndef OSG_DO_DOC
00056 # ifdef OSG_WITH_GIF
00057 # define OSG_GIF_ARG(ARG) ARG
00058 # else
00059 # define OSG_GIF_ARG(ARG)
00060 # endif
00061 #else
00062 # define OSG_GIF_ARG(ARG) ARG
00063 #endif
00064
00065 #ifdef OSG_WITH_GIF
00066
00067
00083
00084 #define GIF_MAXCOLORS 256
00085
00086 typedef enum
00087 {
00088 gif_image,
00089 gif_comment,
00090 gif_text
00091 } GIFStreamType;
00092
00093 typedef enum
00094 {
00095 gif_no_disposal = 0,
00096 gif_keep_disposal = 1,
00097 gif_color_restore = 2,
00098 gif_image_restore = 3
00099 }
00100 GIFDisposalType;
00101
00102 typedef struct
00103 {
00104 int transparent;
00105 int delayTime;
00106 int inputFlag;
00107 GIFDisposalType disposal;
00108 } GIF89info;
00109
00110 typedef struct GIFData
00111 {
00112 GIF89info info;
00113 int x, y;
00114 int width, height;
00115 GIFStreamType type;
00116 union
00117 {
00118 struct
00119 {
00120 int cmapSize;
00121 unsigned char cmapData[GIF_MAXCOLORS][3];
00122 unsigned char *data;
00123 int interlaced;
00124 } image;
00125 struct
00126 {
00127 int fg, bg;
00128 int cellWidth, cellHeight;
00129 int len;
00130 char *text;
00131 } text;
00132 struct
00133 {
00134 int len;
00135 char *text;
00136 } comment;
00137 } data;
00138
00139 struct GIFData *next;
00140 } GIFData;
00141
00142 typedef struct
00143 {
00144 int width, height;
00145
00146 int colorResolution;
00147 int colorMapSize;
00148 int cmapSize;
00149 unsigned char cmapData[GIF_MAXCOLORS][3];
00150
00151 int background;
00152 int aspectRatio;
00153
00154 GIFData *data;
00155 } GIFStream;
00156
00157
00158 static GIFStream *GIFRead (char *);
00159 static GIFStream *GIFReadFP (FILE *);
00160 int GIFTest (char *);
00161 int GIFWrite (char *, GIFStream *, int);
00162 static int GIFWriteFP(FILE *, GIFStream *, int);
00163 static int GIFFree (GIFStream *);
00164
00165 #endif
00166
00167
00168 OSG_USING_NAMESPACE
00169
00170
00171
00172
00173
00174
00175
00176
00177 static const Char8 *suffixArray[] = {
00178 "gif"
00179 };
00180
00181 GIFImageFileType GIFImageFileType::_the ( "gif",
00182 suffixArray, sizeof(suffixArray) );
00183
00184
00185
00189 GIFImageFileType& GIFImageFileType::the (void)
00190 {
00191 return _the;
00192 }
00193
00194
00199 bool GIFImageFileType::read( ImagePtr &OSG_GIF_ARG(image),
00200 const Char8 *OSG_GIF_ARG(fileName))
00201 {
00202 bool retCode = false;
00203
00204 #ifdef OSG_WITH_GIF
00205 Image::PixelFormat pixelFormat = osg::Image::OSG_INVALID_PF;
00206 GIFStream *gifStream = GIFRead(const_cast <char *> (fileName));
00207 GIFData *gifData = 0;
00208 bool isColor;
00209 int i, j, destI, lineSize, lineEnd;
00210 unsigned red, green, blue;
00211 int transparentIndex;
00212 int width = 0, height = 0, channel = 0, xOff = 0, yOff = 0;
00213 unsigned char *srcData = 0, *destData = 0;
00214 int colorIndex;
00215 unsigned frameCount = 0, currentFrame = 0;
00216 unsigned char *colorMap = 0;
00217
00218
00219 int colorMapSize;
00220 Time frameDelay;
00221
00222 if(gifStream)
00223 {
00224 frameCount = 0;
00225 for(gifData = gifStream->data; gifData; gifData = gifData->next)
00226 {
00227 if(gifData->type == gif_image)
00228 frameCount++;
00229 }
00230 }
00231
00232 FDEBUG(("GIF Frames: %d\n", frameCount));
00233
00234 if(gifStream)
00235 {
00236 for(gifData = gifStream->data; gifData; gifData = gifData->next)
00237 {
00238 switch(gifData->type)
00239 {
00240 case gif_image:
00241 if(frameCount)
00242 {
00243 FDEBUG(("Try to copy GIF Anim Frame %d/%d\n",
00244 (currentFrame + 1), frameCount));
00245 }
00246
00247
00248 transparentIndex = gifData->info.transparent;
00249 frameDelay = float(gifData->info.delayTime) / 100.0f;
00250 width = gifData->width;
00251 height = gifData->height;
00252 xOff = gifData->x;
00253 yOff = gifData->y;
00254
00255
00256 isColor = false;
00257 if(gifData->data.image.cmapSize > 0)
00258 {
00259 colorMapSize = gifData->data.image.cmapSize;
00260 colorMap = (unsigned char *) gifData->data.image.cmapData;
00261
00262
00263 }
00264 else if(gifStream->cmapSize > 0)
00265 {
00266 colorMapSize = gifStream->cmapSize;
00267 colorMap = (unsigned char *) gifStream->cmapData;
00268
00269
00270 }
00271 else
00272 {
00273 FWARNING(("Bad color map in GIFImageFileType::read()\n"));
00274 colorMapSize = 0;
00275 }
00276
00277 for(i = 0; i < colorMapSize; i++)
00278 {
00279 if(i != transparentIndex)
00280 {
00281 red = colorMap[i * 3 + 0];
00282 green = colorMap[i * 3 + 1];
00283 blue = colorMap[i * 3 + 2];
00284 if(red != green || red != blue)
00285 {
00286 isColor = true;
00287 break;
00288 }
00289 }
00290 }
00291
00292
00293 channel = (isColor ? 3 : 1) + (transparentIndex >= 0 ? 1 : 0);
00294
00295 if(currentFrame)
00296 {
00297
00298 if((channel == image->getBpp()) &&
00299 (width == image->getWidth()) &&
00300 (height == image->getHeight()))
00301 {
00302 destData = image->getData(0, currentFrame);
00303 }
00304 else
00305 {
00306 FWARNING(("GIF Anim with misc. image dimensions\n"));
00307
00308 fprintf(stderr, "%d %d %d %d %d %d\n",
00309 channel,
00310 image->getBpp(),
00311 gifData->x,
00312 gifData->y,
00313 gifData->width,
00314 gifData->height);
00315
00316 destData = image->getData(0, currentFrame);
00317
00318 memcpy(destData,
00319 image->getData(0, 0),
00320 image->getWidth () *
00321 image->getHeight() *
00322 channel);
00323
00324
00325 }
00326 }
00327 else
00328 {
00329 switch(channel)
00330 {
00331 case 1:
00332 pixelFormat = Image::OSG_L_PF;
00333 break;
00334 case 2:
00335 pixelFormat = Image::OSG_LA_PF;
00336 break;
00337 case 3:
00338 pixelFormat = Image::OSG_RGB_PF;
00339 break;
00340 case 4:
00341 pixelFormat = Image::OSG_RGBA_PF;
00342 break;
00343 };
00344 image->set(pixelFormat, width, height, 1, 1, frameCount,
00345 frameDelay);
00346 destData = image->getData();
00347 }
00348
00349
00350 lineSize = image->getWidth() * channel;
00351 lineEnd = width * channel + xOff * channel;
00352 srcData = gifData->data.image.data;
00353 destData = destData + ((image->getHeight() - yOff - 1) * lineSize);
00354
00355 switch(channel)
00356 {
00357 case 1:
00358 destI = 0;
00359 for(i = width * height; i--;)
00360 {
00361 destData[destI++] = colorMap[*srcData++ *3];
00362 if(destI >= lineSize)
00363 {
00364 destI = 0;
00365 destData -= lineSize;
00366 }
00367 }
00368 break;
00369
00370 case 2:
00371 destI = 0;
00372 for(i = width * height; i--;)
00373 {
00374 colorIndex = *srcData++;
00375 if(colorIndex == transparentIndex)
00376 {
00377 destData[destI++] = 0;
00378 destData[destI++] = 0;
00379 }
00380 else
00381 {
00382 destData[destI++] = colorMap[colorIndex * 3];
00383 destData[destI++] = 255;
00384 }
00385
00386 if(destI >= lineSize)
00387 {
00388 destI = 0;
00389 destData -= lineSize;
00390 }
00391 }
00392 break;
00393
00394 case 3:
00395 destI = 0;
00396 for(i = width * height; i--;)
00397 {
00398 colorIndex = *srcData++;
00399 for(j = 0; j < 3; j++)
00400 {
00401 destData[destI++] = colorMap[colorIndex * 3 + j];
00402 }
00403
00404 if(destI >= lineSize)
00405 {
00406 destI = 0;
00407 destData -= lineSize;
00408 }
00409 }
00410 break;
00411
00412 case 4:
00413 destI = xOff * 4;
00414
00415 for(i = width * height; i--;)
00416 {
00417 colorIndex = *srcData++;
00418 if(colorIndex == transparentIndex)
00419 {
00420
00421
00422
00423
00424
00425 destI += 4;
00426 }
00427 else
00428 {
00429 for(j = 0; j < 3; j++)
00430 {
00431 destData[destI++] =
00432 colorMap[colorIndex * 3 + j];
00433 }
00434
00435 destData[destI++] = 255;
00436 }
00437
00438 if(destI >= lineEnd)
00439 {
00440 destI = xOff * 4;
00441 destData -= lineSize;
00442 }
00443 }
00444 break;
00445 }
00446
00447 retCode = true;
00448
00449 currentFrame++;
00450
00451 break;
00452 case gif_comment:
00453 break;
00454 case gif_text:
00455 break;
00456 }
00457 }
00458
00459 GIFFree(gifStream);
00460 }
00461 else
00462 retCode = false;
00463 #endif
00464 return retCode;
00465 }
00466
00467
00472 bool GIFImageFileType::write(const ImagePtr &,
00473 const Char8 *OSG_CHECK_ARG(fileName))
00474 {
00475 #ifdef OSG_WITH_GIF
00476 SWARNING << getMimeType() << " write is not implemented " << endLog;
00477
00478 #else
00479 SWARNING <<
00480 getMimeType() <<
00481 " write is not compiled into the current binary " <<
00482 endLog;
00483 #endif
00484 return false;
00485 }
00486
00487 bool GIFImageFileType::validateHeader( const Char8 *fileName, bool &implemented)
00488 {
00489 implemented = true;
00490
00491 if(fileName == NULL)
00492 return false;
00493
00494 FILE *file = fopen(fileName, "rb");
00495 if(file == NULL)
00496 return false;
00497
00498 std::string magic;
00499 magic.resize(4);
00500 fread((void *) &magic[0], 4, 1, file);
00501 fclose(file);
00502
00503 if(magic == "GIF8")
00504 {
00505 return true;
00506 }
00507
00508 return false;
00509 }
00510
00511
00515 GIFImageFileType::GIFImageFileType(const Char8 *mimeType,
00516 const Char8 *suffixArray[],
00517 UInt16 suffixByteCount) :
00518 ImageFileType(mimeType,suffixArray, suffixByteCount)
00519 {
00520 return;
00521 }
00522
00523
00527 GIFImageFileType::GIFImageFileType(const GIFImageFileType &obj) :
00528 ImageFileType(obj)
00529 {
00530 return;
00531 }
00532
00533
00537 GIFImageFileType::~GIFImageFileType(void)
00538 {
00539 return;
00540 }
00541
00542
00543
00544
00545
00546
00547
00548
00549
00550
00551
00552 #ifdef OSG_WITH_GIF
00553
00554
00555
00556
00557
00558
00559
00560
00561
00562
00563
00564
00565
00566
00567
00568
00569
00570
00571
00572
00573
00574
00575
00576
00577
00578
00579 #define GIF_TRUE 1
00580 #define GIF_FALSE 0
00581
00582 #define MAX_LWZ_BITS 12
00583
00584 #define INTERLACE 0x40
00585 #define LOCALCOLORMAP 0x80
00586
00587 #define BitSet(byte, bit) (((byte) & (bit)) == (bit))
00588 #define ReadOK(file, buffer, len) (fread(buffer, len, 1, file) != 0)
00589 #define MKINT(a, b) (((b) << 8) | (a))
00590 #define NEW(x) ((x *) malloc(sizeof(x)))
00591
00592
00593
00594
00595
00596
00597
00598 #if 0
00599 #define INFO_MSG(fmt) pm_message fmt
00600 #define ERROR(str) pm_error(str)
00601 #else
00602 #if 0
00603 #define INFO_MSG(fmt)
00604 #define ERROR(str) do { RWSetMsg(str); longjmp(setjmp_buffer, 1); } while(0)
00605 #else
00606 #define INFO_MSG(fmt)
00607 #define GIF_ERROR(str) longjmp(setjmp_buffer, 1)
00608 #endif
00609 #endif
00610
00611
00612
00613 static int readColorMap(FILE *, int, unsigned char [GIF_MAXCOLORS][3]);
00614 static int GetDataBlock(FILE *, unsigned char *);
00615 static void readImage(FILE *, int, int, int, unsigned char *);
00616
00617 static jmp_buf setjmp_buffer;
00618
00619 static int verbose = GIF_FALSE;
00620
00621
00622 int GIFTest(char *file)
00623 {
00624 FILE *fd = fopen(file, "rb");
00625 char buf[10];
00626 int ret = GIF_FALSE;
00627
00628 if (fd != NULL && ReadOK(fd, buf, 6)) {
00629 if ((strncmp(buf, "GIF", 3) == 0) &&
00630 ((strncmp(buf + 3, "87a", 3) != 0) ||
00631 (strncmp(buf + 3, "89a", 3) != 0)))
00632 ret = GIF_TRUE;
00633 }
00634
00635 fclose(fd);
00636
00637 return ret;
00638 }
00639
00640
00641 static GIFStream *GIFReadFP(FILE *fd)
00642 {
00643 unsigned char buf[256];
00644 unsigned char c;
00645 GIFStream *gifStream = 0;
00646 GIFData *cur, **end;
00647 GIF89info info = {0};
00648 int resetInfo = GIF_TRUE;
00649 int n;
00650
00651 if(fd == NULL)
00652 return NULL;
00653
00654 if(setjmp(setjmp_buffer))
00655 goto out;
00656
00657 if(!ReadOK(fd, buf, 6))
00658 {
00659 GIF_ERROR("error reading magic number");
00660 }
00661
00662 if(strncmp((char *) buf, "GIF", 3) != 0)
00663 GIF_ERROR("not a GIF file");
00664
00665 if((strncmp(((char *) (buf)) + 3, "87a", 3) != 0) &&
00666 (strncmp(((char *) (buf)) + 3, "89a", 3) != 0))
00667 {
00668 GIF_ERROR("bad version number, not '87a' or '89a'");
00669 }
00670
00671 if(!ReadOK(fd, buf, 7))
00672 {
00673 GIF_ERROR("failed to read screen descriptor");
00674 }
00675
00676 gifStream = NEW(GIFStream);
00677
00678 gifStream->width = MKINT(buf[0], buf[1]);
00679 gifStream->height = MKINT(buf[2], buf[3]);
00680
00681 gifStream->cmapSize = 2 << (buf[4] & 0x07);
00682 gifStream->colorMapSize = gifStream->cmapSize;
00683 gifStream->colorResolution = ((int) (buf[4] & 0x70) >> 3) + 1;
00684 gifStream->background = buf[5];
00685 gifStream->aspectRatio = buf[6];
00686
00687 gifStream->data = NULL;
00688
00689 end = &gifStream->data;
00690
00691
00692
00693
00694 if(BitSet(buf[4], LOCALCOLORMAP))
00695 {
00696 if(readColorMap(fd, gifStream->cmapSize, gifStream->cmapData))
00697 {
00698 GIF_ERROR("unable to get global colormap");
00699 }
00700 }
00701 else
00702 {
00703 gifStream->cmapSize = 0;
00704 gifStream->background = -1;
00705 }
00706
00707 if(gifStream->aspectRatio != 0 && gifStream->aspectRatio != 49)
00708 {
00709 INFO_MSG(("warning - non-square pixels"));
00710 }
00711
00712 while(ReadOK(fd, &c, 1) && c != ';')
00713 {
00714 if(resetInfo)
00715 {
00716 info.disposal = (GIFDisposalType) 0;
00717 info.inputFlag = 0;
00718 info.delayTime = 0;
00719 info.transparent = -1;
00720 resetInfo = GIF_FALSE;
00721 }
00722
00723 cur = NULL;
00724
00725 if(c == '!')
00726 {
00727 if(!ReadOK(fd, &c, 1))
00728 {
00729 GIF_ERROR("EOF / read error on extention function code");
00730 }
00731
00732 if(c == 0xf9)
00733 {
00734 (void) GetDataBlock(fd, buf);
00735 info.disposal = (GIFDisposalType) ((buf[0] >> 2) & 0x7);
00736 info.inputFlag = (buf[0] >> 1) & 0x1;
00737 info.delayTime = MKINT(buf[1], buf[2]);
00738 if(BitSet(buf[0], 0x1))
00739 info.transparent = buf[3];
00740
00741 while(GetDataBlock(fd, buf) != 0)
00742 ;
00743 }
00744 else if(c == 0xfe || c == 0x01)
00745 {
00746 int len = 0;
00747 int size = 256;
00748 char *text = NULL;
00749
00750
00751
00752
00753 cur = NEW(GIFData);
00754
00755 if(c == 0x01)
00756 {
00757 (void) GetDataBlock(fd, buf);
00758
00759 cur->type = gif_text;
00760 cur->info = info;
00761 cur->x = MKINT(buf[0], buf[1]);
00762 cur->y = MKINT(buf[2], buf[3]);
00763 cur->width = MKINT(buf[4], buf[5]);
00764 cur->height = MKINT(buf[6], buf[7]);
00765
00766 cur->data.text.cellWidth = buf[8];
00767 cur->data.text.cellHeight = buf[9];
00768 cur->data.text.fg = buf[10];
00769 cur->data.text.bg = buf[11];
00770
00771 resetInfo = GIF_TRUE;
00772 }
00773 else
00774 {
00775 cur->type = gif_comment;
00776 }
00777
00778 text = (char *) malloc(size);
00779
00780 while((n = GetDataBlock(fd, buf)) != 0)
00781 {
00782 if(n + len >= size)
00783 {
00784 text = (char *) realloc(text, size += 256);
00785 }
00786
00787 memcpy(text + len, buf, n);
00788 len += n;
00789 }
00790
00791 if(c == 0x01)
00792 {
00793 cur->data.text.len = len;
00794 cur->data.text.text = text;
00795 }
00796 else
00797 {
00798 cur->data.comment.len = len;
00799 cur->data.comment.text = text;
00800 }
00801 }
00802 else
00803 {
00804
00805
00806
00807 while(GetDataBlock(fd, buf) > 0)
00808 ;
00809 }
00810 }
00811 else if(c == ',')
00812 {
00813 if(!ReadOK(fd, buf, 9))
00814 {
00815 GIF_ERROR("couldn't read left/top/width/height");
00816 }
00817
00818 cur = NEW(GIFData);
00819
00820 cur->type = gif_image;
00821 cur->info = info;
00822 cur->x = MKINT(buf[0], buf[1]);
00823 cur->y = MKINT(buf[2], buf[3]);
00824 cur->width = MKINT(buf[4], buf[5]);
00825 cur->height = MKINT(buf[6], buf[7]);
00826 cur->data.image.cmapSize = 1 << ((buf[8] & 0x07) + 1);
00827 if(BitSet(buf[8], LOCALCOLORMAP))
00828 {
00829 if(readColorMap(fd, cur->data.image.cmapSize,
00830 cur->data.image.cmapData))
00831 {
00832 GIF_ERROR("unable to get local colormap");
00833 }
00834 }
00835 else
00836 {
00837 cur->data.image.cmapSize = 0;
00838 }
00839
00840 cur->data.image.data = (unsigned char *)
00841 malloc(cur->width * cur->height);
00842 cur->data.image.interlaced = BitSet(buf[8], INTERLACE);
00843 readImage(fd, BitSet(buf[8], INTERLACE), cur->width, cur->height,
00844 cur->data.image.data);
00845
00846 resetInfo = GIF_TRUE;
00847 }
00848 else
00849 {
00850 INFO_MSG(("bogus character 0x%02x, ignoring", (int) c));
00851 }
00852
00853 if(cur != NULL)
00854 {
00855 *end = cur;
00856 end = &cur->next;
00857 cur->next = NULL;
00858 }
00859 }
00860
00861 if(c != ';')
00862 GIF_ERROR("EOF / data stream");
00863
00864 out:
00865 return gifStream;
00866 }
00867
00868
00869 static GIFStream *GIFRead(char *file)
00870 {
00871 FILE *fp = fopen(file, "rb");
00872 GIFStream *gifStream = NULL;
00873
00874 if(fp != NULL)
00875 {
00876 gifStream = GIFReadFP(fp);
00877 fclose(fp);
00878 }
00879
00880 return gifStream;
00881 }
00882
00883
00884 static int GIFFreeData(GIFData *gifData)
00885 {
00886 int retCode = 0;
00887
00888 if(gifData)
00889 {
00890 switch(gifData->type)
00891 {
00892 case gif_image:
00893 if(gifData->data.image.data)
00894 {
00895 free(gifData->data.image.data);
00896 }
00897 break;
00898 case gif_comment:
00899 if(gifData->data.comment.text)
00900 {
00901 free(gifData->data.comment.text);
00902 }
00903 break;
00904 case gif_text:
00905 if(gifData->data.text.text)
00906 {
00907 free(gifData->data.text.text);
00908 }
00909 break;
00910 }
00911
00912 retCode = 1;
00913 }
00914 else
00915 retCode = 0;
00916
00917 return retCode;
00918 }
00919
00920
00921 static int GIFFree(GIFStream *gifStream)
00922 {
00923 int retCode = 1;
00924 GIFData *gifData, *gifNext;
00925
00926 if(gifStream)
00927 {
00928 gifData = gifStream->data;
00929 while(gifData)
00930 {
00931 gifNext = gifData->next;
00932 GIFFreeData(gifData);
00933 free(gifData);
00934 gifData = gifNext;
00935 }
00936 }
00937
00938 return retCode;
00939 }
00940
00941
00942 static int readColorMap(FILE *fd, int size, unsigned char data[GIF_MAXCOLORS][3])
00943 {
00944 int i;
00945 unsigned char rgb[3 * GIF_MAXCOLORS];
00946 unsigned char *cp = rgb;
00947
00948 if(!ReadOK(fd, rgb, size * 3))
00949 return GIF_TRUE;
00950
00951 for(i = 0; i < size; i++)
00952 {
00953 data[i][0] = *cp++;
00954 data[i][1] = *cp++;
00955 data[i][2] = *cp++;
00956 }
00957
00958 return GIF_FALSE;
00959 }
00960
00961
00962
00963
00964 static int ZeroDataBlock = GIF_FALSE;
00965
00966
00967
00968 static int GetDataBlock(FILE *fd, unsigned char *buf)
00969 {
00970 unsigned char count;
00971
00972 if(!ReadOK(fd, &count, 1))
00973 {
00974 INFO_MSG(("error in getting DataBlock size"));
00975 return -1;
00976 }
00977
00978 ZeroDataBlock = count == 0;
00979
00980 if((count != 0) && (!ReadOK(fd, buf, count)))
00981 {
00982 INFO_MSG(("error in reading DataBlock"));
00983 return -1;
00984 }
00985
00986 return count;
00987 }
00988
00989
00990
00991
00992
00993
00994
00995
00996 static int curbit, lastbit, get_done, last_byte;
00997 static int return_clear;
00998
00999
01000
01001
01002 static int stack[(1 << (MAX_LWZ_BITS)) * 2], *sp;
01003 static int code_size, set_code_size;
01004 static int max_code, max_code_size;
01005 static int clear_code, end_code;
01006
01007
01008
01009 static void initLWZ(int input_code_size)
01010 {
01011
01012
01013 set_code_size = input_code_size;
01014 code_size = set_code_size + 1;
01015 clear_code = 1 << set_code_size ;
01016 end_code = clear_code + 1;
01017 max_code_size = 2 * clear_code;
01018 max_code = clear_code + 2;
01019
01020 curbit = lastbit = 0;
01021 last_byte = 2;
01022 get_done = GIF_FALSE;
01023
01024 return_clear = GIF_TRUE;
01025
01026 sp = stack;
01027 }
01028
01029
01030 static int nextCode(FILE *fd, int code_size)
01031 {
01032 static unsigned char buf[280];
01033 static int maskTbl[16] =
01034 {
01035 0x0000,
01036 0x0001,
01037 0x0003,
01038 0x0007,
01039 0x000f,
01040 0x001f,
01041 0x003f,
01042 0x007f,
01043 0x00ff,
01044 0x01ff,
01045 0x03ff,
01046 0x07ff,
01047 0x0fff,
01048 0x1fff,
01049 0x3fff,
01050 0x7fff,
01051 };
01052 int i, j, ret, end;
01053
01054 if(return_clear)
01055 {
01056 return_clear = GIF_FALSE;
01057 return clear_code;
01058 }
01059
01060 end = curbit + code_size;
01061
01062 if(end >= lastbit)
01063 {
01064 int count;
01065
01066 if(get_done)
01067 {
01068 if(curbit >= lastbit)
01069 {
01070 GIF_ERROR("ran off the end of my bits");
01071 }
01072
01073 return -1;
01074 }
01075
01076 buf[0] = buf[last_byte - 2];
01077 buf[1] = buf[last_byte - 1];
01078
01079 if((count = GetDataBlock(fd, &buf[2])) == 0)
01080 get_done = GIF_TRUE;
01081
01082 last_byte = 2 + count;
01083 curbit = (curbit - lastbit) + 16;
01084 lastbit = (2 + count) * 8;
01085
01086 end = curbit + code_size;
01087 }
01088
01089 j = end / 8;
01090 i = curbit / 8;
01091
01092 if(i == j)
01093 ret = buf[i];
01094 else if(i + 1 == j)
01095 ret = buf[i] | (buf[i + 1] << 8);
01096 else
01097 {
01098 ret = buf[i] | (buf[i + 1] << 8) | (buf[i + 2] << 16);
01099 }
01100
01101 ret = (ret >> (curbit % 8)) & maskTbl[code_size];
01102
01103 curbit += code_size;
01104
01105 return ret;
01106 }
01107
01108 #define readLWZ(fd) ((sp > stack) ? *--sp : nextLWZ(fd))
01109
01110
01111 static int nextLWZ(FILE *fd)
01112 {
01113 static int table[2][(1 << MAX_LWZ_BITS)];
01114 static int firstcode, oldcode;
01115 int code, incode;
01116 register int i;
01117
01118 while((code = nextCode(fd, code_size)) >= 0)
01119 {
01120 if(code == clear_code)
01121 {
01122 for(i = 0; i < clear_code; ++i)
01123 {
01124 table[0][i] = 0;
01125 table[1][i] = i;
01126 }
01127
01128 for(; i < (1 << MAX_LWZ_BITS); ++i)
01129 table[0][i] = table[1][i] = 0;
01130 code_size = set_code_size + 1;
01131 max_code_size = 2 * clear_code;
01132 max_code = clear_code + 2;
01133 sp = stack;
01134 do
01135 {
01136 firstcode = oldcode = nextCode(fd, code_size);
01137 } while(firstcode == clear_code);
01138
01139 return firstcode;
01140 }
01141
01142 if(code == end_code)
01143 {
01144 int count;
01145 unsigned char buf[260];
01146
01147 if(ZeroDataBlock)
01148 return -2;
01149
01150 while((count = GetDataBlock(fd, buf)) > 0)
01151 ;
01152
01153 if(count != 0)
01154 {
01155 INFO_MSG(("missing EOD in data stream"));
01156 }
01157
01158 return -2;
01159 }
01160
01161 incode = code;
01162
01163 if(code >= max_code)
01164 {
01165 *sp++ = firstcode;
01166 code = oldcode;
01167 }
01168
01169 while(code >= clear_code)
01170 {
01171 *sp++ = table[1][code];
01172 if(code == table[0][code])
01173 {
01174 GIF_ERROR("circular table entry BIG ERROR");
01175 }
01176
01177 code = table[0][code];
01178 }
01179
01180 *sp++ = firstcode = table[1][code];
01181
01182 if((code = max_code) < (1 << MAX_LWZ_BITS))
01183 {
01184 table[0][code] = oldcode;
01185 table[1][code] = firstcode;
01186 ++max_code;
01187 if((max_code >= max_code_size) &&
01188 (max_code_size < (1 << MAX_LWZ_BITS)))
01189 {
01190 max_code_size *= 2;
01191 ++code_size;
01192 }
01193 }
01194
01195 oldcode = incode;
01196
01197 if(sp > stack)
01198 return *--sp;
01199 }
01200
01201 return code;
01202 }
01203
01204
01205 static void readImage(FILE *fd, int interlace, int width, int height,
01206 unsigned char *data)
01207 {
01208 unsigned char *dp, c;
01209
01210 int v, xpos = 0, ypos = 0;
01211
01212
01213
01214
01215
01216 if(!ReadOK(fd, &c, 1))
01217 {
01218 GIF_ERROR("EOF / read error on image data");
01219 }
01220
01221 initLWZ(c);
01222
01223 if(verbose)
01224 {
01225 INFO_MSG(("reading %d by %d%s GIF image", width, height, interlace ?
01226 " interlaced" : ""));
01227 }
01228
01229 if(interlace)
01230 {
01231 int i;
01232 int pass = 0, step = 8;
01233
01234 for(i = 0; i < height; i++)
01235 {
01236 dp = &data[width * ypos];
01237 for(xpos = 0; xpos < width; xpos++)
01238 {
01239 if((v = readLWZ(fd)) < 0)
01240 goto fini;
01241
01242 *dp++ = v;
01243 }
01244
01245 if((ypos += step) >= height)
01246 {
01247 do
01248 {
01249 if(pass++ > 0)
01250 step /= 2;
01251 ypos = step / 2;
01252 } while(ypos > height);
01253 }
01254 }
01255 }
01256 else
01257 {
01258 dp = data;
01259 for(ypos = 0; ypos < height; ypos++)
01260 {
01261 for(xpos = 0; xpos < width; xpos++)
01262 {
01263 if((v = readLWZ(fd)) < 0)
01264 goto fini;
01265
01266 *dp++ = v;
01267 }
01268 }
01269 }
01270
01271 fini:
01272 if(readLWZ(fd) >= 0)
01273 {
01274 INFO_MSG(("too much input data, ignoring extra..."));
01275 }
01276
01277 return;
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
01313
01314
01315
01316
01317
01318
01319
01320
01321
01322
01323
01324
01325
01326
01327
01328 #define GIF_TRUE 1
01329 #define GIF_FALSE 0
01330
01331 #define PUTBYTE(v, fp) putc(v, fp)
01332 #define PUTWORD(v, fp) \
01333 do \
01334 { \
01335 putc(((v) & 0xff), fp); \
01336 putc((((v) >> 8) & 0xff), fp); \
01337 } while(0)
01338
01339
01340
01341 typedef int code_int;
01342
01343 typedef long int count_int;
01344
01345 static void putImage(FILE *, int, int, int, int, unsigned char *);
01346 static void putColorMap(FILE *, int, unsigned char[GIF_MAXCOLORS][3]);
01347 static void putDataBlocks(FILE *fp, int, unsigned char *);
01348 static void putGif89Info(FILE *, GIF89info *);
01349
01350 static void output(code_int code);
01351 static void cl_block(void);
01352 static void cl_hash(count_int hsize);
01353 static void char_init(void);
01354 static void char_out(int c);
01355 static void flush_char(void);
01356
01357
01358
01359
01360 struct cval
01361 {
01362 int idx, cnt;
01363 };
01364
01365
01366 static int cvalCMP(struct cval *a, struct cval *b)
01367 {
01368 return b->cnt - a->cnt;
01369 }
01370
01371
01372 static int optimizeCMAP(GIFStream *stream)
01373 {
01374 GIFData *cur = 0, *img = 0;
01375 int count = 0;
01376
01377 for(cur = stream->data; cur != NULL; cur = cur->next)
01378 {
01379 if(cur->type == gif_image)
01380 {
01381 img = cur;
01382 count++;
01383 }
01384 }
01385
01386
01387
01388
01389
01390 if(count == 0 || count > 1)
01391 return 0;
01392
01393
01394
01395
01396
01397
01398 {
01399 int size;
01400 unsigned char *dp = img->data.image.data;
01401 unsigned char *ep = dp + img->width * img->height;
01402 struct cval vals[256];
01403 int i;
01404
01405
01406 unsigned char tmap[256][3], rmap[256];
01407
01408 if((size = img->data.image.cmapSize) == 0)
01409 size = stream->cmapSize;
01410
01411 for(i = 0; i < size; i++)
01412 {
01413 vals[i].idx = i;
01414 vals[i].cnt = 0;
01415 }
01416
01417 for(dp = img->data.image.data, i = 0; dp < ep; i++, dp++)
01418 vals[*dp].cnt++;
01419
01420
01421
01422
01423 qsort(vals, size, sizeof(vals[0]),
01424 (int(*) (const void *, const void *)) cvalCMP);
01425
01426 for(i = 0; i < size; i++)
01427 if(vals[i].idx != i)
01428 break;
01429
01430
01431
01432
01433 if(i == size)
01434 return 1;
01435 for(i = 0; i < size; i++)
01436 rmap[vals[i].idx] = i;
01437
01438
01439
01440
01441 for(dp = img->data.image.data, i = 0; dp < ep; i++, dp++)
01442 *dp = rmap[*dp];
01443 if(img->info.transparent != -1)
01444 {
01445 img->info.transparent = rmap[img->info.transparent];
01446 }
01447
01448
01449
01450
01451 if(img->data.image.cmapSize != 0)
01452 {
01453 for(i = 0; i < size; i++)
01454 {
01455 stream->cmapData[i][0] = img->data.image.cmapData[i][0];
01456 stream->cmapData[i][1] = img->data.image.cmapData[i][1];
01457 stream->cmapData[i][2] = img->data.image.cmapData[i][2];
01458 }
01459
01460 img->data.image.cmapSize = 0;
01461 stream->cmapSize = size;
01462 }
01463
01464
01465
01466
01467 for(i = 0; i < size; i++)
01468 {
01469 tmap[i][0] = stream->cmapData[i][0];
01470 tmap[i][1] = stream->cmapData[i][1];
01471 tmap[i][2] = stream->cmapData[i][2];
01472 }
01473
01474 for(i = 0; i < size; i++)
01475 {
01476 stream->cmapData[rmap[i]][0] = tmap[i][0];
01477 stream->cmapData[rmap[i]][1] = tmap[i][1];
01478 stream->cmapData[rmap[i]][2] = tmap[i][2];
01479 }
01480 }
01481
01482 return 1;
01483 }
01484
01485
01486
01487
01488 static int binaryLog(int val)
01489 {
01490 int i;
01491
01492 if(val == 0)
01493 return 0;
01494
01495 for(i = 1; i <= 8; i++)
01496 if(val <= (1 << i))
01497 return i;
01498 return 8;
01499 }
01500
01501 #ifdef __sgi
01502 #pragma set woff 1209
01503 #endif
01504
01505
01506 static int GIFWriteFP(FILE *fp, GIFStream *stream, int optimize)
01507 {
01508 GIFData *cur;
01509 int flag = GIF_FALSE;
01510 int c;
01511 int globalBitsPP = 0;
01512 int resolution;
01513
01514 if(fp == NULL)
01515 return GIF_TRUE;
01516 if(stream == NULL)
01517 return GIF_FALSE;
01518
01519
01520
01521
01522
01523 resolution = binaryLog(stream->cmapSize) - 1;
01524 for(cur = stream->data; !flag && cur != NULL; cur = cur->next)
01525 {
01526 if(cur->type == gif_text || cur->type == gif_comment)
01527 {
01528 flag = GIF_TRUE;
01529 }
01530 else if(cur->type == gif_image)
01531 {
01532 int v = binaryLog(cur->data.image.cmapSize);
01533
01534 if(v > resolution)
01535 resolution = v;
01536
01537
01538
01539
01540 if(cur->info.transparent != -1 ||
01541 cur->info.delayTime != 0 ||
01542 cur->info.inputFlag != 0 ||
01543 cur->info.disposal != 0)
01544 flag = GIF_TRUE;
01545 }
01546 }
01547
01548
01549
01550
01551 if(optimize)
01552 optimize = optimizeCMAP(stream);
01553
01554 fwrite(flag ? "GIF89a" : "GIF87a", 1, 6, fp);
01555
01556 PUTWORD(stream->width, fp);
01557 PUTWORD(stream->height, fp);
01558
01559
01560
01561
01562 c = ((resolution & 0x07) << 5) | 0x00;
01563 if(stream->cmapSize != 0)
01564 {
01565 globalBitsPP = binaryLog(stream->cmapSize);
01566 c |= 0x80;
01567 c |= globalBitsPP - 1;
01568 }
01569
01570
01571
01572
01573 if(optimize)
01574 c |= 0x08;
01575 PUTBYTE(c, fp);
01576
01577 PUTBYTE(stream->background, fp);
01578 PUTBYTE(stream->aspectRatio, fp);
01579
01580 putColorMap(fp, stream->cmapSize, stream->cmapData);
01581
01582 for(cur = stream->data; cur != NULL; cur = cur->next)
01583 {
01584 if(cur->type == gif_image)
01585 {
01586 int bpp;
01587
01588 putGif89Info(fp, &cur->info);
01589
01590 PUTBYTE(0x2c, fp);
01591 PUTWORD(cur->x, fp);
01592 PUTWORD(cur->y, fp);
01593 PUTWORD(cur->width, fp);
01594 PUTWORD(cur->height, fp);
01595
01596 c = cur->data.image.interlaced ? 0x40 : 0x00;
01597 if(cur->data.image.cmapSize != 0)
01598 {
01599 bpp = binaryLog(cur->data.image.cmapSize);
01600 c |= 0x80;
01601 c |= bpp;
01602 }
01603 else
01604 {
01605 bpp = globalBitsPP;
01606 }
01607
01608 PUTBYTE(c, fp);
01609
01610 putColorMap(fp, cur->data.image.cmapSize, cur->data.image.cmapData);
01611
01612 putImage(fp, cur->data.image.interlaced, bpp, cur->width,
01613 cur->height, cur->data.image.data);
01614 }
01615 else if(cur->type == gif_comment)
01616 {
01617 PUTBYTE('!', fp);
01618 PUTBYTE(0xfe, fp);
01619 putDataBlocks(fp, cur->data.comment.len,
01620 (unsigned char *) cur->data.comment.text);
01621 }
01622 else if(cur->type == gif_text)
01623 {
01624 putGif89Info(fp, &cur->info);
01625
01626 PUTBYTE('!', fp);
01627 PUTBYTE(0x01, fp);
01628
01629 PUTWORD(cur->x, fp);
01630 PUTWORD(cur->y, fp);
01631 PUTWORD(cur->width, fp);
01632 PUTWORD(cur->height, fp);
01633
01634 PUTBYTE(cur->data.text.cellWidth, fp);
01635 PUTBYTE(cur->data.text.cellHeight, fp);
01636 PUTBYTE(cur->data.text.fg, fp);
01637 PUTBYTE(cur->data.text.bg, fp);
01638
01639 putDataBlocks(fp, cur->data.text.len,
01640 (unsigned char *) cur->data.text.text);
01641 }
01642 }
01643
01644
01645
01646
01647 PUTBYTE(';', fp);
01648
01649 return GIF_FALSE;
01650 }
01651
01652 #ifdef __sgi
01653 #pragma reset woff 1209
01654 #endif
01655
01656
01657 int GIFWrite(char *file, GIFStream *stream, int optimize)
01658 {
01659 if(stream != NULL)
01660 {
01661 FILE *fp = fopen(file, "wb");
01662
01663 if(fp != NULL)
01664 {
01665 int s = GIFWriteFP(fp, stream, optimize);
01666 fclose(fp);
01667 return s;
01668 }
01669 }
01670
01671 return GIF_TRUE;
01672 }
01673
01674
01675 static void putColorMap(FILE *fp, int size, unsigned char data[GIF_MAXCOLORS][3])
01676 {
01677 int i;
01678
01679 for(i = 0; i < size; i++)
01680 {
01681 PUTBYTE(data[i][0], fp);
01682 PUTBYTE(data[i][1], fp);
01683 PUTBYTE(data[i][2], fp);
01684 }
01685 }
01686
01687
01688 static void putDataBlocks(FILE *fp, int size, unsigned char *data)
01689 {
01690 int n;
01691
01692 while(size > 0)
01693 {
01694 n = size > 255 ? 255 : size;
01695
01696 PUTBYTE(n, fp);
01697 fwrite(data, 1, n, fp);
01698 data += n;
01699 size -= n;
01700 }
01701
01702 PUTBYTE(0, fp);
01703 }
01704
01705 #ifdef __sgi
01706 #pragma set woff 1209
01707 #endif
01708
01709
01710 static void putGif89Info(FILE *fp, GIF89info *info)
01711 {
01712 unsigned char c;
01713
01714 if(info->transparent == -1 &&
01715 info->delayTime == 0 &&
01716 info->inputFlag == 0 &&
01717 info->disposal == 0)
01718 return;
01719
01720 PUTBYTE('!', fp);
01721 PUTBYTE(0xf9, fp);
01722 PUTBYTE(4, fp);
01723 c = (info->inputFlag ? 0x02 : 0x00) | ((info->disposal & 0x07) << 2) | ((info->transparent != -1) ? 0x01 : 0x00);
01724 PUTBYTE(c, fp);
01725 PUTWORD(info->delayTime, fp);
01726 PUTBYTE(info->transparent, fp);
01727
01728
01729