xref: /PHP-8.1/ext/gd/libgd/gd_gif_out.c (revision d4bd6fb4)
1 #include <stdio.h>
2 #include <math.h>
3 #include <string.h>
4 #include <stdlib.h>
5 #include "gd.h"
6 
7 /* Code drawn from ppmtogif.c, from the pbmplus package
8 **
9 ** Based on GIFENCOD by David Rowley <mgardi@watdscu.waterloo.edu>. A
10 ** Lempel-Zim compression based on "compress".
11 **
12 ** Modified by Marcel Wijkstra <wijkstra@fwi.uva.nl>
13 **
14 ** Copyright (C) 1989 by Jef Poskanzer.
15 **
16 ** Permission to use, copy, modify, and distribute this software and its
17 ** documentation for any purpose and without fee is hereby granted, provided
18 ** that the above copyright notice appear in all copies and that both that
19 ** copyright notice and this permission notice appear in supporting
20 ** documentation.  This software is provided "as is" without express or
21 ** implied warranty.
22 **
23 ** The Graphics Interchange Format(c) is the Copyright property of
24 ** CompuServe Incorporated.  GIF(sm) is a Service Mark property of
25 ** CompuServe Incorporated.
26 */
27 
28 /*
29  * a code_int must be able to hold 2**GIFBITS values of type int, and also -1
30  */
31 typedef int             code_int;
32 
33 #ifdef SIGNED_COMPARE_SLOW
34 typedef unsigned long int count_int;
35 typedef unsigned short int count_short;
36 #else /*SIGNED_COMPARE_SLOW*/
37 typedef long int          count_int;
38 #endif /*SIGNED_COMPARE_SLOW*/
39 
40 /* 2.0.28: threadsafe */
41 
42 #define maxbits GIFBITS
43 
44 /* should NEVER generate this code */
45 #define maxmaxcode ((code_int)1 << GIFBITS)
46 
47 #define HSIZE  5003            /* 80% occupancy */
48 #define hsize HSIZE            /* Apparently invariant, left over from
49 					compress */
50 
51 typedef struct {
52 	int Width, Height;
53 	int curx, cury;
54 	long CountDown;
55 	int Pass;
56 	int Interlace;
57         int n_bits;                        /* number of bits/code */
58         code_int maxcode;                  /* maximum code, given n_bits */
59         count_int htab [HSIZE];
60         unsigned short codetab [HSIZE];
61 	code_int free_ent;                  /* first unused entry */
62 	/*
63 	 * block compression parameters -- after all codes are used up,
64 	 * and compression rate changes, start over.
65 	 */
66 	int clear_flg;
67 	int offset;
68 	long int in_count;            /* length of input */
69 	long int out_count;           /* # of codes output (for debugging) */
70 
71 	int g_init_bits;
72 	gdIOCtx * g_outfile;
73 
74 	int ClearCode;
75 	int EOFCode;
76 	unsigned long cur_accum;
77 	int cur_bits;
78         /*
79          * Number of characters so far in this 'packet'
80          */
81         int a_count;
82         /*
83          * Define the storage for the packet accumulator
84          */
85         char accum[ 256 ];
86 } GifCtx;
87 
88 static int gifPutWord(int w, gdIOCtx *out);
89 static int colorstobpp(int colors);
90 static void BumpPixel (GifCtx *ctx);
91 static int GIFNextPixel (gdImagePtr im, GifCtx *ctx);
92 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);
93 static void compress (int init_bits, gdIOCtx *outfile, gdImagePtr im, GifCtx *ctx);
94 static void output (code_int code, GifCtx *ctx);
95 static void cl_block (GifCtx *ctx);
96 static void cl_hash (register count_int chsize, GifCtx *ctx);
97 static void char_init (GifCtx *ctx);
98 static void char_out (int c, GifCtx *ctx);
99 static void flush_char (GifCtx *ctx);
100 
101 static int _gdImageGifCtx(gdImagePtr im, gdIOCtxPtr out);
102 
gdImageGifPtr(gdImagePtr im,int * size)103 void * gdImageGifPtr (gdImagePtr im, int *size)
104 {
105   void *rv;
106   gdIOCtx *out = gdNewDynamicCtx (2048, NULL);
107 	if (!_gdImageGifCtx(im, out)) {
108 		rv = gdDPExtractData(out, size);
109 	} else {
110 		rv = NULL;
111 	}
112   out->gd_free (out);
113   return rv;
114 }
115 
gdImageGif(gdImagePtr im,FILE * outFile)116 void gdImageGif (gdImagePtr im, FILE * outFile)
117 {
118   gdIOCtx *out = gdNewFileCtx (outFile);
119   gdImageGifCtx (im, out);
120   out->gd_free (out);
121 }
122 
gdImageGifCtx(gdImagePtr im,gdIOCtxPtr out)123 void gdImageGifCtx(gdImagePtr im, gdIOCtxPtr out)
124 {
125 	_gdImageGifCtx(im, out);
126 }
127 
128 /* returns 0 on success, 1 on failure */
_gdImageGifCtx(gdImagePtr im,gdIOCtxPtr out)129 static int _gdImageGifCtx(gdImagePtr im, gdIOCtxPtr out)
130 {
131 	gdImagePtr pim = 0, tim = im;
132 	int interlace, BitsPerPixel;
133 	interlace = im->interlace;
134 	if (im->trueColor) {
135 		/* Expensive, but the only way that produces an
136 			acceptable result: mix down to a palette
137 			based temporary image. */
138 		pim = gdImageCreatePaletteFromTrueColor(im, 1, 256);
139 		if (!pim) {
140 			return 1;
141 		}
142 		tim = pim;
143 	}
144 	BitsPerPixel = colorstobpp(tim->colorsTotal);
145 	/* All set, let's do it. */
146 	GIFEncode(
147 		out, tim->sx, tim->sy, interlace, 0, tim->transparent, BitsPerPixel,
148 		tim->red, tim->green, tim->blue, tim);
149 	if (pim) {
150 		/* Destroy palette based temporary image. */
151 		gdImageDestroy(	pim);
152 	}
153 
154     return 0;
155 }
156 
157 static int
colorstobpp(int colors)158 colorstobpp(int colors)
159 {
160     int bpp = 0;
161 
162     if ( colors <= 2 )
163         bpp = 1;
164     else if ( colors <= 4 )
165         bpp = 2;
166     else if ( colors <= 8 )
167         bpp = 3;
168     else if ( colors <= 16 )
169         bpp = 4;
170     else if ( colors <= 32 )
171         bpp = 5;
172     else if ( colors <= 64 )
173         bpp = 6;
174     else if ( colors <= 128 )
175         bpp = 7;
176     else if ( colors <= 256 )
177         bpp = 8;
178     return bpp;
179     }
180 
181 /*****************************************************************************
182  *
183  * GIFENCODE.C    - GIF Image compression interface
184  *
185  * GIFEncode( FName, GHeight, GWidth, GInterlace, Background, Transparent,
186  *            BitsPerPixel, Red, Green, Blue, gdImagePtr )
187  *
188  *****************************************************************************/
189 
190 #define TRUE 1
191 #define FALSE 0
192 /*
193  * Bump the 'curx' and 'cury' to point to the next pixel
194  */
195 static void
BumpPixel(GifCtx * ctx)196 BumpPixel(GifCtx *ctx)
197 {
198         /*
199          * Bump the current X position
200          */
201         ++(ctx->curx);
202 
203         /*
204          * If we are at the end of a scan line, set curx back to the beginning
205          * If we are interlaced, bump the cury to the appropriate spot,
206          * otherwise, just increment it.
207          */
208         if( ctx->curx == ctx->Width ) {
209                 ctx->curx = 0;
210 
211                 if( !ctx->Interlace )
212                         ++(ctx->cury);
213                 else {
214                      switch( ctx->Pass ) {
215 
216                        case 0:
217                           ctx->cury += 8;
218                           if( ctx->cury >= ctx->Height ) {
219                                 ++(ctx->Pass);
220                                 ctx->cury = 4;
221                           }
222                           break;
223 
224                        case 1:
225                           ctx->cury += 8;
226                           if( ctx->cury >= ctx->Height ) {
227                                 ++(ctx->Pass);
228                                 ctx->cury = 2;
229                           }
230                           break;
231 
232                        case 2:
233                           ctx->cury += 4;
234                           if( ctx->cury >= ctx->Height ) {
235                              ++(ctx->Pass);
236                              ctx->cury = 1;
237                           }
238                           break;
239 
240                        case 3:
241                           ctx->cury += 2;
242                           break;
243                         }
244                 }
245         }
246 }
247 
248 /*
249  * Return the next pixel from the image
250  */
251 static int
GIFNextPixel(gdImagePtr im,GifCtx * ctx)252 GIFNextPixel(gdImagePtr im, GifCtx *ctx)
253 {
254         int r;
255 
256         if( ctx->CountDown == 0 )
257                 return EOF;
258 
259         --(ctx->CountDown);
260 
261         r = gdImageGetPixel(im, ctx->curx, ctx->cury);
262 
263         BumpPixel(ctx);
264 
265         return r;
266 }
267 
268 /* public */
269 
270 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)271 GIFEncode(gdIOCtxPtr fp, int GWidth, int GHeight, int GInterlace, int Background, int Transparent, int BitsPerPixel, int *Red, int *Green, int *Blue, gdImagePtr im)
272 {
273         int B;
274         int RWidth, RHeight;
275         int LeftOfs, TopOfs;
276         int Resolution;
277         int ColorMapSize;
278         int InitCodeSize;
279         int i;
280 		GifCtx ctx;
281 
282 		memset(&ctx, 0, sizeof(ctx));
283         ctx.Interlace = GInterlace;
284 		ctx.in_count = 1;
285 
286         ColorMapSize = 1 << BitsPerPixel;
287 
288         RWidth = ctx.Width = GWidth;
289         RHeight = ctx.Height = GHeight;
290         LeftOfs = TopOfs = 0;
291 
292         Resolution = BitsPerPixel;
293 
294         /*
295          * Calculate number of bits we are expecting
296          */
297         ctx.CountDown = (long)ctx.Width * (long)ctx.Height;
298 
299         /*
300          * Indicate which pass we are on (if interlace)
301          */
302         ctx.Pass = 0;
303 
304         /*
305          * The initial code size
306          */
307         if( BitsPerPixel <= 1 )
308                 InitCodeSize = 2;
309         else
310                 InitCodeSize = BitsPerPixel;
311 
312         /*
313          * Set up the current x and y position
314          */
315         ctx.curx = ctx.cury = 0;
316 
317         /*
318          * Write the Magic header
319          */
320         gdPutBuf(Transparent < 0 ? "GIF87a" : "GIF89a", 6, fp );
321 
322         /*
323          * Write out the screen width and height
324          */
325         gifPutWord( RWidth, fp );
326         gifPutWord( RHeight, fp );
327 
328         /*
329          * Indicate that there is a global colour map
330          */
331         B = 0x80;       /* Yes, there is a color map */
332 
333         /*
334          * OR in the resolution
335          */
336         B |= (Resolution - 1) << 4;
337 
338         /*
339          * OR in the Bits per Pixel
340          */
341         B |= (BitsPerPixel - 1);
342 
343         /*
344          * Write it out
345          */
346         gdPutC( B, fp );
347 
348         /*
349          * Write out the Background colour
350          */
351         gdPutC( Background, fp );
352 
353         /*
354          * Byte of 0's (future expansion)
355          */
356         gdPutC( 0, fp );
357 
358         /*
359          * Write out the Global Colour Map
360          */
361         for( i=0; i<ColorMapSize; ++i ) {
362                 gdPutC( Red[i], fp );
363                 gdPutC( Green[i], fp );
364                 gdPutC( Blue[i], fp );
365         }
366 
367 	/*
368 	 * Write out extension for transparent colour index, if necessary.
369 	 */
370 	if ( Transparent >= 0 ) {
371 	    gdPutC( '!', fp );
372 	    gdPutC( 0xf9, fp );
373 	    gdPutC( 4, fp );
374 	    gdPutC( 1, fp );
375 	    gdPutC( 0, fp );
376 	    gdPutC( 0, fp );
377 	    gdPutC( (unsigned char) Transparent, fp );
378 	    gdPutC( 0, fp );
379 	}
380 
381         /*
382          * Write an Image separator
383          */
384         gdPutC( ',', fp );
385 
386         /*
387          * Write the Image header
388          */
389 
390         gifPutWord( LeftOfs, fp );
391         gifPutWord( TopOfs, fp );
392         gifPutWord( ctx.Width, fp );
393         gifPutWord( ctx.Height, fp );
394 
395         /*
396          * Write out whether or not the image is interlaced
397          */
398         if( ctx.Interlace )
399                 gdPutC( 0x40, fp );
400         else
401                 gdPutC( 0x00, fp );
402 
403         /*
404          * Write out the initial code size
405          */
406         gdPutC( InitCodeSize, fp );
407 
408         /*
409          * Go and actually compress the data
410          */
411         compress( InitCodeSize+1, fp, im, &ctx );
412 
413         /*
414          * Write out a Zero-length packet (to end the series)
415          */
416         gdPutC( 0, fp );
417 
418         /*
419          * Write the GIF file terminator
420          */
421         gdPutC( ';', fp );
422 }
423 
424 /***************************************************************************
425  *
426  *  GIFCOMPR.C       - GIF Image compression routines
427  *
428  *  Lempel-Ziv compression based on 'compress'.  GIF modifications by
429  *  David Rowley (mgardi@watdcsu.waterloo.edu)
430  *
431  ***************************************************************************/
432 
433 /*
434  * General DEFINEs
435  */
436 
437 #define GIFBITS    12
438 
439 #ifdef NO_UCHAR
440  typedef char   char_type;
441 #else /*NO_UCHAR*/
442  typedef        unsigned char   char_type;
443 #endif /*NO_UCHAR*/
444 
445 /*
446  *
447  * GIF Image compression - modified 'compress'
448  *
449  * Based on: compress.c - File compression ala IEEE Computer, June 1984.
450  *
451  * By Authors:  Spencer W. Thomas       (decvax!harpo!utah-cs!utah-gr!thomas)
452  *              Jim McKie               (decvax!mcvax!jim)
453  *              Steve Davies            (decvax!vax135!petsd!peora!srd)
454  *              Ken Turkowski           (decvax!decwrl!turtlevax!ken)
455  *              James A. Woods          (decvax!ihnp4!ames!jaw)
456  *              Joe Orost               (decvax!vax135!petsd!joe)
457  *
458  */
459 #include <ctype.h>
460 
461 #define ARGVAL() (*++(*argv) || (--argc && *++argv))
462 
463 #ifdef COMPATIBLE               /* But wrong! */
464 # define MAXCODE(n_bits)        ((code_int) 1 << (n_bits) - 1)
465 #else /*COMPATIBLE*/
466 # define MAXCODE(n_bits)        (((code_int) 1 << (n_bits)) - 1)
467 #endif /*COMPATIBLE*/
468 
469 #define HashTabOf(i)       ctx->htab[i]
470 #define CodeTabOf(i)    ctx->codetab[i]
471 
472 
473 /*
474  * To save much memory, we overlay the table used by compress() with those
475  * used by decompress().  The tab_prefix table is the same size and type
476  * as the codetab.  The tab_suffix table needs 2**GIFBITS characters.  We
477  * get this from the beginning of htab.  The output stack uses the rest
478  * of htab, and contains characters.  There is plenty of room for any
479  * possible stack (stack used to be 8000 characters).
480  */
481 
482 #define tab_prefixof(i) CodeTabOf(i)
483 #define tab_suffixof(i)        ((char_type*)(htab))[i]
484 #define de_stack               ((char_type*)&tab_suffixof((code_int)1<<GIFBITS))
485 
486 /*
487  * compress stdin to stdout
488  *
489  * Algorithm:  use open addressing double hashing (no chaining) on the
490  * prefix code / next character combination.  We do a variant of Knuth's
491  * algorithm D (vol. 3, sec. 6.4) along with G. Knott's relatively-prime
492  * secondary probe.  Here, the modular division first probe is gives way
493  * to a faster exclusive-or manipulation.  Also do block compression with
494  * an adaptive reset, whereby the code table is cleared when the compression
495  * ratio decreases, but after the table fills.  The variable-length output
496  * codes are re-sized at this point, and a special CLEAR code is generated
497  * for the decompressor.  Late addition:  construct the table according to
498  * file size for noticeable speed improvement on small files.  Please direct
499  * questions about this implementation to ames!jaw.
500  */
501 
502 static void
503 output(code_int code, GifCtx *ctx);
504 
505 static void
compress(int init_bits,gdIOCtxPtr outfile,gdImagePtr im,GifCtx * ctx)506 compress(int init_bits, gdIOCtxPtr outfile, gdImagePtr im, GifCtx *ctx)
507 {
508     register long fcode;
509     register code_int i /* = 0 */;
510     register int c;
511     register code_int ent;
512     register code_int disp;
513     register code_int hsize_reg;
514     register int hshift;
515 
516     /*
517      * Set up the globals:  g_init_bits - initial number of bits
518      *                      g_outfile   - pointer to output file
519      */
520     ctx->g_init_bits = init_bits;
521     ctx->g_outfile = outfile;
522 
523     /*
524      * Set up the necessary values
525      */
526     ctx->offset = 0;
527     ctx->out_count = 0;
528     ctx->clear_flg = 0;
529     ctx->in_count = 1;
530     ctx->maxcode = MAXCODE(ctx->n_bits = ctx->g_init_bits);
531 
532     ctx->ClearCode = (1 << (init_bits - 1));
533     ctx->EOFCode = ctx->ClearCode + 1;
534     ctx->free_ent = ctx->ClearCode + 2;
535 
536     char_init(ctx);
537 
538     ent = GIFNextPixel( im, ctx );
539 
540     hshift = 0;
541     for ( fcode = (long) hsize;  fcode < 65536L; fcode *= 2L )
542         ++hshift;
543     hshift = 8 - hshift;                /* set hash code range bound */
544 
545     hsize_reg = hsize;
546     cl_hash( (count_int) hsize_reg, ctx );            /* clear hash table */
547 
548     output( (code_int)ctx->ClearCode, ctx );
549 
550 #ifdef SIGNED_COMPARE_SLOW
551     while ( (c = GIFNextPixel( im, ctx )) != (unsigned) EOF ) {
552 #else /*SIGNED_COMPARE_SLOW*/
553     while ( (c = GIFNextPixel( im, ctx )) != EOF ) {  /* } */
554 #endif /*SIGNED_COMPARE_SLOW*/
555 
556         ++(ctx->in_count);
557 
558         fcode = (long) (((long) c << maxbits) + ent);
559         i = (((code_int)c << hshift) ^ ent);    /* xor hashing */
560 
561         if ( HashTabOf (i) == fcode ) {
562             ent = CodeTabOf (i);
563             continue;
564         } else if ( (long)HashTabOf (i) < 0 )      /* empty slot */
565             goto nomatch;
566         disp = hsize_reg - i;           /* secondary hash (after G. Knott) */
567         if ( i == 0 )
568             disp = 1;
569 probe:
570         if ( (i -= disp) < 0 )
571             i += hsize_reg;
572 
573         if ( HashTabOf (i) == fcode ) {
574             ent = CodeTabOf (i);
575             continue;
576         }
577         if ( (long)HashTabOf (i) > 0 )
578             goto probe;
579 nomatch:
580         output ( (code_int) ent, ctx );
581         ++(ctx->out_count);
582         ent = c;
583 #ifdef SIGNED_COMPARE_SLOW
584         if ( (unsigned) ctx->free_ent < (unsigned) maxmaxcode) {
585 #else /*SIGNED_COMPARE_SLOW*/
586         if ( ctx->free_ent < maxmaxcode ) {  /* } */
587 #endif /*SIGNED_COMPARE_SLOW*/
588             CodeTabOf (i) = ctx->free_ent++; /* code -> hashtable */
589             HashTabOf (i) = fcode;
590         } else
591                 cl_block(ctx);
592     }
593     /*
594      * Put out the final code.
595      */
596     output( (code_int)ent, ctx );
597     ++(ctx->out_count);
598     output( (code_int) ctx->EOFCode, ctx );
599 }
600 
601 /*****************************************************************
602  * TAG( output )
603  *
604  * Output the given code.
605  * Inputs:
606  *      code:   A n_bits-bit integer.  If == -1, then EOF.  This assumes
607  *              that n_bits =< (long)wordsize - 1.
608  * Outputs:
609  *      Outputs code to the file.
610  * Assumptions:
611  *      Chars are 8 bits long.
612  * Algorithm:
613  *      Maintain a GIFBITS character long buffer (so that 8 codes will
614  * fit in it exactly).  Use the VAX insv instruction to insert each
615  * code in turn.  When the buffer fills up empty it and start over.
616  */
617 
618 static const unsigned long masks[] = { 0x0000, 0x0001, 0x0003, 0x0007, 0x000F,
619                                   0x001F, 0x003F, 0x007F, 0x00FF,
620                                   0x01FF, 0x03FF, 0x07FF, 0x0FFF,
621                                   0x1FFF, 0x3FFF, 0x7FFF, 0xFFFF };
622 
623 
624 /* Arbitrary value to mark output is done.  When we see EOFCode, then we don't
625  * expect to see any more data.  If we do (e.g. corrupt image inputs), cur_bits
626  * might be negative, so flag it to return early.
627  */
628 #define CUR_BITS_FINISHED -1000
629 
630 
631 static void
632 output(code_int code, GifCtx *ctx)
633 {
634 	if (ctx->cur_bits == CUR_BITS_FINISHED) {
635 		return;
636 	}
637 
638     ctx->cur_accum &= masks[ ctx->cur_bits ];
639 
640     if( ctx->cur_bits > 0 )
641         ctx->cur_accum |= ((long)code << ctx->cur_bits);
642     else
643         ctx->cur_accum = code;
644 
645     ctx->cur_bits += ctx->n_bits;
646 
647     while( ctx->cur_bits >= 8 ) {
648         char_out( (unsigned int)(ctx->cur_accum & 0xff), ctx );
649         ctx->cur_accum >>= 8;
650         ctx->cur_bits -= 8;
651     }
652 
653     /*
654      * If the next entry is going to be too big for the code size,
655      * then increase it, if possible.
656      */
657    if ( ctx->free_ent > ctx->maxcode || ctx->clear_flg ) {
658 
659             if( ctx->clear_flg ) {
660 
661                 ctx->maxcode = MAXCODE (ctx->n_bits = ctx->g_init_bits);
662                 ctx->clear_flg = 0;
663 
664             } else {
665 
666                 ++(ctx->n_bits);
667                 if ( ctx->n_bits == maxbits )
668                     ctx->maxcode = maxmaxcode;
669                 else
670                     ctx->maxcode = MAXCODE(ctx->n_bits);
671             }
672         }
673 
674     if( code == ctx->EOFCode ) {
675         /*
676          * At EOF, write the rest of the buffer.
677          */
678         while( ctx->cur_bits > 0 ) {
679                 char_out( (unsigned int)(ctx->cur_accum & 0xff), ctx);
680                 ctx->cur_accum >>= 8;
681                 ctx->cur_bits -= 8;
682         }
683 
684 		/* Flag that it's done to prevent re-entry. */
685 		ctx->cur_bits = CUR_BITS_FINISHED;
686 
687         flush_char(ctx);
688     }
689 }
690 
691 /*
692  * Clear out the hash table
693  */
694 static void
695 cl_block (GifCtx *ctx)             /* table clear for block compress */
696 {
697 
698         cl_hash ( (count_int) hsize, ctx );
699         ctx->free_ent = ctx->ClearCode + 2;
700         ctx->clear_flg = 1;
701 
702         output( (code_int)ctx->ClearCode, ctx);
703 }
704 
705 static void
706 cl_hash(register count_int chsize, GifCtx *ctx)          /* reset code table */
707 
708 {
709 
710         register count_int *htab_p = ctx->htab+chsize;
711 
712         register long i;
713         register long m1 = -1;
714 
715         i = chsize - 16;
716         do {                            /* might use Sys V memset(3) here */
717                 *(htab_p-16) = m1;
718                 *(htab_p-15) = m1;
719                 *(htab_p-14) = m1;
720                 *(htab_p-13) = m1;
721                 *(htab_p-12) = m1;
722                 *(htab_p-11) = m1;
723                 *(htab_p-10) = m1;
724                 *(htab_p-9) = m1;
725                 *(htab_p-8) = m1;
726                 *(htab_p-7) = m1;
727                 *(htab_p-6) = m1;
728                 *(htab_p-5) = m1;
729                 *(htab_p-4) = m1;
730                 *(htab_p-3) = m1;
731                 *(htab_p-2) = m1;
732                 *(htab_p-1) = m1;
733                 htab_p -= 16;
734         } while ((i -= 16) >= 0);
735 
736         for ( i += 16; i > 0; --i )
737                 *--htab_p = m1;
738 }
739 
740 /******************************************************************************
741  *
742  * GIF Specific routines
743  *
744  ******************************************************************************/
745 
746 /*
747  * Set up the 'byte output' routine
748  */
749 static void
750 char_init(GifCtx *ctx)
751 {
752         ctx->a_count = 0;
753 }
754 
755 /*
756  * Add a character to the end of the current packet, and if it is 254
757  * characters, flush the packet to disk.
758  */
759 static void
760 char_out(int c, GifCtx *ctx)
761 {
762         ctx->accum[ ctx->a_count++ ] = c;
763         if( ctx->a_count >= 254 )
764                 flush_char(ctx);
765 }
766 
767 /*
768  * Flush the packet to disk, and reset the accumulator
769  */
770 static void
771 flush_char(GifCtx *ctx)
772 {
773         if( ctx->a_count > 0 ) {
774                 gdPutC( ctx->a_count, ctx->g_outfile );
775                 gdPutBuf( ctx->accum, ctx->a_count, ctx->g_outfile );
776                 ctx->a_count = 0;
777         }
778 }
779 
780 static int gifPutWord(int w, gdIOCtx *out)
781 {
782 	/* Byte order is little-endian */
783 	gdPutC(w & 0xFF, out);
784 	gdPutC((w >> 8) & 0xFF, out);
785 	return 0;
786 }
787 
788 
789