Main Page | Modules | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members | Related Pages

OSGGIFImageFileType.cpp

Go to the documentation of this file.
00001 /*---------------------------------------------------------------------------*\
00002  *                                OpenSG                                     *
00003  *                                                                           *
00004  *                                                                           *
00005  *             Copyright (C) 2000-2002 by the OpenSG Forum                   *
00006  *                                                                           *
00007  *                            www.opensg.org                                 *
00008  *                                                                           *
00009  *   contact: dirk@opensg.org, gerrit.voss@vossg.org, jbehr@zgdv.de          *
00010  *                                                                           *
00011 \*---------------------------------------------------------------------------*/
00012 /*---------------------------------------------------------------------------*\
00013  *                                License                                    *
00014  *                                                                           *
00015  * This library is free software; you can redistribute it and/or modify it   *
00016  * under the terms of the GNU Library General Public License as published    *
00017  * by the Free Software Foundation, version 2.                               *
00018  *                                                                           *
00019  * This library is distributed in the hope that it will be useful, but       *
00020  * WITHOUT ANY WARRANTY; without even the implied warranty of                *
00021  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU         *
00022  * Library General Public License for more details.                          *
00023  *                                                                           *
00024  * You should have received a copy of the GNU Library General Public         *
00025  * License along with this library; if not, write to the Free Software       *
00026  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.                 *
00027  *                                                                           *
00028 \*---------------------------------------------------------------------------*/
00029 /*---------------------------------------------------------------------------*\
00030  *                                Changes                                    *
00031  *                                                                           *
00032  *                                                                           *
00033  *                                                                           *
00034  *                                                                           *
00035  *                                                                           *
00036  *                                                                           *
00037 \*---------------------------------------------------------------------------*/
00038 //-------------------------------
00039 //      Includes                                
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 //--- GIF-INCLUDE START ----------------------------------------------------
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;    /* transparency index */
00105     int             delayTime;      /* Time in 1/100 of a second */
00106     int             inputFlag;      /* wait for input after display */
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 //--- GIF INCLUDE END ----------------------------------------------------
00168 OSG_USING_NAMESPACE
00169 
00170 /*****************************
00171  *   Types
00172  *****************************/
00173 /*****************************
00174  *    Classvariables
00175  *****************************/
00176 // Static Class Varible implementations:
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     //    int imageSize = 0;
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                 // get the att.
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                 // check if the movie is color or greyscale
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                     // cout << "INFO: Use gifData colorMap" << endl;
00263                 }
00264                 else if(gifStream->cmapSize > 0)
00265                 {
00266                     colorMapSize = gifStream->cmapSize;
00267                     colorMap = (unsigned char *) gifStream->cmapData;
00268 
00269                     // cout << "INFO: Use gifStream colorMap" << endl;
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                 // calculate the movie channel
00293                 channel = (isColor ? 3 : 1) + (transparentIndex >= 0 ? 1 : 0);
00294 
00295                 if(currentFrame)
00296                 {
00297                     // is not the first frame
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 //currentFrame++;
00324 //                        continue;
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                 // copy the image data)
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: // Greyscale without Alpha
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: // Greyscale with Alpha
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: // RGB without Alpha
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: // RGB with Alpha
00413                     destI = xOff * 4;                    
00414                     
00415                     for(i = width * height; i--;)
00416                     {
00417                         colorIndex = *srcData++;
00418                         if(colorIndex == transparentIndex)
00419                         {
00420 /*
00421                             for(j = 0; j < 3; j++)
00422                                 destData[destI++] = 0;                              // RGB
00423                             destData[destI++] = 0;                                  // ALPHA
00424  */
00425                             destI += 4;
00426                         }
00427                         else
00428                         {
00429                             for(j = 0; j < 3; j++)
00430                             {
00431                                 destData[destI++] = 
00432                                     colorMap[colorIndex * 3 + j];   // RGB
00433                             }
00434 
00435                             destData[destI++] = 255;                                // ALPHA
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 /*------------access----------------*/
00543 /*------------properies-------------*/
00544 /*------------your Category---------*/
00545 /*------------Operators-------------*/
00546 /****************************
00547 *protected  
00548 ****************************/
00549 /****************************
00550 *private
00551 ****************************/
00552 #ifdef OSG_WITH_GIF
00553 
00554 //--- GIF-READ START ----------------------------------------------------
00555 /*
00556 **  Copyright 1994, Home Pages, Inc.
00557 **
00558 **    Please read the file COPYRIGHT for specific information.
00559 **
00560 **    Home Pages, Inc.
00561 **    257 Castro St. Suite 219
00562 **    Mountain View, CA 94041
00563 **
00564 **    Phone: 1 415 903 5353
00565 **      Fax: 1 415 903 5345
00566 **
00567 **    EMail: support@homepages.com
00568 ** 
00569 */
00570 /* +-------------------------------------------------------------------+ */
00571 /* | Copyright 1990 - 1994, David Koblas. (koblas@netcom.com)          | */
00572 /* |   Permission to use, copy, modify, and distribute this software   | */
00573 /* |   and its documentation for any purpose and without fee is hereby | */
00574 /* |   granted, provided that the above copyright notice appear in all | */
00575 /* |   copies and that both that copyright notice and this permission  | */
00576 /* |   notice appear in supporting documentation.  This software is    | */
00577 /* |   provided "as is" without express or implied warranty.           | */
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 *  ERROR()    --  should not return
00594 *  INFO_MSG() --  info message, can be ignored
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 //static int    showComment = GIF_FALSE;
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     **  Global colormap is present.
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         {           /* Extension */
00727             if(!ReadOK(fd, &c, 1))
00728             {
00729                 GIF_ERROR("EOF / read error on extention function code");
00730             }
00731 
00732             if(c == 0xf9)
00733             {       /* graphic control */
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                 **  Comment or Plain Text
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                 **  Unrecogonized extension, consume it.
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 **  Pulled out of nextCode
00995 */
00996 static int  curbit, lastbit, get_done, last_byte;
00997 static int  return_clear;
00998 
00999 /*
01000 **  Out of nextLWZ
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 //  static int  inited = GIF_FALSE;
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     //    int pass = 0;
01213     /*
01214     **  Initialize the Compression routines
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 //--- GIF-READ END ------------------------------------------------------
01281 //--- GIF-WRITE START ---------------------------------------------------
01282 /*
01283 **  Copyright 1994, Home Pages, Inc.
01284 **
01285 **    Please read the file COPYRIGHT for specific information.
01286 **
01287 **    Home Pages, Inc.
01288 **    257 Castro St. Suite 219
01289 **    Mountain View, CA 94041
01290 **
01291 **    Phone: 1 415 903 5353
01292 **      Fax: 1 415 903 5345
01293 **
01294 **    EMail: support@homepages.com
01295 ** 
01296 */
01297 /* +-------------------------------------------------------------------+ */
01298 /* | Copyright 1993, David Koblas (koblas@netcom.com)                  | */
01299 /* |                                                                   | */
01300 /* | Permission to use, copy, modify, and to distribute this software  | */
01301 /* | and its documentation for any purpose is hereby granted without   | */
01302 /* | fee, provided that the above copyright notice appear in all       | */
01303 /* | copies and that both that copyright notice and this permission    | */
01304 /* | notice appear in supporting documentation.  There is no           | */
01305 /* | representations about the suitability of this software for        | */
01306 /* | any purpose.  this software is provided "as is" without express   | */
01307 /* | or implied warranty.                                              | */
01308 /* |                                                                   | */
01309 /* +-------------------------------------------------------------------+ */
01310 /* ppmtogif.c - read a portable pixmap and produce a GIF file
01311 **
01312 ** Based on GIFENCOD by David Rowley <mgardi@watdscu.waterloo.edu>.A
01313 ** Lempel-Zim compression based on "compress".
01314 **
01315 ** Copyright (C) 1989 by Jef Poskanzer.
01316 **
01317 ** Permission to use, copy, modify, and distribute this software and its
01318 ** documentation for any purpose and without fee is hereby granted, provided
01319 ** that the above copyright notice appear in all copies and that both that
01320 ** copyright notice and this permission notice appear in supporting
01321 ** documentation.  This software is provided "as is" without express or
01322 ** implied warranty.
01323 **
01324 ** The Graphics Interchange Format(c) is the Copyright property of
01325 ** CompuServe Incorporated.  GIF(sm) is a Service Mark property of
01326 ** CompuServe Incorporated.
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  * a code_int must be able to hold 2**BITS values of type int, and also -1
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     **  No images, no optimizations...
01388     **   or too many images...
01389     */
01390     if(count == 0 || count > 1)
01391         return 0;
01392 
01393     /*
01394     **  One image, nice and simple...
01395     **    Insure there is a global colormap, and optimize the
01396     **    image too it.
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         //        int  j;
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         **  Quite, I'm doing a bubble sort... ACK!
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         **  Already sorted, no change!
01432         */
01433         if(i == size)
01434             return 1;
01435         for(i = 0; i < size; i++)
01436             rmap[vals[i].idx] = i;
01437 
01438         /*
01439         **  Now reorder the colormap, and the image
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         **  Toast the local colormap
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         **  Now finally reorer the colormap
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 **  Return the ceiling log of n 
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     **  First find if this is a 87A or an 89A GIF image
01521     **    also, figure out the color resolution of the image.
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             **  Uses one of the 89 extensions.
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     ** assume 256 entry color resution, and non sorted colormap 
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     **  Is the global colormap optimized?
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     **  Write termination
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); /* End Block */
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     **