PageRenderTime 1147ms CodeModel.GetById 102ms app.highlight 984ms RepoModel.GetById 44ms app.codeStats 1ms

/Source/System/Image/FileIO/OSGGIFImageFileType.cpp

https://github.com/msteners/OpenSGDevMaster_Toolbox
C++ | 2188 lines | 1472 code | 324 blank | 392 comment | 257 complexity | 74bcb18a183c1325f76a96256b127897 MD5 | raw file

Large files files are truncated, but you can click here to view the full file

   1/*---------------------------------------------------------------------------*\
   2 *                                OpenSG                                     *
   3 *                                                                           *
   4 *                                                                           *
   5 *             Copyright (C) 2000-2002 by the OpenSG Forum                   *
   6 *                                                                           *
   7 *                            www.opensg.org                                 *
   8 *                                                                           *
   9 *   contact: dirk@opensg.org, gerrit.voss@vossg.org, jbehr@zgdv.de          *
  10 *                                                                           *
  11\*---------------------------------------------------------------------------*/
  12/*---------------------------------------------------------------------------*\
  13 *                                License                                    *
  14 *                                                                           *
  15 * This library is free software; you can redistribute it and/or modify it   *
  16 * under the terms of the GNU Library General Public License as published    *
  17 * by the Free Software Foundation, version 2.                               *
  18 *                                                                           *
  19 * This library is distributed in the hope that it will be useful, but       *
  20 * WITHOUT ANY WARRANTY; without even the implied warranty of                *
  21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU         *
  22 * Library General Public License for more details.                          *
  23 *                                                                           *
  24 * You should have received a copy of the GNU Library General Public         *
  25 * License along with this library; if not, write to the Free Software       *
  26 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.                 *
  27 *                                                                           *
  28\*---------------------------------------------------------------------------*/
  29/*---------------------------------------------------------------------------*\
  30 *                                Changes                                    *
  31 *                                                                           *
  32 *                                                                           *
  33 *                                                                           *
  34 *                                                                           *
  35 *                                                                           *
  36 *                                                                           *
  37\*---------------------------------------------------------------------------*/
  38//-------------------------------
  39//      Includes                                
  40//-------------------------------
  41
  42#include <cstdlib>
  43#include <cstdio>
  44#include <setjmp.h>
  45#include <cstring>
  46#include <cctype>
  47
  48#include "OSGConfig.h"
  49
  50#ifdef   OSG_SGI_LIB
  51#include <limits>
  52#endif
  53#include "OSGGIFImageFileType.h"
  54#include "OSGLog.h"
  55
  56#ifndef OSG_DO_DOC
  57#    ifdef OSG_WITH_GIF
  58#        define OSG_GIF_ARG(ARG) ARG
  59#    else
  60#        define OSG_GIF_ARG(ARG)
  61#    endif
  62#else
  63#    define OSG_GIF_ARG(ARG) ARG
  64#endif
  65
  66#ifdef OSG_WITH_GIF
  67
  68
  69/*! \class OSG::GIFImageFileType 
  70    \ingroup GrpSystemImage
  71
  72  Image File Type to read/write and store/restore Image objects as
  73  GIF data.
  74  
  75  All the type specific code is included in the class. Does
  76  not depend on external libs.
  77  
  78  You have to --enable-gif in the configure line to enable
  79  the singleton object.
  80 
  81*/
  82
  83
  84//--- GIF-INCLUDE START ----------------------------------------------------
  85
  86#define GIF_MAXCOLORS   256
  87
  88typedef enum
  89{
  90    gif_image,
  91    gif_comment,
  92    gif_text
  93} GIFStreamType;
  94
  95typedef enum
  96{
  97    gif_no_disposal     = 0,
  98    gif_keep_disposal   = 1,
  99    gif_color_restore   = 2,
 100    gif_image_restore   = 3
 101}
 102GIFDisposalType;
 103
 104typedef struct
 105{
 106    int             transparent;    /* transparency index */
 107    int             delayTime;      /* Time in 1/100 of a second */
 108    int             inputFlag;      /* wait for input after display */
 109    GIFDisposalType disposal;
 110} GIF89info;
 111
 112typedef struct  GIFData
 113{
 114    GIF89info       info;
 115    int             x, y;
 116    int             width, height;
 117    GIFStreamType   type;
 118    union
 119    {
 120        struct
 121        {
 122            int             cmapSize;
 123            unsigned char   cmapData[GIF_MAXCOLORS][3];
 124            unsigned char   *data;
 125            int             interlaced;
 126        } image;
 127        struct
 128        {
 129            int     fg, bg;
 130            int     cellWidth, cellHeight;
 131            int     len;
 132            char    *text;
 133        } text;
 134        struct
 135        {
 136            int     len;
 137            char    *text;
 138        } comment;
 139    } data;
 140
 141    struct GIFData  *next;
 142} GIFData;
 143
 144typedef struct
 145{
 146    int             width, height;
 147
 148    int             colorResolution;
 149    int             colorMapSize;
 150    int             cmapSize;
 151    unsigned char   cmapData[GIF_MAXCOLORS][3];
 152
 153    int             background;
 154    int             aspectRatio;
 155
 156    GIFData         *data;
 157} GIFStream;
 158
 159
 160static GIFStream *GIFRead   (std::istream &is);
 161       int        GIFTest   (char *);
 162       int        GIFWrite  (char *, GIFStream *, int);
 163static int        GIFWriteFP(FILE *, GIFStream *, int);
 164static int        GIFFree   (GIFStream *);
 165
 166#endif
 167
 168//--- GIF INCLUDE END ----------------------------------------------------
 169
 170OSG_USING_NAMESPACE
 171
 172static const Char8 *suffixArray[] = 
 173{
 174    "gif"
 175};
 176
 177GIFImageFileType GIFImageFileType::_the("image/gif",
 178                                        suffixArray, 
 179                                        sizeof(suffixArray));
 180
 181
 182
 183//-------------------------------------------------------------------------
 184/*! Tries to fill the image object with the data read from
 185    the given fileName. Returns true on success.
 186*/
 187
 188bool GIFImageFileType::read(      Image        *OSG_GIF_ARG(pImage), 
 189                                  std::istream &OSG_GIF_ARG(is),
 190                            const std::string  &OSG_GIF_ARG(mimetype))
 191{
 192    bool                retCode = false;
 193
 194#ifdef OSG_WITH_GIF
 195    Image::PixelFormat  pixelFormat = Image::OSG_INVALID_PF;
 196    GIFStream           *gifStream = GIFRead(is);
 197    GIFData             *gifData = 0;
 198    bool                isColor;
 199    int                 i, j, destI, lineSize, lineEnd;
 200    unsigned            red, green, blue;
 201    int                 transparentIndex;
 202    int                 width = 0, height = 0, channel = 0;
 203    int                 xOff = 0, yOff = 0;
 204    unsigned char       *srcData = 0, *destData = 0;
 205    int                 colorIndex;
 206    unsigned            frameCount = 0, currentFrame = 0;
 207    unsigned char       *colorMap = 0;
 208
 209    //    int imageSize = 0;
 210    int                 colorMapSize;
 211    Time                frameDelay;
 212
 213    if(gifStream)
 214    {
 215        frameCount = 0;
 216
 217        for(gifData = gifStream->data; gifData; gifData = gifData->next)
 218        {
 219            if(gifData->type == gif_image)
 220                frameCount++;
 221        }
 222    }
 223
 224    FDEBUG(("GIF Frames: %d\n", frameCount));
 225
 226    if(gifStream)
 227    {
 228        for(gifData = gifStream->data; gifData; gifData = gifData->next)
 229        {
 230            switch(gifData->type)
 231            {
 232                case gif_image:
 233                    if(frameCount)
 234                    {
 235                        FDEBUG(("Try to copy GIF Anim Frame %d/%d\n",
 236                                (currentFrame + 1), frameCount));
 237                    }
 238                    
 239                    // get the att.
 240                    transparentIndex = gifData->info.transparent;
 241                    frameDelay = float(gifData->info.delayTime) / 100.0f;
 242                    width  = gifData->width;
 243                    height = gifData->height;
 244                    xOff   = gifData->x;
 245                    yOff   = gifData->y;
 246                    
 247                    // check if the movie is color or greyscale
 248                    isColor = false;
 249                    if(gifData->data.image.cmapSize > 0)
 250                    {
 251                        colorMapSize = gifData->data.image.cmapSize;
 252                        colorMap = 
 253                            reinterpret_cast<unsigned char *>(
 254                                gifData->data.image.cmapData);
 255                        
 256                        // cout << "INFO: Use gifData colorMap" << endl;
 257                    }
 258                    else if(gifStream->cmapSize > 0)
 259                    {
 260                        colorMapSize = gifStream->cmapSize;
 261                        colorMap = 
 262                            reinterpret_cast<unsigned char *>(
 263                                gifStream->cmapData);
 264                        
 265                        // cout << "INFO: Use gifStream colorMap" << endl;
 266                    }
 267                    else
 268                    {
 269                        FWARNING(("Bad color map in "
 270                                  "GIFImageFileType::read()\n"));
 271                        colorMapSize = 0;
 272                    }
 273                    
 274                    for(i = 0; i < colorMapSize; i++)
 275                    {
 276                        if(i != transparentIndex)
 277                        {
 278                            red   = colorMap[i * 3 + 0];
 279                            green = colorMap[i * 3 + 1];
 280                            blue  = colorMap[i * 3 + 2];
 281
 282                            if(red != green || red != blue)
 283                            {
 284                                isColor = true;
 285                                break;
 286                            }
 287                        }
 288                    }
 289                    
 290                    // calculate the movie channel
 291                    channel = 
 292                        (isColor ? 3 : 1) + (transparentIndex >= 0 ? 1 : 0);
 293                    
 294                    if(currentFrame)
 295                    {
 296                        // is not the first frame
 297                        if((channel == pImage->getBpp()) &&
 298                           (width == pImage->getWidth()) &&
 299                           (height == pImage->getHeight()))
 300                        {
 301                            destData = pImage->editData(0, currentFrame);
 302                        }
 303                        else
 304                        {
 305                            destData = pImage->editData(0, currentFrame);
 306                            
 307                            // This is probably wrong, but it's a start
 308                            switch(gifData->info.disposal)
 309                            {
 310                                case gif_no_disposal:
 311                                    break;
 312                                    
 313                                case gif_keep_disposal:
 314                                    memcpy(destData, 
 315                                           pImage->getData(0, 
 316                                                           currentFrame - 1), 
 317                                           pImage->getWidth () * 
 318                                           pImage->getHeight() * 
 319                                           channel);
 320                                    break;
 321                                    
 322                                case gif_color_restore:
 323                                {
 324                                    unsigned char r,g,b,a;
 325                                    Int32 bgindex = gifStream->background;
 326                                    unsigned char *d = destData;
 327                                    
 328                                    r = colorMap[bgindex * 3 + 0];
 329                                    g = colorMap[bgindex * 3 + 1];
 330                                    b = colorMap[bgindex * 3 + 2];
 331                                    a = (bgindex == transparentIndex) ? 
 332                                        0 : 255;
 333                                    
 334                                    for(UInt32 pixel = 
 335                                            pImage->getWidth () * 
 336                                            pImage->getHeight(); 
 337                                        pixel > 0; --pixel, d += channel)
 338                                    {
 339                                        d[0] = r;
 340                                        d[1] = g;
 341                                        d[2] = b;
 342                                        if(channel == 4)
 343                                            d[3] = a;
 344                                    }
 345                                }
 346                                break;
 347                                
 348                                case gif_image_restore:                       
 349                                    memcpy(destData, 
 350                                           pImage->getData(
 351                                               0, 
 352                                               (currentFrame >= 2) ?
 353                                                   (currentFrame - 2) : 0),
 354                                           pImage->getWidth () * 
 355                                           pImage->getHeight() * 
 356                                           channel);
 357                                    break;
 358                                default:
 359                                    FWARNING(("Unknown GIF disposal "
 360                                              "mode %d\n", 
 361                                              gifData->info.disposal));
 362                                    break;
 363                            }
 364                        }
 365                    }
 366                    else
 367                    {
 368                        switch(channel)
 369                        {
 370                            case 1:
 371                                pixelFormat = Image::OSG_L_PF;
 372                                break;
 373                            case 2:
 374                                pixelFormat = Image::OSG_LA_PF;
 375                                break;
 376                            case 3:
 377                                pixelFormat = Image::OSG_RGB_PF;
 378                                break;
 379                            case 4:
 380                                pixelFormat = Image::OSG_RGBA_PF;
 381                                break;
 382                        };
 383                        pImage->set(pixelFormat, 
 384                                    width, 
 385                                    height, 
 386                                    1, 1, 
 387                                    frameCount, frameDelay);
 388
 389                        destData = pImage->editData();
 390                    }
 391                    
 392                    // copy the image data)
 393                    lineSize = pImage->getWidth() * channel;
 394                    lineEnd  = width * channel + xOff * channel;
 395                    srcData  = gifData->data.image.data;
 396                    destData = 
 397                        destData + ((pImage->getHeight() - yOff - 1)*lineSize);
 398
 399                    switch(channel)
 400                    {
 401                        case 1: // Greyscale without Alpha
 402                            destI = 0;
 403                            for(i = width * height; i--;)
 404                            {
 405                                destData[destI++] = colorMap[*srcData++ *3];
 406                                if(destI >= lineSize)
 407                                {
 408                                    destI = 0;
 409                                    destData -= lineSize;
 410                                }
 411                            }
 412                            break;
 413                            
 414                        case 2: // Greyscale with Alpha
 415                            destI = 0;
 416                            for(i = width * height; i--;)
 417                            {
 418                                colorIndex = *srcData++;
 419                                if(colorIndex == transparentIndex)
 420                                {
 421                                    destData[destI++] = 0;
 422                                    destData[destI++] = 0;
 423                                }
 424                                else
 425                                {
 426                                    destData[destI++] = colorMap[colorIndex*3];
 427                                    destData[destI++] = 255;
 428                                }
 429                                
 430                                if(destI >= lineSize)
 431                                {
 432                                    destI = 0;
 433                                    destData -= lineSize;
 434                                }
 435                            }
 436                            break;
 437                            
 438                        case 3: // RGB without Alpha
 439                            destI = 0;
 440                            for(i = width * height; i--;)
 441                            {
 442                                colorIndex = *srcData++;
 443                                for(j = 0; j < 3; j++)
 444                                {
 445                                    destData[destI++] = 
 446                                        colorMap[colorIndex * 3 + j];
 447                                }
 448                                
 449                                if(destI >= lineSize)
 450                                {
 451                                    destI = 0;
 452                                    destData -= lineSize;
 453                                }
 454                            }
 455                            break;
 456                            
 457                        case 4: // RGB with Alpha
 458                            destI = xOff * 4;                    
 459
 460                            for(i = width * height; i--;)
 461                            {
 462                                colorIndex = *srcData++;
 463                                if(colorIndex == transparentIndex)
 464                                {
 465#if 0
 466                                    for(j = 0; j < 3; j++)
 467                                        destData[destI++] = 0; // RGB
 468                                    destData[destI++] = 0;     // ALPHA
 469#endif
 470
 471                                    destI += 4;
 472                                }
 473                                else
 474                                {
 475                                    for(j = 0; j < 3; j++)
 476                                    {
 477                                        destData[destI++] = 
 478                                            colorMap[colorIndex * 3 + j];// RGB
 479                                    }
 480                                    
 481                                    destData[destI++] = 255;          // ALPHA
 482                                }
 483                                
 484                                if(destI >= lineEnd)
 485                                {
 486                                    destI = xOff * 4;
 487                                    destData -= lineSize;
 488                                }
 489                            }
 490                            break;
 491                    }
 492                    
 493                    retCode = true;
 494                    
 495                    currentFrame++;
 496                    
 497                    break;
 498                case gif_comment:
 499                    break;
 500                case gif_text:
 501                    break;
 502            }
 503        }
 504        
 505        GIFFree(gifStream);
 506    }
 507    else
 508    {
 509        retCode = false;
 510    }
 511#endif
 512
 513    return retCode;
 514}
 515
 516//-------------------------------------------------------------------------
 517/*! Tries to write the image object to the given fileName.
 518    Returns true on success.
 519*/
 520
 521bool GIFImageFileType::write(const Image         *  , 
 522                                   std::ostream  &, 
 523                             const std::string   &)
 524{
 525#ifdef OSG_WITH_GIF
 526    SWARNING << getMimeType() << " write is not implemented " << endLog;
 527    
 528#else
 529    SWARNING << getMimeType()
 530             << " write is not compiled into the current binary "
 531             << endLog;
 532#endif
 533
 534    return false;
 535}
 536
 537//-------------------------------------------------------------------------
 538/*!
 539  Tries to determine the mime type of the data provided by an input stream
 540  by searching for magic bytes. Returns the mime type or an empty string
 541  when the function could not determine the mime type.
 542*/
 543
 544std::string GIFImageFileType::determineMimetypeFromStream(std::istream &is)
 545{
 546    char filecode[4];
 547
 548    is.read(filecode, 4);
 549    is.seekg(-4, std::ios::cur);
 550
 551    return strncmp(filecode, "GIF8", 4) == 0 ?
 552        std::string(getMimeType()) : std::string();
 553}
 554
 555bool GIFImageFileType::validateHeader(const Char8 *fileName, bool &implemented)
 556{
 557    implemented = true;
 558    
 559    if(fileName == NULL)
 560        return false;
 561    
 562    FILE *file = fopen(fileName, "rb");
 563
 564    if(file == NULL)
 565        return false;
 566
 567    std::string magic;
 568
 569    magic.resize(4);
 570
 571    fread(static_cast<void *>(&magic[0]), 4, 1, file);
 572
 573    fclose(file);
 574
 575    if(magic == "GIF8")
 576    {
 577        return true;
 578    }
 579
 580    return false;
 581}
 582
 583//-------------------------------------------------------------------------
 584/*! Constructor used for the singleton object
 585 */
 586
 587GIFImageFileType::GIFImageFileType(const Char8  *mimeType,
 588                                   const Char8  *suffixArray[],
 589                                         UInt16  suffixByteCount) :
 590    Inherited(mimeType,suffixArray, suffixByteCount)
 591{
 592}
 593
 594//-------------------------------------------------------------------------
 595/*! Destructor
 596 */
 597
 598GIFImageFileType::~GIFImageFileType(void)
 599{
 600}
 601
 602#ifdef OSG_WITH_GIF
 603
 604//--- GIF-READ START ----------------------------------------------------
 605/*
 606**  Copyright 1994, Home Pages, Inc.
 607**
 608**    Please read the file COPYRIGHT for specific information.
 609**
 610**    Home Pages, Inc.
 611**    257 Castro St. Suite 219
 612**    Mountain View, CA 94041
 613**
 614**    Phone: 1 415 903 5353
 615**      Fax: 1 415 903 5345
 616**
 617**    EMail: support@homepages.com
 618** 
 619*/
 620/* +-------------------------------------------------------------------+ */
 621/* | Copyright 1990 - 1994, David Koblas. (koblas@netcom.com)          | */
 622/* |   Permission to use, copy, modify, and distribute this software   | */
 623/* |   and its documentation for any purpose and without fee is hereby | */
 624/* |   granted, provided that the above copyright notice appear in all | */
 625/* |   copies and that both that copyright notice and this permission  | */
 626/* |   notice appear in supporting documentation.  This software is    | */
 627/* |   provided "as is" without express or implied warranty.           | */
 628/* +-------------------------------------------------------------------+ */
 629#define GIF_TRUE                    1
 630#define GIF_FALSE                   0
 631
 632#define MAX_LWZ_BITS                12
 633
 634#define INTERLACE                   0x40
 635#define LOCALCOLORMAP               0x80
 636
 637#define BitSet(byte, bit)           (((byte) & (bit)) == (bit))
 638#define ReadOK(is, buffer, len)     (is.read(reinterpret_cast<char*>(buffer), \
 639                                             len).gcount() == len)
 640#define MKINT(a, b)                 (((b) << 8) | (a))
 641#define NEW(x)                      (static_cast<x *>(malloc(sizeof(x))))
 642/***************************************************************************
 643*
 644*  ERROR()    --  should not return
 645*  INFO_MSG() --  info message, can be ignored
 646*
 647***************************************************************************/
 648
 649#if 0
 650#define INFO_MSG(fmt)   pm_message fmt 
 651#define ERROR(str)  pm_error(str)
 652#else
 653#if 0 
 654#define INFO_MSG(fmt)   
 655#define ERROR(str) do  { RWSetMsg(str); longjmp(setjmp_buffer, 1); } while(0)
 656#else
 657#define INFO_MSG(fmt)  { FINFO(("Info loading gif: '%s'!\n", fmt)); }
 658#define GIF_ERROR(str) { FWARNING(("Error loading gif: '%s'!\n", str)); \
 659                         longjmp(setjmp_buffer, 1); }
 660#endif
 661#endif
 662
 663/***************************************************************************/
 664
 665static int readColorMap(std::istream &, int, unsigned char [GIF_MAXCOLORS][3]);
 666static int GetDataBlock(std::istream &, unsigned char *);
 667static void readImage  (std::istream &, int, int, int, unsigned char *);
 668
 669static jmp_buf                  setjmp_buffer;
 670
 671static int    verbose = GIF_FALSE;
 672//static int    showComment = GIF_FALSE;
 673
 674/* */
 675static GIFStream *GIFRead(std::istream &is)
 676{
 677    unsigned char   buf[256];
 678    unsigned char   c;
 679    GIFStream       *gifStream = 0;
 680    GIFData         *cur, **end;
 681    GIF89info       info = {0, 0, 0, gif_no_disposal};
 682    int             resetInfo = GIF_TRUE;
 683    int             n;
 684
 685    if(setjmp(setjmp_buffer))
 686        goto out;
 687
 688    if(!ReadOK(is, buf, 6))
 689    {
 690        GIF_ERROR("error reading magic number");
 691    }
 692
 693    if(strncmp(reinterpret_cast<char *>(buf), "GIF", 3) != 0)
 694        GIF_ERROR("not a GIF file");
 695
 696    if((strncmp((reinterpret_cast<char *>(buf)) + 3, "87a", 3) != 0) &&
 697       (strncmp((reinterpret_cast<char *>(buf)) + 3, "89a", 3) != 0))
 698    {
 699        GIF_ERROR("bad version number, not '87a' or '89a'");
 700    }
 701
 702    if(!ReadOK(is, buf, 7))
 703    {
 704        GIF_ERROR("failed to read screen descriptor");
 705    }
 706
 707    gifStream = NEW(GIFStream);
 708
 709    gifStream->width = MKINT(buf[0], buf[1]);
 710    gifStream->height = MKINT(buf[2], buf[3]);
 711
 712    gifStream->cmapSize = 2 << (buf[4] & 0x07);
 713    gifStream->colorMapSize = gifStream->cmapSize;
 714    gifStream->colorResolution = (int(buf[4] & 0x70) >> 3) + 1;
 715    gifStream->background = buf[5];
 716    gifStream->aspectRatio = buf[6];
 717
 718    gifStream->data = NULL;
 719
 720    end = &gifStream->data;
 721
 722    /*
 723    **  Global colormap is present.
 724    */
 725    if(BitSet(buf[4], LOCALCOLORMAP))
 726    {
 727        if(readColorMap(is, gifStream->cmapSize, gifStream->cmapData))
 728        {
 729            GIF_ERROR("unable to get global colormap");
 730        }
 731    }
 732    else
 733    {
 734        gifStream->cmapSize = 0;
 735        gifStream->background = -1;
 736    }
 737
 738    if(gifStream->aspectRatio != 0 && gifStream->aspectRatio != 49)
 739    {
 740        INFO_MSG(("warning - non-square pixels"));
 741    }
 742
 743    while(ReadOK(is, &c, 1) && c != ';')
 744    {
 745        if(resetInfo)
 746        {
 747            info.disposal = static_cast<GIFDisposalType>(0);
 748            info.inputFlag = 0;
 749            info.delayTime = 0;
 750            info.transparent = -1;
 751            resetInfo = GIF_FALSE;
 752        }
 753
 754        cur = NULL;
 755
 756        if(c == '!')
 757        {           /* Extension */
 758            if(!ReadOK(is, &c, 1))
 759            {
 760                GIF_ERROR("EOF / read error on extention function code");
 761            }
 762
 763            if(c == 0xf9)
 764            {       /* graphic control */
 765                (void) GetDataBlock(is, buf);
 766                info.disposal = 
 767                    static_cast<GIFDisposalType>((buf[0] >> 2) & 0x7);
 768                info.inputFlag = (buf[0] >> 1) & 0x1;
 769                info.delayTime = MKINT(buf[1], buf[2]);
 770                if(BitSet(buf[0], 0x1))
 771                    info.transparent = buf[3];
 772
 773                while(GetDataBlock(is, buf) != 0)
 774                    ;
 775            }
 776            else if(c == 0xfe || c == 0x01)
 777            {
 778                int     len = 0;
 779                int     size = 256;
 780                char    *text = NULL;
 781
 782                /* 
 783                **  Comment or Plain Text
 784                */
 785                cur = NEW(GIFData);
 786
 787                if(c == 0x01)
 788                {
 789                    (void) GetDataBlock(is, buf);
 790
 791                    cur->type = gif_text;
 792                    cur->info = info;
 793                    cur->x = MKINT(buf[0], buf[1]);
 794                    cur->y = MKINT(buf[2], buf[3]);
 795                    cur->width = MKINT(buf[4], buf[5]);
 796                    cur->height = MKINT(buf[6], buf[7]);
 797
 798                    cur->data.text.cellWidth = buf[8];
 799                    cur->data.text.cellHeight = buf[9];
 800                    cur->data.text.fg = buf[10];
 801                    cur->data.text.bg = buf[11];
 802
 803                    resetInfo = GIF_TRUE;
 804                }
 805                else
 806                {
 807                    cur->type = gif_comment;
 808                }
 809
 810                text = static_cast<char *>(malloc(size));
 811
 812                while((n = GetDataBlock(is, buf)) != 0)
 813                {
 814                    if(n + len >= size)
 815                    {
 816                        text = static_cast<char *>(realloc(text, size += 256));
 817                    }
 818
 819                    memcpy(text + len, buf, n);
 820                    len += n;
 821                }
 822
 823                if(c == 0x01)
 824                {
 825                    cur->data.text.len = len;
 826                    cur->data.text.text = text;
 827                }
 828                else
 829                {
 830                    cur->data.comment.len = len;
 831                    cur->data.comment.text = text;
 832                }
 833            }
 834            else
 835            {
 836                /*
 837                **  Unrecogonized extension, consume it.
 838                */
 839                while(GetDataBlock(is, buf) > 0)
 840                    ;
 841            }
 842        }
 843        else if(c == ',')
 844        {
 845            if(!ReadOK(is, buf, 9))
 846            {
 847                GIF_ERROR("couldn't read left/top/width/height");
 848            }
 849
 850            cur = NEW(GIFData);
 851
 852            cur->type = gif_image;
 853            cur->info = info;
 854            cur->x = MKINT(buf[0], buf[1]);
 855            cur->y = MKINT(buf[2], buf[3]);
 856            cur->width = MKINT(buf[4], buf[5]);
 857            cur->height = MKINT(buf[6], buf[7]);
 858            cur->data.image.cmapSize = 1 << ((buf[8] & 0x07) + 1);
 859            if(BitSet(buf[8], LOCALCOLORMAP))
 860            {
 861                if(readColorMap(is, cur->data.image.cmapSize,
 862                                         cur->data.image.cmapData))
 863                {
 864                    GIF_ERROR("unable to get local colormap");
 865                }
 866            }
 867            else
 868            {
 869                cur->data.image.cmapSize = 0;
 870            }
 871
 872            cur->data.image.data = static_cast<unsigned char *>(
 873                malloc(cur->width * cur->height));
 874            cur->data.image.interlaced = BitSet(buf[8], INTERLACE);
 875            readImage(is, BitSet(buf[8], INTERLACE), cur->width, cur->height,
 876                      cur->data.image.data);
 877
 878            resetInfo = GIF_TRUE;
 879        }
 880        else
 881        {
 882            FINFO(("Info loading gif: bogus character 0x%02x, ignoring", 
 883                   int(c)));
 884        }
 885
 886        if(cur != NULL)
 887        {
 888            *end = cur;
 889            end = &cur->next;
 890            cur->next = NULL;
 891        }
 892    }
 893
 894    if(c != ';')
 895        GIF_ERROR("EOF / data stream");
 896
 897out:
 898    return gifStream;
 899}
 900
 901/* */
 902static int GIFFreeData(GIFData *gifData)
 903{
 904    int retCode = 0;
 905
 906    if(gifData)
 907    {
 908        switch(gifData->type)
 909        {
 910        case gif_image:
 911            if(gifData->data.image.data)
 912            {
 913                free(gifData->data.image.data);
 914            }
 915            break;
 916        case gif_comment:
 917            if(gifData->data.comment.text)
 918            {
 919                free(gifData->data.comment.text);
 920            }
 921            break;
 922        case gif_text:
 923            if(gifData->data.text.text)
 924            {
 925                free(gifData->data.text.text);
 926            }
 927            break;
 928        }
 929
 930        retCode = 1;
 931    }
 932    else
 933        retCode = 0;
 934
 935    return retCode;
 936}
 937
 938/* */
 939static int GIFFree(GIFStream *gifStream)
 940{
 941    int     retCode = 1;
 942    GIFData *gifData, *gifNext;
 943
 944    if(gifStream)
 945    {
 946        gifData = gifStream->data;
 947        while(gifData)
 948        {
 949            gifNext = gifData->next;
 950            GIFFreeData(gifData);
 951            free(gifData);
 952            gifData = gifNext;
 953        }
 954    }
 955
 956    return retCode;
 957}
 958
 959/* */
 960static int readColorMap(std::istream &is, int size, unsigned char data[GIF_MAXCOLORS][3])
 961{
 962    int             i;
 963    unsigned char   rgb[3 * GIF_MAXCOLORS];
 964    unsigned char   *cp = rgb;
 965
 966    if(!ReadOK(is, rgb, size * 3))
 967        return GIF_TRUE;
 968
 969    for(i = 0; i < size; i++)
 970    {
 971        data[i][0] = *cp++;
 972        data[i][1] = *cp++;
 973        data[i][2] = *cp++;
 974    }
 975
 976    return GIF_FALSE;
 977}
 978
 979/*
 980**
 981*/
 982static int  ZeroDataBlock = GIF_FALSE;
 983
 984/* */
 985
 986static int GetDataBlock(std::istream &is, unsigned char *buf)
 987{
 988    unsigned char   count;
 989
 990    if(!ReadOK(is, &count, 1))
 991    {
 992        INFO_MSG(("error in getting DataBlock size"));
 993        return -1;
 994    }
 995
 996    ZeroDataBlock = count == 0;
 997
 998    if((count != 0) && (!ReadOK(is, buf, count)))
 999    {
1000        INFO_MSG(("error in reading DataBlock"));
1001        return -1;
1002    }
1003
1004    return count;
1005}
1006
1007/*
1008**
1009**
1010*/
1011/*
1012**  Pulled out of nextCode
1013*/
1014static int  curbit, lastbit, get_done, last_byte;
1015static int  return_clear;
1016
1017/*
1018**  Out of nextLWZ
1019*/
1020static int  stack[(1 << (MAX_LWZ_BITS)) * 2], *sp;
1021static int  code_size, set_code_size;
1022static int  max_code, max_code_size;
1023static int  clear_code, end_code;
1024
1025/* */
1026
1027static void initLWZ(int input_code_size)
1028{
1029//  static int  inited = GIF_FALSE;
1030
1031    set_code_size = input_code_size;
1032    code_size     = set_code_size + 1;
1033    clear_code    = 1 << set_code_size ;
1034    end_code      = clear_code + 1;
1035    max_code_size = 2 * clear_code;
1036    max_code      = clear_code + 2;
1037
1038    curbit = lastbit = 0;
1039    last_byte = 2;
1040    get_done = GIF_FALSE;
1041
1042    return_clear = GIF_TRUE;
1043
1044    sp = stack;
1045}
1046
1047/* */
1048static int nextCode(std::istream &is, int code_size)
1049{
1050    static unsigned char    buf[280];
1051    static int              maskTbl[16] =
1052    {
1053        0x0000,
1054        0x0001,
1055        0x0003,
1056        0x0007,
1057        0x000f,
1058        0x001f,
1059        0x003f,
1060        0x007f,
1061        0x00ff,
1062        0x01ff,
1063        0x03ff,
1064        0x07ff,
1065        0x0fff,
1066        0x1fff,
1067        0x3fff,
1068        0x7fff,
1069    };
1070    int                     i, j, ret, end;
1071
1072    if(return_clear)
1073    {
1074        return_clear = GIF_FALSE;
1075        return clear_code;
1076    }
1077
1078    end = curbit + code_size;
1079
1080    if(end >= lastbit)
1081    {
1082        int count;
1083
1084        if(get_done)
1085        {
1086            if(curbit >= lastbit)
1087            {
1088                GIF_ERROR("ran off the end of my bits");
1089            }
1090
1091            return -1;
1092        }
1093
1094        buf[0] = buf[last_byte - 2];
1095        buf[1] = buf[last_byte - 1];
1096
1097        if((count = GetDataBlock(is, &buf[2])) == 0)
1098            get_done = GIF_TRUE;
1099
1100        last_byte = 2 + count;
1101        curbit = (curbit - lastbit) + 16;
1102        lastbit = (2 + count) * 8;
1103
1104        end = curbit + code_size;
1105    }
1106
1107    j = end / 8;
1108    i = curbit / 8;
1109
1110    if(i == j)
1111        ret = buf[i];
1112    else if(i + 1 == j)
1113        ret = buf[i] | (buf[i + 1] << 8);
1114    else
1115    {
1116        ret = buf[i] | (buf[i + 1] << 8) | (buf[i + 2] << 16);
1117    }
1118
1119    ret = (ret >> (curbit % 8)) & maskTbl[code_size];
1120
1121    curbit += code_size;
1122
1123    return ret;
1124}
1125
1126#define readLWZ(fd) ((sp > stack) ? *--sp : nextLWZ(fd))
1127
1128/* */
1129static int nextLWZ(std::istream &is)
1130{
1131    static int      table[2][(1 << MAX_LWZ_BITS)];
1132    static int      firstcode, oldcode;
1133    int             code, incode;
1134    register int    i;
1135
1136    while((code = nextCode(is, code_size)) >= 0)
1137    {
1138        if(code == clear_code)
1139        {
1140            for(i = 0; i < clear_code; ++i)
1141            {
1142                table[0][i] = 0;
1143                table[1][i] = i;
1144            }
1145
1146            for(; i < (1 << MAX_LWZ_BITS); ++i)
1147                table[0][i] = table[1][i] = 0;
1148            code_size = set_code_size + 1;
1149            max_code_size = 2 * clear_code;
1150            max_code = clear_code + 2;
1151            sp = stack;
1152            do
1153            {
1154                firstcode = oldcode = nextCode(is, code_size);
1155            } while(firstcode == clear_code);
1156
1157            return firstcode;
1158        }
1159
1160        if(code == end_code)
1161        {
1162            int             count;
1163            unsigned char   buf[260];
1164
1165            if(ZeroDataBlock)
1166                return -2;
1167
1168            while((count = GetDataBlock(is, buf)) > 0)
1169                ;
1170
1171            if(count != 0)
1172            {
1173                INFO_MSG(("missing EOD in data stream"));
1174            }
1175
1176            return -2;
1177        }
1178
1179        incode = code;
1180
1181        if(code >= max_code)
1182        {
1183            *sp++ = firstcode;
1184            code = oldcode;
1185        }
1186
1187        while(code >= clear_code)
1188        {
1189            *sp++ = table[1][code];
1190            if(code == table[0][code])
1191            {
1192                GIF_ERROR("circular table entry BIG ERROR");
1193            }
1194
1195            code = table[0][code];
1196        }
1197
1198        *sp++ = firstcode = table[1][code];
1199
1200        if((code = max_code) < (1 << MAX_LWZ_BITS))
1201        {
1202            table[0][code] = oldcode;
1203            table[1][code] = firstcode;
1204            ++max_code;
1205            if((max_code >= max_code_size) &&
1206               (max_code_size < (1 << MAX_LWZ_BITS)))
1207            {
1208                max_code_size *= 2;
1209                ++code_size;
1210            }
1211        }
1212
1213        oldcode = incode;
1214
1215        if(sp > stack)
1216            return *--sp;
1217    }
1218
1219    return code;
1220}
1221
1222/* */
1223static void readImage(std::istream &is, int interlace, int width, int height,
1224                       unsigned char *data)
1225{
1226    unsigned char   *dp, c;
1227
1228    int             v, xpos = 0, ypos = 0;
1229
1230    //    int pass = 0;
1231    /*
1232    **  Initialize the Compression routines
1233    */
1234    if(!ReadOK(is, &c, 1))
1235    {
1236        GIF_ERROR("EOF / read error on image data");
1237    }
1238
1239    initLWZ(c);
1240
1241    if(verbose)
1242    {
1243        FINFO(("Info loading gif: reading %d by %d%s GIF image", 
1244               width, height, interlace ? " interlaced" : ""));
1245    }
1246
1247    if(interlace)
1248    {
1249        int i;
1250        int pass = 0, step = 8;
1251
1252        for(i = 0; i < height; i++)
1253        {
1254            dp = &data[width * ypos];
1255            for(xpos = 0; xpos < width; xpos++)
1256            {
1257                if((v = readLWZ(is)) < 0)
1258                    goto fini;
1259
1260                *dp++ = v;
1261            }
1262
1263            if((ypos += step) >= height)
1264            {
1265                do
1266                {
1267                    if(pass++ > 0)
1268                        step /= 2;
1269                    ypos = step / 2;
1270                } while(ypos > height);
1271            }
1272        }
1273    }
1274    else
1275    {
1276        dp = data;
1277        for(ypos = 0; ypos < height; ypos++)
1278        {
1279            for(xpos = 0; xpos < width; xpos++)
1280            {
1281                if((v = readLWZ(is)) < 0)
1282                    goto fini;
1283
1284                *dp++ = v;
1285            }
1286        }
1287    }
1288
1289fini:
1290    if(readLWZ(is) >= 0)
1291    {
1292        INFO_MSG(("too much input data, ignoring extra..."));
1293    }
1294
1295    return;
1296}
1297
1298//--- GIF-READ END ------------------------------------------------------
1299//--- GIF-WRITE START ---------------------------------------------------
1300/*
1301**  Copyright 1994, Home Pages, Inc.
1302**
1303**    Please read the file COPYRIGHT for specific information.
1304**
1305**    Home Pages, Inc.
1306**    257 Castro St. Suite 219
1307**    Mountain View, CA 94041
1308**
1309**    Phone: 1 415 903 5353
1310**      Fax: 1 415 903 5345
1311**
1312**    EMail: support@homepages.com
1313** 
1314*/
1315/* +-------------------------------------------------------------------+ */
1316/* | Copyright 1993, David Koblas (koblas@netcom.com)                  | */
1317/* |                                                                   | */
1318/* | Permission to use, copy, modify, and to distribute this software  | */
1319/* | and its documentation for any purpose is hereby granted without   | */
1320/* | fee, provided that the above copyright notice appear in all       | */
1321/* | copies and that both that copyright notice and this permission    | */
1322/* | notice appear in supporting documentation.  There is no           | */
1323/* | representations about the suitability of this software for        | */
1324/* | any purpose.  this software is provided "as is" without express   | */
1325/* | or implied warranty.                                              | */
1326/* |                                                                   | */
1327/* +-------------------------------------------------------------------+ */
1328/* ppmtogif.c - read a portable pixmap and produce a GIF file
1329**
1330** Based on GIFENCOD by David Rowley <mgardi@watdscu.waterloo.edu>.A
1331** Lempel-Zim compression based on "compress".
1332**
1333** Copyright (C) 1989 by Jef Poskanzer.
1334**
1335** Permission to use, copy, modify, and distribute this software and its
1336** documentation for any purpose and without fee is hereby granted, provided
1337** that the above copyright notice appear in all copies and that both that
1338** copyright notice and this permission notice appear in supporting
1339** documentation.  This software is provided "as is" without express or
1340** implied warranty.
1341**
1342** The Graphics Interchange Format(c) is the Copyright property of
1343** CompuServe Incorporated.  GIF(sm) is a Service Mark property of
1344** CompuServe Incorporated.
1345*/
1346#define GIF_TRUE        1
1347#define GIF_FALSE       0
1348
1349#define PUTBYTE(v, fp)  putc(v, fp)
1350#define PUTWORD(v, fp) \
1351    do \
1352    { \
1353        putc(((v) & 0xff), fp); \
1354        putc((((v) >> 8) & 0xff), fp); \
1355    } while(0)
1356/*
1357 * a code_int must be able to hold 2**BITS values of type int, and also -1
1358 */
1359    typedef int     code_int;
1360
1361typedef long int    count_int;
1362
1363static void         putImage(FILE *, int, int, int, int, unsigned char *);
1364static void         putColorMap(FILE *, int, unsigned char[GIF_MAXCOLORS][3]);
1365static void         putDataBlocks(FILE *fp, int, unsigned char *);
1366static void         putGif89Info(FILE *, GIF89info *);
1367
1368static void         output(code_int code);
1369static void         cl_block(void);
1370static void         cl_hash(count_int hsize);
1371static void         char_init(void);
1372static void         char_out(int c);
1373static void         flush_char(void);
1374
1375/*
1376**
1377*/
1378struct cval
1379{
1380    int idx, cnt;
1381};
1382
1383/* */
1384static int cvalCMP(struct cval *a, struct cval *b)
1385{
1386    return b->cnt - a->cnt;
1387}
1388
1389/* */
1390static int optimizeCMAP(GIFStream *stream)
1391{
1392    GIFData *cur = 0, *img = 0;
1393    int     count = 0;
1394
1395    for(cur = stream->data; cur != NULL; cur = cur->next)
1396    {
1397        if(cur->type == gif_image)
1398        {
1399            img = cur;
1400            count++;
1401        }
1402    }
1403
1404    /*
1405    **  No images, no optimizations...
1406    **   or too many images...
1407    */
1408    if(count == 0 || count > 1)
1409        return 0;
1410
1411    /*
1412    **  One image, nice and simple...
1413    **    Insure there is a global colormap, and optimize the
1414    **    image too it.
1415    */
1416    {
1417        int             size;
1418        unsigned char   *dp = img->data.image.data;
1419        unsigned char   *ep = dp + img->width * img->height;
1420        struct cval     vals[256];
1421        int             i;
1422
1423        //        int  j;
1424        unsigned char   tmap[256][3], rmap[256];
1425
1426        if((size = img->data.image.cmapSize) == 0)
1427            size = stream->cmapSize;
1428
1429        for(i = 0; i < size; i++)
1430        {
1431            vals[i].idx = i;
1432            vals[i].cnt = 0;
1433        }
1434
1435        for(dp = img->data.image.data, i = 0; dp < ep; i++, dp++)
1436            vals[*dp].cnt++;
1437
1438        /*
1439        **  Quite, I'm doing a bubble sort... ACK!
1440        */
1441        qsort(vals, size, sizeof(vals[0]),
1442              reinterpret_cast<int(*) (const void *, const void *)>(cvalCMP));
1443
1444        for(i = 0; i < size; i++)
1445            if(vals[i].idx != i)
1446                break;
1447
1448        /*
1449        **  Already sorted, no change!
1450        */
1451        if(i == size)
1452            return 1;
1453        for(i = 0; i < size; i++)
1454            rmap[vals[i].idx] = i;
1455
1456        /*
1457        **  Now reorder the colormap, and the image
1458        */
1459        for(dp = img->data.image.data, i = 0; dp < ep; i++, dp++)
1460            *dp = rmap[*dp];
1461        if(img->info.transparent != -1)
1462        {
1463            img->info.transparent = rmap[img->info.transparent];
1464        }
1465
1466        /*
1467        **  Toast the local colormap
1468        */
1469        if(img->data.image.cmapSize != 0)
1470        {
1471            for(i = 0; i < size; i++)
1472            {
1473                stream->cmapData[i][0] = img->data.image.cmapData[i][0];
1474                stream->cmapData[i][1] = img->data.image.cmapData[i][1];
1475                stream->cmapData[i][2] = img->data.image.cmapData[i][2];
1476            }
1477
1478            img->data.image.cmapSize = 0;
1479            stream->cmapSize = size;
1480        }
1481
1482        /*
1483        **  Now finally reorer the colormap
1484        */
1485        for(i = 0; i < size; i++)
1486        {
1487            tmap[i][0] = stream->cmapData[i][0];
1488            tmap[i][1] = stream->cmapData[i][1];
1489            tmap[i][2] = stream->cmapData[i][2];
1490        }
1491
1492        for(i = 0; i < size; i++)
1493        {
1494            stream->cmapData[rmap[i]][0] = tmap[i][0];
1495            stream->cmapData[rmap[i]][1] = tmap[i][1];
1496            stream->cmapData[rmap[i]][2] = tmap[i][2];
1497        }
1498    }
1499
1500    return 1;
1501}
1502
1503/*
1504**  Return the ceiling log of n 
1505*/
1506static int binaryLog(int val)
1507{
1508    int i;
1509
1510    if(val == 0)
1511        return 0;
1512
1513    for(i = 1; i <= 8; i++)
1514        if(val <= (1 << i))
1515            return i;
1516    return 8;
1517}
1518
1519#ifdef __sgi
1520#pragma set woff 1209
1521#endif
1522
1523/* */
1524static int GIFWriteFP(FILE *fp, GIFStream *stream, int optimize)
1525{
1526    GIFData *cur;
1527    int     flag = GIF_FALSE;
1528    int     c;
1529    int     globalBitsPP = 0;
1530    int     resolution;
1531
1532    if(fp == NULL)
1533        return GIF_TRUE;
1534    if(stream == NULL)
1535        return GIF_FALSE;
1536
1537    /*
1538    **  First find if this is a 87A or an 89A GIF image
1539    **    also, figure out the color resolution of the image.
1540    */
1541    resolution = binaryLog(stream->cmapSize) - 1;
1542    for(cur = stream->data; !flag && cur != NULL; cur = cur->next)
1543    {
1544        if(cur->type == gif_text || cur->type == gif_comment)
1545        {
1546            flag = GIF_TRUE;
1547        }
1548        else if(cur->type == gif_image)
1549        {
1550            int v = binaryLog(cur->data.image.cmapSize);
1551
1552            if(v > resolution)
1553                resolution = v;
1554
1555            /*
1556            **  Uses one of the 89 extensions.
1557            */
1558            if(cur->info.transparent != -1 ||
1559               cur->info.delayTime != 0 ||
1560               cur->info.inputFlag != 0 ||
1561               cur->info.disposal != 0)
1562                flag = GIF_TRUE;
1563        }
1564    }
1565
1566    /*
1567    **
1568    */
1569    if(optimize)
1570        optimize = optimizeCMAP(stream);
1571
1572    fwrite(flag ? "GIF89a" : "GIF87a", 1, 6, fp);
1573
1574    PUTWORD(stream->width, fp);
1575    PUTWORD(stream->height, fp);
1576
1577    /* 
1578    ** assume 256 entry color resution, and non sorted colormap 
1579    */
1580    c = ((resolution & 0x07) << 5) | 0x00;
1581    if(stream->cmapSize != 0)
1582    {
1583        globalBitsPP = binaryLog(stream->cmapSize);
1584        c |= 0x80;
1585        c |= globalBitsPP - 1;
1586    }
1587
1588    /*
1589    **  Is the global colormap optimized?
1590    */
1591    if(optimize)
1592        c |= 0x08;
1593    PUTBYTE(c, fp);
1594
1595    PUTBYTE(stream->background, fp);
1596    PUTBYTE(stream->aspectRatio, fp);
1597
1598    putColorMap(fp, stream->cmapSize, stream->cmapData);
1599
1600    for(cur = stream->data; cur != NULL; cur = cur->next)
1601    {
1602        if(cur->type == gif_image)
1603        {
1604            int bpp;
1605
1606            putGif89Info(fp, &cur->info);
1607
1608            PUTBYTE(0x2c, fp);
1609            PUTWORD(cur->x, fp);
1610            PUTWORD(cur->y, fp);
1611            PUTWORD(cur->width, fp);
1612            PUTWORD(cur->height, fp);
1613
1614            c = cur->data.image.interlaced ? 0x40 : 0x00;
1615            if(cur->data.image.cmapSize != 0)
1616            {
1617                bpp = binaryLog(cur->data.image.cmapSize);
1618                c |= 0x80;
1619                c |= bpp;
1620            }
1621            else
1622            {
1623                bpp = globalBitsPP;
1624            }
1625
1626            PUTBYTE(c, fp);
1627
1628            putColorMap(fp, cur->data.image.cmapSize, cur->data.image.cmapData);
1629
1630            putImage(fp, cur->data.image.interlaced, bpp, cur->width,
1631                     cur->height, cur->data.image.data);
1632        }
1633        else if(cur->type == gif_comment)
1634        {
1635            PUTBYTE('!', fp);
1636            PUTBYTE(0xfe, fp);
1637            putDataBlocks(
1638                fp, 
1639                cur->data.comment.len,
1640                reinterpret_cast<unsigned char *>(cur->data.comment.text));
1641        }
1642        else if(cur->type == gif_text)
1643        {
1644            putGif89Info(fp, &cur->info);
1645
1646            PUTBYTE('!', fp);
1647            PUTBYTE(0x01, fp);
1648
1649            PUTWORD(cur->x, fp);
1650            PUTWORD(cur->y, fp);
1651            PUTWORD(cur->width, fp);
1652            PUTWORD(cur->height, fp);
1653
1654            PUTBYTE(cur->data.text.cellWidth, fp);
1655            PUTBYTE(cur->data.text.cellHeight, fp);
1656            PUTBYTE(cur->data.text.fg, fp);
1657            PUTBYTE(cur->data.text.bg, fp);
1658
1659            putDataBlocks(
1660                fp, 
1661                cur->data.text.len,
1662                reinterpret_cast<unsigned char *>(cur->data.text.text));
1663        }
1664    }
1665
1666    /*
1667    **  Write termination
1668    */
1669    PUTBYTE(';', fp);
1670
1671    return GIF_FALSE;
1672}
1673
1674#ifdef __sgi
1675#pragma reset woff 1209
1676#endif
1677
1678/* */
1679int GIFWrite(char *file, GIFStream *stream, int optimize)
1680{
1681    if(stream != NULL)
1682    {
1683        FILE    *fp = fopen(file, "wb");
1684
1685        if(fp != NULL)
1686        {
1687            int s = GIFWriteFP(fp, stream, optimize);
1688            fclose(fp);
1689            return s;
1690        }
1691    }
1692
1693    return GIF_TRUE;
1694}
1695
1696/* */
1697static void putColorMap(FILE *fp, int size, unsigned char data[GIF_MAXCOLORS][3])
1698{
1699    int i;
1700
1701    for(i = 0; i < size; i++)
1702    {
1703        PUTBYTE(data[i][0], fp);
1704        PUTBYTE(data[i][1], fp);
1705        PUTBYTE(data[i][2], fp);
1706    }
1707}
1708
1709/* */
1710static void putDataBlocks(FILE *fp, int size, unsigned char *data)
1711{
1712    int n;
1713
1714    while(size > 0)
1715    {
1716        n = size > 255 ? 255 : size;
1717
1718        PUTBYTE(n, fp);
1719        fwrite(data, 1, n, fp);
1720        data += n;
1721        size -= n;
1722    }
1723
1724    PUTBYTE(0, fp); /* End Block */
1725}
1726
1727#ifdef __sgi
1728#pragma set woff 1209
1729#endif
1730
1731/* */
1732static void putGi

Large files files are truncated, but you can click here to view the full file