Back to index

php5  5.3.10
gd_gif_out.c
Go to the documentation of this file.
00001 #include <stdio.h>
00002 #include <math.h>
00003 #include <string.h>
00004 #include <stdlib.h>
00005 #include "gd.h"
00006 
00007 /* Code drawn from ppmtogif.c, from the pbmplus package
00008 **
00009 ** Based on GIFENCOD by David Rowley <mgardi@watdscu.waterloo.edu>. A
00010 ** Lempel-Zim compression based on "compress".
00011 **
00012 ** Modified by Marcel Wijkstra <wijkstra@fwi.uva.nl>
00013 **
00014 ** Copyright (C) 1989 by Jef Poskanzer.
00015 **
00016 ** Permission to use, copy, modify, and distribute this software and its
00017 ** documentation for any purpose and without fee is hereby granted, provided
00018 ** that the above copyright notice appear in all copies and that both that
00019 ** copyright notice and this permission notice appear in supporting
00020 ** documentation.  This software is provided "as is" without express or
00021 ** implied warranty.
00022 **
00023 ** The Graphics Interchange Format(c) is the Copyright property of
00024 ** CompuServe Incorporated.  GIF(sm) is a Service Mark property of
00025 ** CompuServe Incorporated.
00026 */
00027 
00028 /*
00029  * a code_int must be able to hold 2**GIFBITS values of type int, and also -1
00030  */
00031 typedef int             code_int;
00032 
00033 #ifdef SIGNED_COMPARE_SLOW
00034 typedef unsigned long int count_int;
00035 typedef unsigned short int count_short;
00036 #else /*SIGNED_COMPARE_SLOW*/
00037 typedef long int          count_int;
00038 #endif /*SIGNED_COMPARE_SLOW*/
00039 
00040 /* 2.0.28: threadsafe */
00041 
00042 #define maxbits GIFBITS
00043 
00044 /* should NEVER generate this code */
00045 #define maxmaxcode ((code_int)1 << GIFBITS)
00046 
00047 #define HSIZE  5003            /* 80% occupancy */
00048 #define hsize HSIZE            /* Apparently invariant, left over from 
00049                                    compress */
00050 
00051 typedef struct {
00052        int Width, Height;
00053        int curx, cury;
00054        long CountDown;
00055        int Pass;
00056        int Interlace;
00057         int n_bits;                        /* number of bits/code */
00058         code_int maxcode;                  /* maximum code, given n_bits */
00059         count_int htab [HSIZE];
00060         unsigned short codetab [HSIZE];
00061        code_int free_ent;                  /* first unused entry */
00062        /*
00063         * block compression parameters -- after all codes are used up,
00064         * and compression rate changes, start over.
00065         */
00066        int clear_flg;
00067        int offset;
00068        long int in_count;            /* length of input */
00069        long int out_count;           /* # of codes output (for debugging) */
00070 
00071        int g_init_bits;
00072        gdIOCtx * g_outfile;
00073 
00074        int ClearCode;
00075        int EOFCode;
00076        unsigned long cur_accum;
00077        int cur_bits;
00078         /*
00079          * Number of characters so far in this 'packet'
00080          */
00081         int a_count;
00082         /*
00083          * Define the storage for the packet accumulator
00084          */
00085         char accum[ 256 ];
00086 } GifCtx;
00087 
00088 static int gifPutWord(int w, gdIOCtx *out);
00089 static int colorstobpp(int colors);
00090 static void BumpPixel (GifCtx *ctx);
00091 static int GIFNextPixel (gdImagePtr im, GifCtx *ctx);
00092 static void GIFEncode (gdIOCtxPtr fp, int GWidth, int GHeight, int GInterlace, int Background, int Transparent, int BitsPerPixel, int *Red, int *Green, int *Blue, gdImagePtr im);
00093 static void compress (int init_bits, gdIOCtx *outfile, gdImagePtr im, GifCtx *ctx);
00094 static void output (code_int code, GifCtx *ctx);
00095 static void cl_block (GifCtx *ctx);
00096 static void cl_hash (register count_int chsize, GifCtx *ctx);
00097 static void char_init (GifCtx *ctx);
00098 static void char_out (int c, GifCtx *ctx);
00099 static void flush_char (GifCtx *ctx);
00100 void * gdImageGifPtr (gdImagePtr im, int *size)
00101 {
00102   void *rv;
00103   gdIOCtx *out = gdNewDynamicCtx (2048, NULL);
00104   gdImageGifCtx (im, out);
00105   rv = gdDPExtractData (out, size);
00106   out->gd_free (out);
00107   return rv;
00108 }
00109 
00110 void gdImageGif (gdImagePtr im, FILE * outFile)
00111 {
00112   gdIOCtx *out = gdNewFileCtx (outFile);
00113   gdImageGifCtx (im, out);
00114   out->gd_free (out);
00115 }
00116 
00117 void gdImageGifCtx(gdImagePtr im, gdIOCtxPtr out)
00118 {
00119        gdImagePtr pim = 0, tim = im;
00120        int interlace, BitsPerPixel;
00121        interlace = im->interlace;
00122        if (im->trueColor) {
00123               /* Expensive, but the only way that produces an
00124                      acceptable result: mix down to a palette
00125                      based temporary image. */
00126               pim = gdImageCreatePaletteFromTrueColor(im, 1, 256);
00127               if (!pim) {
00128                      return;
00129               }
00130               tim = pim; 
00131        }
00132        BitsPerPixel = colorstobpp(tim->colorsTotal);
00133        /* All set, let's do it. */
00134        GIFEncode(
00135               out, tim->sx, tim->sy, tim->interlace, 0, tim->transparent, BitsPerPixel,
00136               tim->red, tim->green, tim->blue, tim);
00137        if (pim) {
00138               /* Destroy palette based temporary image. */
00139               gdImageDestroy(      pim);
00140        }
00141 }
00142 
00143 static int
00144 colorstobpp(int colors)
00145 {
00146     int bpp = 0;
00147 
00148     if ( colors <= 2 )
00149         bpp = 1;
00150     else if ( colors <= 4 )
00151         bpp = 2;
00152     else if ( colors <= 8 )
00153         bpp = 3;
00154     else if ( colors <= 16 )
00155         bpp = 4;
00156     else if ( colors <= 32 )
00157         bpp = 5;
00158     else if ( colors <= 64 )
00159         bpp = 6;
00160     else if ( colors <= 128 )
00161         bpp = 7;
00162     else if ( colors <= 256 )
00163         bpp = 8;
00164     return bpp;
00165     }
00166 
00167 /*****************************************************************************
00168  *
00169  * GIFENCODE.C    - GIF Image compression interface
00170  *
00171  * GIFEncode( FName, GHeight, GWidth, GInterlace, Background, Transparent,
00172  *            BitsPerPixel, Red, Green, Blue, gdImagePtr )
00173  *
00174  *****************************************************************************/
00175 
00176 #define TRUE 1
00177 #define FALSE 0
00178 /*
00179  * Bump the 'curx' and 'cury' to point to the next pixel
00180  */
00181 static void
00182 BumpPixel(GifCtx *ctx)
00183 {
00184         /*
00185          * Bump the current X position
00186          */
00187         ++(ctx->curx);
00188 
00189         /*
00190          * If we are at the end of a scan line, set curx back to the beginning
00191          * If we are interlaced, bump the cury to the appropriate spot,
00192          * otherwise, just increment it.
00193          */
00194         if( ctx->curx == ctx->Width ) {
00195                 ctx->curx = 0;
00196 
00197                 if( !ctx->Interlace )
00198                         ++(ctx->cury);
00199                 else {
00200                      switch( ctx->Pass ) {
00201 
00202                        case 0:
00203                           ctx->cury += 8;
00204                           if( ctx->cury >= ctx->Height ) {
00205                                 ++(ctx->Pass);
00206                                 ctx->cury = 4;
00207                           }
00208                           break;
00209 
00210                        case 1:
00211                           ctx->cury += 8;
00212                           if( ctx->cury >= ctx->Height ) {
00213                                 ++(ctx->Pass);
00214                                 ctx->cury = 2;
00215                           }
00216                           break;
00217 
00218                        case 2:
00219                           ctx->cury += 4;
00220                           if( ctx->cury >= ctx->Height ) {
00221                              ++(ctx->Pass);
00222                              ctx->cury = 1;
00223                           }
00224                           break;
00225 
00226                        case 3:
00227                           ctx->cury += 2;
00228                           break;
00229                         }
00230                 }
00231         }
00232 }
00233 
00234 /*
00235  * Return the next pixel from the image
00236  */
00237 static int
00238 GIFNextPixel(gdImagePtr im, GifCtx *ctx)
00239 {
00240         int r;
00241 
00242         if( ctx->CountDown == 0 )
00243                 return EOF;
00244 
00245         --(ctx->CountDown);
00246 
00247         r = gdImageGetPixel(im, ctx->curx, ctx->cury);
00248 
00249         BumpPixel(ctx);
00250 
00251         return r;
00252 }
00253 
00254 /* public */
00255 
00256 static void
00257 GIFEncode(gdIOCtxPtr fp, int GWidth, int GHeight, int GInterlace, int Background, int Transparent, int BitsPerPixel, int *Red, int *Green, int *Blue, gdImagePtr im)
00258 {
00259         int B;
00260         int RWidth, RHeight;
00261         int LeftOfs, TopOfs;
00262         int Resolution;
00263         int ColorMapSize;
00264         int InitCodeSize;
00265         int i;
00266               GifCtx ctx;
00267 
00268               memset(&ctx, 0, sizeof(ctx));
00269         ctx.Interlace = GInterlace;
00270               ctx.in_count = 1;
00271 
00272         ColorMapSize = 1 << BitsPerPixel;
00273 
00274         RWidth = ctx.Width = GWidth;
00275         RHeight = ctx.Height = GHeight;
00276         LeftOfs = TopOfs = 0;
00277 
00278         Resolution = BitsPerPixel;
00279 
00280         /*
00281          * Calculate number of bits we are expecting
00282          */
00283         ctx.CountDown = (long)ctx.Width * (long)ctx.Height;
00284 
00285         /*
00286          * Indicate which pass we are on (if interlace)
00287          */
00288         ctx.Pass = 0;
00289 
00290         /*
00291          * The initial code size
00292          */
00293         if( BitsPerPixel <= 1 )
00294                 InitCodeSize = 2;
00295         else
00296                 InitCodeSize = BitsPerPixel;
00297 
00298         /*
00299          * Set up the current x and y position
00300          */
00301         ctx.curx = ctx.cury = 0;
00302 
00303         /*
00304          * Write the Magic header
00305          */
00306         gdPutBuf(Transparent < 0 ? "GIF87a" : "GIF89a", 6, fp );
00307 
00308         /*
00309          * Write out the screen width and height
00310          */
00311         gifPutWord( RWidth, fp );
00312         gifPutWord( RHeight, fp );
00313 
00314         /*
00315          * Indicate that there is a global colour map
00316          */
00317         B = 0x80;       /* Yes, there is a color map */
00318 
00319         /*
00320          * OR in the resolution
00321          */
00322         B |= (Resolution - 1) << 5;
00323 
00324         /*
00325          * OR in the Bits per Pixel
00326          */
00327         B |= (BitsPerPixel - 1);
00328 
00329         /*
00330          * Write it out
00331          */
00332         gdPutC( B, fp );
00333 
00334         /*
00335          * Write out the Background colour
00336          */
00337         gdPutC( Background, fp );
00338 
00339         /*
00340          * Byte of 0's (future expansion)
00341          */
00342         gdPutC( 0, fp );
00343 
00344         /*
00345          * Write out the Global Colour Map
00346          */
00347         for( i=0; i<ColorMapSize; ++i ) {
00348                 gdPutC( Red[i], fp );
00349                 gdPutC( Green[i], fp );
00350                 gdPutC( Blue[i], fp );
00351         }
00352 
00353        /*
00354         * Write out extension for transparent colour index, if necessary.
00355         */
00356        if ( Transparent >= 0 ) {
00357            gdPutC( '!', fp );
00358            gdPutC( 0xf9, fp );
00359            gdPutC( 4, fp );
00360            gdPutC( 1, fp );
00361            gdPutC( 0, fp );
00362            gdPutC( 0, fp );
00363            gdPutC( (unsigned char) Transparent, fp );
00364            gdPutC( 0, fp );
00365        }
00366 
00367         /*
00368          * Write an Image separator
00369          */
00370         gdPutC( ',', fp );
00371 
00372         /*
00373          * Write the Image header
00374          */
00375 
00376         gifPutWord( LeftOfs, fp );
00377         gifPutWord( TopOfs, fp );
00378         gifPutWord( ctx.Width, fp );
00379         gifPutWord( ctx.Height, fp );
00380 
00381         /*
00382          * Write out whether or not the image is interlaced
00383          */
00384         if( ctx.Interlace )
00385                 gdPutC( 0x40, fp );
00386         else
00387                 gdPutC( 0x00, fp );
00388 
00389         /*
00390          * Write out the initial code size
00391          */
00392         gdPutC( InitCodeSize, fp );
00393 
00394         /*
00395          * Go and actually compress the data
00396          */
00397         compress( InitCodeSize+1, fp, im, &ctx );
00398 
00399         /*
00400          * Write out a Zero-length packet (to end the series)
00401          */
00402         gdPutC( 0, fp );
00403 
00404         /*
00405          * Write the GIF file terminator
00406          */
00407         gdPutC( ';', fp );
00408 }
00409 
00410 /***************************************************************************
00411  *
00412  *  GIFCOMPR.C       - GIF Image compression routines
00413  *
00414  *  Lempel-Ziv compression based on 'compress'.  GIF modifications by
00415  *  David Rowley (mgardi@watdcsu.waterloo.edu)
00416  *
00417  ***************************************************************************/
00418 
00419 /*
00420  * General DEFINEs
00421  */
00422 
00423 #define GIFBITS    12
00424 
00425 #ifdef NO_UCHAR
00426  typedef char   char_type;
00427 #else /*NO_UCHAR*/
00428  typedef        unsigned char   char_type;
00429 #endif /*NO_UCHAR*/
00430 
00431 /*
00432  *
00433  * GIF Image compression - modified 'compress'
00434  *
00435  * Based on: compress.c - File compression ala IEEE Computer, June 1984.
00436  *
00437  * By Authors:  Spencer W. Thomas       (decvax!harpo!utah-cs!utah-gr!thomas)
00438  *              Jim McKie               (decvax!mcvax!jim)
00439  *              Steve Davies            (decvax!vax135!petsd!peora!srd)
00440  *              Ken Turkowski           (decvax!decwrl!turtlevax!ken)
00441  *              James A. Woods          (decvax!ihnp4!ames!jaw)
00442  *              Joe Orost               (decvax!vax135!petsd!joe)
00443  *
00444  */
00445 #include <ctype.h>
00446 
00447 #define ARGVAL() (*++(*argv) || (--argc && *++argv))
00448 
00449 #ifdef COMPATIBLE               /* But wrong! */
00450 # define MAXCODE(n_bits)        ((code_int) 1 << (n_bits) - 1)
00451 #else /*COMPATIBLE*/
00452 # define MAXCODE(n_bits)        (((code_int) 1 << (n_bits)) - 1)
00453 #endif /*COMPATIBLE*/
00454 
00455 #define HashTabOf(i)       ctx->htab[i]
00456 #define CodeTabOf(i)    ctx->codetab[i]
00457 
00458 
00459 /*
00460  * To save much memory, we overlay the table used by compress() with those
00461  * used by decompress().  The tab_prefix table is the same size and type
00462  * as the codetab.  The tab_suffix table needs 2**GIFBITS characters.  We
00463  * get this from the beginning of htab.  The output stack uses the rest
00464  * of htab, and contains characters.  There is plenty of room for any
00465  * possible stack (stack used to be 8000 characters).
00466  */
00467 
00468 #define tab_prefixof(i) CodeTabOf(i)
00469 #define tab_suffixof(i)        ((char_type*)(htab))[i]
00470 #define de_stack               ((char_type*)&tab_suffixof((code_int)1<<GIFBITS))
00471 
00472 /*
00473  * compress stdin to stdout
00474  *
00475  * Algorithm:  use open addressing double hashing (no chaining) on the
00476  * prefix code / next character combination.  We do a variant of Knuth's
00477  * algorithm D (vol. 3, sec. 6.4) along with G. Knott's relatively-prime
00478  * secondary probe.  Here, the modular division first probe is gives way
00479  * to a faster exclusive-or manipulation.  Also do block compression with
00480  * an adaptive reset, whereby the code table is cleared when the compression
00481  * ratio decreases, but after the table fills.  The variable-length output
00482  * codes are re-sized at this point, and a special CLEAR code is generated
00483  * for the decompressor.  Late addition:  construct the table according to
00484  * file size for noticeable speed improvement on small files.  Please direct
00485  * questions about this implementation to ames!jaw.
00486  */
00487 
00488 static void
00489 output(code_int code, GifCtx *ctx);
00490 
00491 static void
00492 compress(int init_bits, gdIOCtxPtr outfile, gdImagePtr im, GifCtx *ctx)
00493 {
00494     register long fcode;
00495     register code_int i /* = 0 */;
00496     register int c;
00497     register code_int ent;
00498     register code_int disp;
00499     register code_int hsize_reg;
00500     register int hshift;
00501 
00502     /*
00503      * Set up the globals:  g_init_bits - initial number of bits
00504      *                      g_outfile   - pointer to output file
00505      */
00506     ctx->g_init_bits = init_bits;
00507     ctx->g_outfile = outfile;
00508 
00509     /*
00510      * Set up the necessary values
00511      */
00512     ctx->offset = 0;
00513     ctx->out_count = 0;
00514     ctx->clear_flg = 0;
00515     ctx->in_count = 1;
00516     ctx->maxcode = MAXCODE(ctx->n_bits = ctx->g_init_bits);
00517 
00518     ctx->ClearCode = (1 << (init_bits - 1));
00519     ctx->EOFCode = ctx->ClearCode + 1;
00520     ctx->free_ent = ctx->ClearCode + 2;
00521 
00522     char_init(ctx);
00523 
00524     ent = GIFNextPixel( im, ctx );
00525 
00526     hshift = 0;
00527     for ( fcode = (long) hsize;  fcode < 65536L; fcode *= 2L )
00528         ++hshift;
00529     hshift = 8 - hshift;                /* set hash code range bound */
00530 
00531     hsize_reg = hsize;
00532     cl_hash( (count_int) hsize_reg, ctx );            /* clear hash table */
00533 
00534     output( (code_int)ctx->ClearCode, ctx );
00535 
00536 #ifdef SIGNED_COMPARE_SLOW
00537     while ( (c = GIFNextPixel( im )) != (unsigned) EOF ) {
00538 #else /*SIGNED_COMPARE_SLOW*/
00539     while ( (c = GIFNextPixel( im, ctx )) != EOF ) {  /* } */
00540 #endif /*SIGNED_COMPARE_SLOW*/
00541 
00542         ++(ctx->in_count);
00543 
00544         fcode = (long) (((long) c << maxbits) + ent);
00545         i = (((code_int)c << hshift) ^ ent);    /* xor hashing */
00546 
00547         if ( HashTabOf (i) == fcode ) {
00548             ent = CodeTabOf (i);
00549             continue;
00550         } else if ( (long)HashTabOf (i) < 0 )      /* empty slot */
00551             goto nomatch;
00552         disp = hsize_reg - i;           /* secondary hash (after G. Knott) */
00553         if ( i == 0 )
00554             disp = 1;
00555 probe:
00556         if ( (i -= disp) < 0 )
00557             i += hsize_reg;
00558 
00559         if ( HashTabOf (i) == fcode ) {
00560             ent = CodeTabOf (i);
00561             continue;
00562         }
00563         if ( (long)HashTabOf (i) > 0 )
00564             goto probe;
00565 nomatch:
00566         output ( (code_int) ent, ctx );
00567         ++(ctx->out_count);
00568         ent = c;
00569 #ifdef SIGNED_COMPARE_SLOW
00570         if ( (unsigned) ctx->free_ent < (unsigned) maxmaxcode) {
00571 #else /*SIGNED_COMPARE_SLOW*/
00572         if ( ctx->free_ent < maxmaxcode ) {  /* } */
00573 #endif /*SIGNED_COMPARE_SLOW*/
00574             CodeTabOf (i) = ctx->free_ent++; /* code -> hashtable */
00575             HashTabOf (i) = fcode;
00576         } else
00577                 cl_block(ctx);
00578     }
00579     /*
00580      * Put out the final code.
00581      */
00582     output( (code_int)ent, ctx );
00583     ++(ctx->out_count);
00584     output( (code_int) ctx->EOFCode, ctx );
00585 }
00586 
00587 /*****************************************************************
00588  * TAG( output )
00589  *
00590  * Output the given code.
00591  * Inputs:
00592  *      code:   A n_bits-bit integer.  If == -1, then EOF.  This assumes
00593  *              that n_bits =< (long)wordsize - 1.
00594  * Outputs:
00595  *      Outputs code to the file.
00596  * Assumptions:
00597  *      Chars are 8 bits long.
00598  * Algorithm:
00599  *      Maintain a GIFBITS character long buffer (so that 8 codes will
00600  * fit in it exactly).  Use the VAX insv instruction to insert each
00601  * code in turn.  When the buffer fills up empty it and start over.
00602  */
00603 
00604 static unsigned long masks[] = { 0x0000, 0x0001, 0x0003, 0x0007, 0x000F,
00605                                   0x001F, 0x003F, 0x007F, 0x00FF,
00606                                   0x01FF, 0x03FF, 0x07FF, 0x0FFF,
00607                                   0x1FFF, 0x3FFF, 0x7FFF, 0xFFFF };
00608 
00609 static void
00610 output(code_int code, GifCtx *ctx)
00611 {
00612     ctx->cur_accum &= masks[ ctx->cur_bits ];
00613 
00614     if( ctx->cur_bits > 0 )
00615         ctx->cur_accum |= ((long)code << ctx->cur_bits);
00616     else
00617         ctx->cur_accum = code;
00618 
00619     ctx->cur_bits += ctx->n_bits;
00620 
00621     while( ctx->cur_bits >= 8 ) {
00622         char_out( (unsigned int)(ctx->cur_accum & 0xff), ctx );
00623         ctx->cur_accum >>= 8;
00624         ctx->cur_bits -= 8;
00625     }
00626 
00627     /*
00628      * If the next entry is going to be too big for the code size,
00629      * then increase it, if possible.
00630      */
00631    if ( ctx->free_ent > ctx->maxcode || ctx->clear_flg ) {
00632 
00633             if( ctx->clear_flg ) {
00634 
00635                 ctx->maxcode = MAXCODE (ctx->n_bits = ctx->g_init_bits);
00636                 ctx->clear_flg = 0;
00637 
00638             } else {
00639 
00640                 ++(ctx->n_bits);
00641                 if ( ctx->n_bits == maxbits )
00642                     ctx->maxcode = maxmaxcode;
00643                 else
00644                     ctx->maxcode = MAXCODE(ctx->n_bits);
00645             }
00646         }
00647 
00648     if( code == ctx->EOFCode ) {
00649         /*
00650          * At EOF, write the rest of the buffer.
00651          */
00652         while( ctx->cur_bits > 0 ) {
00653                 char_out( (unsigned int)(ctx->cur_accum & 0xff), ctx);
00654                 ctx->cur_accum >>= 8;
00655                 ctx->cur_bits -= 8;
00656         }
00657 
00658         flush_char(ctx);
00659 
00660     }
00661 }
00662 
00663 /*
00664  * Clear out the hash table
00665  */
00666 static void
00667 cl_block (GifCtx *ctx)             /* table clear for block compress */
00668 {
00669 
00670         cl_hash ( (count_int) hsize, ctx );
00671         ctx->free_ent = ctx->ClearCode + 2;
00672         ctx->clear_flg = 1;
00673 
00674         output( (code_int)ctx->ClearCode, ctx);
00675 }
00676 
00677 static void
00678 cl_hash(register count_int chsize, GifCtx *ctx)          /* reset code table */
00679                          
00680 {
00681 
00682         register count_int *htab_p = ctx->htab+chsize;
00683 
00684         register long i;
00685         register long m1 = -1;
00686 
00687         i = chsize - 16;
00688         do {                            /* might use Sys V memset(3) here */
00689                 *(htab_p-16) = m1;
00690                 *(htab_p-15) = m1;
00691                 *(htab_p-14) = m1;
00692                 *(htab_p-13) = m1;
00693                 *(htab_p-12) = m1;
00694                 *(htab_p-11) = m1;
00695                 *(htab_p-10) = m1;
00696                 *(htab_p-9) = m1;
00697                 *(htab_p-8) = m1;
00698                 *(htab_p-7) = m1;
00699                 *(htab_p-6) = m1;
00700                 *(htab_p-5) = m1;
00701                 *(htab_p-4) = m1;
00702                 *(htab_p-3) = m1;
00703                 *(htab_p-2) = m1;
00704                 *(htab_p-1) = m1;
00705                 htab_p -= 16;
00706         } while ((i -= 16) >= 0);
00707 
00708         for ( i += 16; i > 0; --i )
00709                 *--htab_p = m1;
00710 }
00711 
00712 /******************************************************************************
00713  *
00714  * GIF Specific routines
00715  *
00716  ******************************************************************************/
00717 
00718 /*
00719  * Set up the 'byte output' routine
00720  */
00721 static void
00722 char_init(GifCtx *ctx)
00723 {
00724         ctx->a_count = 0;
00725 }
00726 
00727 /*
00728  * Add a character to the end of the current packet, and if it is 254
00729  * characters, flush the packet to disk.
00730  */
00731 static void
00732 char_out(int c, GifCtx *ctx)
00733 {
00734         ctx->accum[ ctx->a_count++ ] = c;
00735         if( ctx->a_count >= 254 )
00736                 flush_char(ctx);
00737 }
00738 
00739 /*
00740  * Flush the packet to disk, and reset the accumulator
00741  */
00742 static void
00743 flush_char(GifCtx *ctx)
00744 {
00745         if( ctx->a_count > 0 ) {
00746                 gdPutC( ctx->a_count, ctx->g_outfile );
00747                 gdPutBuf( ctx->accum, ctx->a_count, ctx->g_outfile );
00748                 ctx->a_count = 0;
00749         }
00750 }
00751 
00752 static int gifPutWord(int w, gdIOCtx *out)
00753 {
00754        /* Byte order is little-endian */
00755        gdPutC(w & 0xFF, out);
00756        gdPutC((w >> 8) & 0xFF, out);
00757        return 0;
00758 }
00759 
00760