Annotation of loncom/cgi/mimeTeX/gifsave.c, revision 1.2

1.1       albertel    1: /* $Id: gifsave.c,v 1.2 1998/07/05 16:29:56 sverrehu Exp $ */
                      2: /**************************************************************************
                      3:  *
                      4:  *  FILE            gifsave.c
                      5:  *
                      6:  *  DESCRIPTION     Routines to create a GIF-file. See README for
                      7:  *                  a description.
                      8:  *
                      9:  *                  The functions were originally written using Borland's
                     10:  *                  C-compiler on an IBM PC -compatible computer, but they
                     11:  *                  are compiled and tested on Linux and SunOS as well.
                     12:  *
                     13:  *  WRITTEN BY      Sverre H. Huseby <sverrehu@online.no>
                     14:  *
                     15:  **************************************************************************/
                     16: 
                     17: #include <stdlib.h>
                     18: #include <stdio.h>
                     19: /* #include <unistd.h> */	/* (added by j.forkosh) to get STDOUT_FILENO*/
                     20: #include <string.h>		/* " */
                     21: /* --- windows-specific header info --- */
                     22: #ifndef WINDOWS			/* -DWINDOWS not supplied by user */
1.2     ! albertel   23:   #if defined(_WINDOWS) || defined(_WIN32) || defined(WIN32) \
        !            24:   ||  defined(DJGPP)		/* try to recognize windows compilers */ \
        !            25:   ||  defined(_USRDLL)		/* must be WINDOWS if compiling for DLL */
1.1       albertel   26:     #define WINDOWS		/* signal windows */
                     27:   #endif
                     28: #endif
                     29: #ifdef WINDOWS			/* " if filename=NULL passed to GIF_Create()*/
                     30:   #include <fcntl.h>		/* " OutFile=stdout used.  But Windows opens*/
                     31:   #include <io.h>		/* " stdout in char mode, and precedes every*/
                     32: 				/* " 0x0A with spurious 0x0D. */
                     33:   #if defined(_O_BINARY) && !defined(O_BINARY)  /* only have _O_BINARY */
                     34:     #define O_BINARY _O_BINARY	/* make O_BINARY available, etc... */
                     35:     #define setmode  _setmode
                     36:     #define fileno   _fileno
                     37:   #endif
                     38:   #if defined(_O_BINARY) || defined(O_BINARY)  /* setmode() now available */
                     39:     #define HAVE_SETMODE	/* so we'll use setmode() */
                     40:   #endif
                     41: #endif
                     42: 
                     43: /* #include "gifsave.h" */	/* (j.forkosh) explcitly include header */
                     44: enum GIF_Code {
                     45:     GIF_OK = 0,
                     46:     GIF_ERRCREATE,
                     47:     GIF_ERRWRITE,
                     48:     GIF_OUTMEM
                     49: };
                     50: 
                     51: int  GIF_Create(const char *filename, int width, int height,
                     52: 		int numcolors, int colorres);
                     53: void GIF_SetColor(int colornum, int red, int green, int blue);
                     54: void GIF_SetTransparent(int colornum);	/* (added by j.forkosh) */
                     55: int  GIF_CompressImage(int left, int top, int width, int height,
                     56: 		       int (*getpixel)(int x, int y));
                     57: int  GIF_Close(void);
                     58: /* --- end-of-header gifsave.h --- */
                     59: 
                     60: 
                     61: /**************************************************************************
                     62:  *                                                                        *
                     63:  *                       P R I V A T E    D A T A                         *
                     64:  *                                                                        *
                     65:  **************************************************************************/
                     66: 
                     67: typedef unsigned Word;          /* at least two bytes (16 bits) */
                     68: typedef unsigned char Byte;     /* exactly one byte (8 bits) */
                     69: 
                     70: /* used by IO-routines */
                     71: static FILE *OutFile = NULL;    /* file to write to */
1.2     ! albertel   72: static Byte *OutBuffer = NULL;	/* (added by j.forkosh) */
        !            73: static int isCloseOutFile = 0;	/* " */
        !            74: int gifSize = 0;		/* " #bytes comprising gif */
        !            75: int maxgifSize = 64000;		/* " max #bytes written to OutBuffer */
1.1       albertel   76: 
                     77: /* used when writing to a file bitwise */
                     78: static Byte Buffer[256];        /* there must be one more than `needed' */
                     79: static int  Index,              /* current byte in buffer */
                     80:             BitsLeft;           /* bits left to fill in current byte. These
                     81:                                  * are right-justified */
                     82: 
                     83: /* used by routines maintaining an LZW string table */
                     84: #define RES_CODES 2
                     85: 
                     86: #define HASH_FREE 0xFFFF
                     87: #define NEXT_FIRST 0xFFFF
                     88: 
                     89: #define MAXBITS 12
                     90: #define MAXSTR (1 << MAXBITS)
                     91: 
                     92: #define HASHSIZE 9973
                     93: #define HASHSTEP 2039
                     94: 
                     95: #define HASH(index, lastbyte) (((lastbyte << 8) ^ index) % HASHSIZE)
                     96: 
                     97: static Byte *StrChr = NULL;
                     98: static Word *StrNxt = NULL,
                     99:             *StrHsh = NULL,
                    100:             NumStrings;
                    101: 
                    102: /* used in the main routines */
                    103: typedef struct {
                    104:     Word LocalScreenWidth,
                    105:          LocalScreenHeight;
                    106:     Byte GlobalColorTableSize : 3,
                    107:          SortFlag             : 1,
                    108:          ColorResolution      : 3,
                    109:          GlobalColorTableFlag : 1;
                    110:     Byte BackgroundColorIndex;
                    111:     Byte PixelAspectRatio;
                    112: } ScreenDescriptor;
                    113: 
                    114: typedef struct {
                    115:     Byte Separator;
                    116:     Word LeftPosition,
                    117:          TopPosition;
                    118:     Word Width,
                    119:          Height;
                    120:     Byte LocalColorTableSize : 3,
                    121:          Reserved            : 2,
                    122:          SortFlag            : 1,
                    123:          InterlaceFlag       : 1,
                    124:          LocalColorTableFlag : 1;
                    125: } ImageDescriptor;
                    126: 
                    127: static int  BitsPrPrimColor,    /* bits pr primary color */
                    128:             NumColors;          /* number of colors in color table */
                    129: static int  TransparentColorIndex=(-1); /* (added by j.forkosh) */
                    130: static Byte *ColorTable = NULL;
                    131: static Word ScreenHeight,
                    132:             ScreenWidth,
                    133:             ImageHeight,
                    134:             ImageWidth,
                    135:             ImageLeft,
                    136:             ImageTop,
                    137:             RelPixX, RelPixY;   /* used by InputByte() -function */
                    138: static int  (*GetPixel)(int x, int y);
                    139: 
                    140: 
                    141: 
                    142: /**************************************************************************
                    143:  *                                                                        *
                    144:  *                   P R I V A T E    F U N C T I O N S                   *
                    145:  *                                                                        *
                    146:  **************************************************************************/
                    147: 
                    148: /*========================================================================*
                    149:  =                         Routines to do file IO                         =
                    150:  *========================================================================*/
                    151: 
                    152: /*-------------------------------------------------------------------------
                    153:  *
                    154:  *  NAME          Create
                    155:  *
                    156:  *  DESCRIPTION   Creates a new file, and enables referencing using the
                    157:  *                global variable OutFile. This variable is only used
                    158:  *                by these IO-functions, making it relatively simple to
                    159:  *                rewrite file IO.
                    160:  *
                    161:  *  INPUT         filename
1.2     ! albertel  162:  *                        name of file to create,
        !           163:  *                        or NULL for stdout,
        !           164:  *                        or if *filename='\000' then it's the address of
        !           165:  *                           a memory buffer to which gif will be written
1.1       albertel  166:  *
                    167:  *  RETURNS       GIF_OK       - OK
                    168:  *                GIF_ERRWRITE - Error opening the file
                    169:  */
                    170: static int
                    171: Create(const char *filename)
                    172: {
1.2     ! albertel  173:     OutBuffer = NULL;				/* (added by j.forkosh) */
        !           174:     isCloseOutFile = 0;				/* " */
        !           175:     gifSize = 0;				/* " */
        !           176:     if ( filename == NULL )			/* " */
1.1       albertel  177:       {	OutFile = stdout;			/* " */
                    178: 	/*OutFile = fdopen(STDOUT_FILENO,"wb");*/ /* " doesn't work, */
                    179: 	#ifdef WINDOWS				/* "   so instead... */
                    180: 	  #ifdef HAVE_SETMODE			/* "   try to use setmode()*/
                    181: 	    if ( setmode ( fileno (stdout), O_BINARY) /* to  set stdout */
                    182: 	    == -1 ) ; /* handle error */	/* " to binary mode */
                    183: 	  #else					/* " setmode not available */
                    184: 	    #if 1				/* " */
                    185: 	      freopen ("CON", "wb", stdout);	/* " freopen stdout binary */
                    186: 	    #else				/* " */
                    187: 	      stdout = fdopen (STDOUT_FILENO, "wb"); /*fdopen stdout binary*/
                    188: 	    #endif				/* " */
                    189: 	  #endif				/* " */
                    190: 	#endif					/* " */
                    191:       }						/* " */
                    192:     else					/* " */
1.2     ! albertel  193:       if ( *filename != '\000' )		/* " */
        !           194: 	{ if ((OutFile = fopen(filename, "wb")) == NULL)
        !           195: 	    return GIF_ERRCREATE;
        !           196: 	  isCloseOutFile = 1; }			/* (added by j.forkosh) */
        !           197:       else					/* " */
        !           198: 	OutBuffer = (Byte *)filename;		/* " */
1.1       albertel  199:     return GIF_OK;
                    200: }
                    201: 
                    202: 
                    203: 
                    204: /*-------------------------------------------------------------------------
                    205:  *
                    206:  *  NAME          Write
                    207:  *
                    208:  *  DESCRIPTION   Output bytes to the current OutFile.
                    209:  *
                    210:  *  INPUT         buf     pointer to buffer to write
                    211:  *                len     number of bytes to write
                    212:  *
                    213:  *  RETURNS       GIF_OK       - OK
                    214:  *                GIF_ERRWRITE - Error writing to the file
                    215:  */
                    216: static int
                    217: Write(const void *buf, unsigned len)
                    218: {
1.2     ! albertel  219:     if ( OutBuffer == NULL )			/* (added by j.forkosh) */
        !           220:       {	if (fwrite(buf, sizeof(Byte), len, OutFile) < len)
        !           221: 	  return GIF_ERRWRITE; }
        !           222:     else					/* (added by j.forkosh) */
        !           223:       {	if ( gifSize+len <= maxgifSize )	/* " */
        !           224: 	  memcpy(OutBuffer+gifSize,buf,len); }	/* " */
        !           225:     gifSize += len;				/* " */
1.1       albertel  226:     return GIF_OK;
                    227: }
                    228: 
                    229: 
                    230: 
                    231: /*-------------------------------------------------------------------------
                    232:  *
                    233:  *  NAME          WriteByte
                    234:  *
                    235:  *  DESCRIPTION   Output one byte to the current OutFile.
                    236:  *
                    237:  *  INPUT         b       byte to write
                    238:  *
                    239:  *  RETURNS       GIF_OK       - OK
                    240:  *                GIF_ERRWRITE - Error writing to the file
                    241:  */
                    242: static int
                    243: WriteByte(Byte b)
                    244: {
1.2     ! albertel  245:     if ( OutBuffer == NULL )			/* (added by j.forkosh) */
        !           246:       {	if (putc(b, OutFile) == EOF)
        !           247: 	  return GIF_ERRWRITE; }
        !           248:     else					/* (added by j.forkosh) */
        !           249:       {	if ( gifSize < maxgifSize )		/* " */
        !           250: 	  OutBuffer[gifSize] = b; }		/* " */
        !           251:     gifSize++;					/* " */
1.1       albertel  252:     return GIF_OK;
                    253: }
                    254: 
                    255: 
                    256: 
                    257: /*-------------------------------------------------------------------------
                    258:  *
                    259:  *  NAME          WriteWord
                    260:  *
                    261:  *  DESCRIPTION   Output one word (2 bytes with byte-swapping, like on
                    262:  *                the IBM PC) to the current OutFile.
                    263:  *
                    264:  *  INPUT         w       word to write
                    265:  *
                    266:  *  RETURNS       GIF_OK       - OK
                    267:  *                GIF_ERRWRITE - Error writing to the file
                    268:  */
                    269: static int
                    270: WriteWord(Word w)
                    271: {
1.2     ! albertel  272:     if ( OutBuffer == NULL )			/* (added by j.forkosh) */
        !           273:       {	if (putc(w & 0xFF, OutFile) == EOF)
        !           274: 	  return GIF_ERRWRITE;
        !           275: 	if (putc((w >> 8), OutFile) == EOF)
        !           276: 	  return GIF_ERRWRITE; }
        !           277:     else					/* (added by j.forkosh) */
        !           278:       if ( gifSize+1 < maxgifSize )		/* " */
        !           279: 	{ OutBuffer[gifSize] = (Byte)(w & 0xFF);  /* " */
        !           280: 	  OutBuffer[gifSize+1] = (Byte)(w >> 8); }  /* " */
        !           281:     gifSize += 2;				/* " */
1.1       albertel  282:     return GIF_OK;
                    283: }
                    284: 
                    285: 
                    286: 
                    287: /*-------------------------------------------------------------------------
                    288:  *
                    289:  *  NAME          Close
                    290:  *
                    291:  *  DESCRIPTION   Close current OutFile.
                    292:  */
                    293: static void
                    294: Close(void)
                    295: {
                    296:     if ( isCloseOutFile )			/* (added by j.forkosh) */
                    297:       fclose(OutFile);
1.2     ! albertel  298:     OutBuffer = NULL;				/* (added by j.forkosh) */
        !           299:     isCloseOutFile = 0;				/* " */
1.1       albertel  300: }
                    301: 
                    302: 
                    303: 
                    304: 
                    305: 
                    306: /*========================================================================*
                    307:  =                                                                        =
                    308:  =                      Routines to write a bit-file                      =
                    309:  =                                                                        =
                    310:  *========================================================================*/
                    311: 
                    312: /*-------------------------------------------------------------------------
                    313:  *
                    314:  *  NAME          InitBitFile
                    315:  *
                    316:  *  DESCRIPTION   Initiate for using a bitfile. All output is sent to
                    317:  *                  the current OutFile using the I/O-routines above.
                    318:  */
                    319: static void
                    320: InitBitFile(void)
                    321: {
                    322:     Buffer[Index = 0] = 0;
                    323:     BitsLeft = 8;
                    324: }
                    325: 
                    326: 
                    327: 
                    328: /*-------------------------------------------------------------------------
                    329:  *
                    330:  *  NAME          ResetOutBitFile
                    331:  *
                    332:  *  DESCRIPTION   Tidy up after using a bitfile
                    333:  *
                    334:  *  RETURNS       0 - OK, -1 - error
                    335:  */
                    336: static int
                    337: ResetOutBitFile(void)
                    338: {
                    339:     Byte numbytes;
                    340: 
                    341:     /* how much is in the buffer? */
                    342:     numbytes = Index + (BitsLeft == 8 ? 0 : 1);
                    343: 
                    344:     /* write whatever is in the buffer to the file */
                    345:     if (numbytes) {
                    346:         if (WriteByte(numbytes) != GIF_OK)
                    347:             return -1;
                    348: 
                    349:         if (Write(Buffer, numbytes) != GIF_OK)
                    350:             return -1;
                    351: 
                    352:         Buffer[Index = 0] = 0;
                    353:         BitsLeft = 8;
                    354:     }
                    355:     return 0;
                    356: }
                    357: 
                    358: 
                    359: 
                    360: /*-------------------------------------------------------------------------
                    361:  *
                    362:  *  NAME          WriteBits
                    363:  *
                    364:  *  DESCRIPTION   Put the given number of bits to the outfile.
                    365:  *
                    366:  *  INPUT         bits    bits to write from (right justified)
                    367:  *                numbits number of bits to write
                    368:  *
                    369:  *  RETURNS       bits written, or -1 on error.
                    370:  *
                    371:  */
                    372: static int
                    373: WriteBits(int bits, int numbits)
                    374: {
                    375:     int  bitswritten = 0;
                    376:     Byte numbytes = 255;
                    377: 
                    378:     do {
                    379:         /* if the buffer is full, write it */
                    380:         if ((Index == 254 && !BitsLeft) || Index > 254) {
                    381:             if (WriteByte(numbytes) != GIF_OK)
                    382:                 return -1;
                    383: 
                    384:             if (Write(Buffer, numbytes) != GIF_OK)
                    385:                 return -1;
                    386: 
                    387:             Buffer[Index = 0] = 0;
                    388:             BitsLeft = 8;
                    389:         }
                    390: 
                    391:         /* now take care of the two specialcases */
                    392:         if (numbits <= BitsLeft) {
                    393:             Buffer[Index] |= (bits & ((1 << numbits) - 1)) << (8 - BitsLeft);
                    394:             bitswritten += numbits;
                    395:             BitsLeft -= numbits;
                    396:             numbits = 0;
                    397:         } else {
                    398:             Buffer[Index] |= (bits & ((1 << BitsLeft) - 1)) << (8 - BitsLeft);
                    399:             bitswritten += BitsLeft;
                    400:             bits >>= BitsLeft;
                    401:             numbits -= BitsLeft;
                    402: 
                    403:             Buffer[++Index] = 0;
                    404:             BitsLeft = 8;
                    405:         }
                    406:     } while (numbits);
                    407: 
                    408:     return bitswritten;
                    409: }
                    410: 
                    411: 
                    412: 
                    413: /*========================================================================*
                    414:  =                Routines to maintain an LZW-string table                =
                    415:  *========================================================================*/
                    416: 
                    417: /*-------------------------------------------------------------------------
                    418:  *
                    419:  *  NAME          FreeStrtab
                    420:  *
                    421:  *  DESCRIPTION   Free arrays used in string table routines
                    422:  */
                    423: static void
                    424: FreeStrtab(void)
                    425: {
                    426:     if (StrHsh) {
                    427:         free(StrHsh);
                    428:         StrHsh = NULL;
                    429:     }
                    430:     if (StrNxt) {
                    431:         free(StrNxt);
                    432:         StrNxt = NULL;
                    433:     }
                    434:     if (StrChr) {
                    435:         free(StrChr);
                    436:         StrChr = NULL;
                    437:     }
                    438: }
                    439: 
                    440: 
                    441: 
                    442: /*-------------------------------------------------------------------------
                    443:  *
                    444:  *  NAME          AllocStrtab
                    445:  *
                    446:  *  DESCRIPTION   Allocate arrays used in string table routines
                    447:  *
                    448:  *  RETURNS       GIF_OK     - OK
                    449:  *                GIF_OUTMEM - Out of memory
                    450:  */
                    451: static int
                    452: AllocStrtab(void)
                    453: {
                    454:     /* just in case */
                    455:     FreeStrtab();
                    456: 
                    457:     if ((StrChr = (Byte *) malloc(MAXSTR * sizeof(Byte))) == 0) {
                    458:         FreeStrtab();
                    459:         return GIF_OUTMEM;
                    460:     }
                    461:     if ((StrNxt = (Word *) malloc(MAXSTR * sizeof(Word))) == 0) {
                    462:         FreeStrtab();
                    463:         return GIF_OUTMEM;
                    464:     }
                    465:     if ((StrHsh = (Word *) malloc(HASHSIZE * sizeof(Word))) == 0) {
                    466:         FreeStrtab();
                    467:         return GIF_OUTMEM;
                    468:     }
                    469:     return GIF_OK;
                    470: }
                    471: 
                    472: 
                    473: 
                    474: /*-------------------------------------------------------------------------
                    475:  *
                    476:  *  NAME          AddCharString
                    477:  *
                    478:  *  DESCRIPTION   Add a string consisting of the string of index plus
                    479:  *                the byte b.
                    480:  *
                    481:  *                If a string of length 1 is wanted, the index should
                    482:  *                be 0xFFFF.
                    483:  *
                    484:  *  INPUT         index   index to first part of string, or 0xFFFF is
                    485:  *                        only 1 byte is wanted
                    486:  *                b       last byte in new string
                    487:  *
                    488:  *  RETURNS       Index to new string, or 0xFFFF if no more room
                    489:  */
                    490: static Word
                    491: AddCharString(Word index, Byte b)
                    492: {
                    493:     Word hshidx;
                    494: 
                    495:     /* check if there is more room */
                    496:     if (NumStrings >= MAXSTR)
                    497:         return 0xFFFF;
                    498: 
                    499:     /* search the string table until a free position is found */
                    500:     hshidx = HASH(index, b);
                    501:     while (StrHsh[hshidx] != 0xFFFF)
                    502:         hshidx = (hshidx + HASHSTEP) % HASHSIZE;
                    503: 
                    504:     /* insert new string */
                    505:     StrHsh[hshidx] = NumStrings;
                    506:     StrChr[NumStrings] = b;
                    507:     StrNxt[NumStrings] = (index != 0xFFFF) ? index : NEXT_FIRST;
                    508: 
                    509:     return NumStrings++;
                    510: }
                    511: 
                    512: 
                    513: 
                    514: /*-------------------------------------------------------------------------
                    515:  *
                    516:  *  NAME          FindCharString
                    517:  *
                    518:  *  DESCRIPTION   Find index of string consisting of the string of index
                    519:  *                plus the byte b.
                    520:  *
                    521:  *                If a string of length 1 is wanted, the index should
                    522:  *                be 0xFFFF.
                    523:  *
                    524:  *  INPUT         index   index to first part of string, or 0xFFFF is
                    525:  *                        only 1 byte is wanted
                    526:  *                b       last byte in string
                    527:  *
                    528:  *  RETURNS       Index to string, or 0xFFFF if not found
                    529:  */
                    530: static Word
                    531: FindCharString(Word index, Byte b)
                    532: {
                    533:     Word hshidx, nxtidx;
                    534: 
                    535:     /* check if index is 0xFFFF. in that case we need only return b,
                    536:      * since all one-character strings has their bytevalue as their
                    537:      * index */
                    538:     if (index == 0xFFFF)
                    539:         return b;
                    540: 
                    541:     /* search the string table until the string is found, or we find
                    542:      * HASH_FREE. in that case the string does not exist. */
                    543:     hshidx = HASH(index, b);
                    544:     while ((nxtidx = StrHsh[hshidx]) != 0xFFFF) {
                    545:         if (StrNxt[nxtidx] == index && StrChr[nxtidx] == b)
                    546:             return nxtidx;
                    547:         hshidx = (hshidx + HASHSTEP) % HASHSIZE;
                    548:     }
                    549: 
                    550:     /* no match is found */
                    551:     return 0xFFFF;
                    552: }
                    553: 
                    554: 
                    555: 
                    556: /*-------------------------------------------------------------------------
                    557:  *
                    558:  *  NAME          ClearStrtab
                    559:  *
                    560:  *  DESCRIPTION   Mark the entire table as free, enter the 2**codesize
                    561:  *                one-byte strings, and reserve the RES_CODES reserved
                    562:  *                codes.
                    563:  *
                    564:  *  INPUT         codesize
                    565:  *                        number of bits to encode one pixel
                    566:  */
                    567: static void
                    568: ClearStrtab(int codesize)
                    569: {
                    570:     int q, w;
                    571:     Word *wp;
                    572: 
                    573:     /* no strings currently in the table */
                    574:     NumStrings = 0;
                    575: 
                    576:     /* mark entire hashtable as free */
                    577:     wp = StrHsh;
                    578:     for (q = 0; q < HASHSIZE; q++)
                    579:         *wp++ = HASH_FREE;
                    580: 
                    581:     /* insert 2**codesize one-character strings, and reserved codes */
                    582:     w = (1 << codesize) + RES_CODES;
                    583:     for (q = 0; q < w; q++)
                    584:         AddCharString(0xFFFF, q);
                    585: }
                    586: 
                    587: 
                    588: 
                    589: /*========================================================================*
                    590:  =                        LZW compression routine                         =
                    591:  *========================================================================*/
                    592: 
                    593: /*-------------------------------------------------------------------------
                    594:  *
                    595:  *  NAME          LZW_Compress
                    596:  *
                    597:  *  DESCRIPTION   Perform LZW compression as specified in the
                    598:  *                GIF-standard.
                    599:  *
                    600:  *  INPUT         codesize
                    601:  *                         number of bits needed to represent
                    602:  *                         one pixelvalue.
                    603:  *                inputbyte
                    604:  *                         function that fetches each byte to compress.
                    605:  *                         must return -1 when no more bytes.
                    606:  *
                    607:  *  RETURNS       GIF_OK     - OK
                    608:  *                GIF_OUTMEM - Out of memory
                    609:  */
                    610: static int
                    611: LZW_Compress(int codesize, int (*inputbyte)(void))
                    612: {
                    613:     register int c;
                    614:     register Word index;
                    615:     int  clearcode, endofinfo, numbits, limit, errcode;
                    616:     Word prefix = 0xFFFF;
                    617: 
                    618:     /* set up the given outfile */
                    619:     InitBitFile();
                    620: 
                    621:     /* set up variables and tables */
                    622:     clearcode = 1 << codesize;
                    623:     endofinfo = clearcode + 1;
                    624: 
                    625:     numbits = codesize + 1;
                    626:     limit = (1 << numbits) - 1;
                    627: 
                    628:     if ((errcode = AllocStrtab()) != GIF_OK)
                    629:         return errcode;
                    630:     ClearStrtab(codesize);
                    631: 
                    632:     /* first send a code telling the unpacker to clear the stringtable */
                    633:     WriteBits(clearcode, numbits);
                    634: 
                    635:     /* pack image */
                    636:     while ((c = inputbyte()) != -1) {
                    637:         /* now perform the packing. check if the prefix + the new
                    638:          *  character is a string that exists in the table */
                    639:         if ((index = FindCharString(prefix, c)) != 0xFFFF) {
                    640:             /* the string exists in the table. make this string the
                    641:              * new prefix.  */
                    642:             prefix = index;
                    643:         } else {
                    644:             /* the string does not exist in the table. first write
                    645:              * code of the old prefix to the file. */
                    646:             WriteBits(prefix, numbits);
                    647: 
                    648:             /* add the new string (the prefix + the new character) to
                    649:              * the stringtable */
                    650:             if (AddCharString(prefix, c) > limit) {
                    651:                 if (++numbits > 12) {
                    652:                     WriteBits(clearcode, numbits - 1);
                    653:                     ClearStrtab(codesize);
                    654:                     numbits = codesize + 1;
                    655:                 }
                    656:                 limit = (1 << numbits) - 1;
                    657:             }
                    658: 
                    659:             /* set prefix to a string containing only the character
                    660:              * read. since all possible one-character strings exists
                    661:              * int the table, there's no need to check if it is found. */
                    662:             prefix = c;
                    663:         }
                    664:     }
                    665: 
                    666:     /* end of info is reached. write last prefix. */
                    667:     if (prefix != 0xFFFF)
                    668:         WriteBits(prefix, numbits);
                    669: 
                    670:     /* erite end of info -mark, flush the buffer, and tidy up */
                    671:     WriteBits(endofinfo, numbits);
                    672:     ResetOutBitFile();
                    673:     FreeStrtab();
                    674: 
                    675:     return GIF_OK;
                    676: }
                    677: 
                    678: 
                    679: 
                    680: /*========================================================================*
                    681:  =                              Other routines                            =
                    682:  *========================================================================*/
                    683: 
                    684: /*-------------------------------------------------------------------------
                    685:  *
                    686:  *  NAME          BitsNeeded
                    687:  *
                    688:  *  DESCRIPTION   Calculates number of bits needed to store numbers
                    689:  *                between 0 and n - 1
                    690:  *
                    691:  *  INPUT         n       number of numbers to store (0 to n - 1)
                    692:  *
                    693:  *  RETURNS       Number of bits needed
                    694:  */
                    695: static int
                    696: BitsNeeded(Word n)
                    697: {
                    698:     int ret = 1;
                    699: 
                    700:     if (!n--)
                    701:         return 0;
                    702:     while (n >>= 1)
                    703:         ++ret;
                    704:     return ret;
                    705: }
                    706: 
                    707: 
                    708: 
                    709: /*-------------------------------------------------------------------------
                    710:  *
                    711:  *  NAME          InputByte
                    712:  *
                    713:  *  DESCRIPTION   Get next pixel from image. Called by the
                    714:  *                LZW_Compress()-function
                    715:  *
                    716:  *  RETURNS       Next pixelvalue, or -1 if no more pixels
                    717:  */
                    718: static int
                    719: InputByte(void)
                    720: {
                    721:     int ret;
                    722: 
                    723:     if (RelPixY >= ImageHeight)
                    724:         return -1;
                    725:     ret = GetPixel(ImageLeft + RelPixX, ImageTop + RelPixY);
                    726:     if (++RelPixX >= ImageWidth) {
                    727:         RelPixX = 0;
                    728:         ++RelPixY;
                    729:     }
                    730:     return ret;
                    731: }
                    732: 
                    733: 
                    734: 
                    735: /*-------------------------------------------------------------------------
                    736:  *
                    737:  *  NAME          WriteScreenDescriptor
                    738:  *
                    739:  *  DESCRIPTION   Output a screen descriptor to the current GIF-file
                    740:  *
                    741:  *  INPUT         sd      pointer to screen descriptor to output
                    742:  *
                    743:  *  RETURNS       GIF_OK       - OK
                    744:  *                GIF_ERRWRITE - Error writing to the file
                    745:  */
                    746: static int
                    747: WriteScreenDescriptor(ScreenDescriptor *sd)
                    748: {
                    749:     Byte tmp;
                    750: 
                    751:     if (WriteWord(sd->LocalScreenWidth) != GIF_OK)
                    752:         return GIF_ERRWRITE;
                    753:     if (WriteWord(sd->LocalScreenHeight) != GIF_OK)
                    754:         return GIF_ERRWRITE;
                    755:     tmp = (sd->GlobalColorTableFlag << 7)
                    756:           | (sd->ColorResolution << 4)
                    757:           | (sd->SortFlag << 3)
                    758:           | sd->GlobalColorTableSize;
                    759:     if (WriteByte(tmp) != GIF_OK)
                    760:         return GIF_ERRWRITE;
                    761:     if (WriteByte(sd->BackgroundColorIndex) != GIF_OK)
                    762:         return GIF_ERRWRITE;
                    763:     if (WriteByte(sd->PixelAspectRatio) != GIF_OK)
                    764:         return GIF_ERRWRITE;
                    765: 
                    766:     return GIF_OK;
                    767: }
                    768: 
                    769: 
                    770: 
                    771: /*-------------------------------------------------------------------------
                    772:  *
                    773:  *  NAME          WriteTransparentColorIndex (added by j.forkosh)
                    774:  *
                    775:  *  DESCRIPTION   Output a graphic extension block setting transparent
                    776:  *		  colormap index
                    777:  *
                    778:  *  INPUT         colornum       colormap index of color to be transparent
                    779:  *
                    780:  *  RETURNS       GIF_OK       - OK
                    781:  *                GIF_ERRWRITE - Error writing to the file
                    782:  */
                    783: static int
                    784: WriteTransparentColorIndex(int colornum)
                    785: {
                    786:     if ( colornum < 0 ) return GIF_OK;		/*no transparent color set*/
                    787:     if (WriteByte((Byte)(0x21)) != GIF_OK)	/*magic:Extension Introducer*/
                    788:         return GIF_ERRWRITE;
                    789:     if (WriteByte((Byte)(0xf9)) != GIF_OK)     /*magic:Graphic Control Label*/
                    790:         return GIF_ERRWRITE;
                    791:     if (WriteByte((Byte)(4)) != GIF_OK)		/* #bytes in block */
                    792:         return GIF_ERRWRITE;
                    793:     if (WriteByte((Byte)(1)) != GIF_OK)        /*transparent index indicator*/
                    794:         return GIF_ERRWRITE;
                    795:     if (WriteWord((Word)(0)) != GIF_OK)		/* delay time */
                    796:         return GIF_ERRWRITE;
                    797:     if (WriteByte((Byte)(colornum)) != GIF_OK)	/* transparent color index */
                    798:         return GIF_ERRWRITE;
                    799:     if (WriteByte((Byte)(0)) != GIF_OK)        /* terminator */
                    800:         return GIF_ERRWRITE;
                    801: 
                    802:     return GIF_OK;
                    803: }
                    804: 
                    805: 
                    806: 
                    807: /*-------------------------------------------------------------------------
                    808:  *
                    809:  *  NAME          WriteImageDescriptor
                    810:  *
                    811:  *  DESCRIPTION   Output an image descriptor to the current GIF-file
                    812:  *
                    813:  *  INPUT         id      pointer to image descriptor to output
                    814:  *
                    815:  *  RETURNS       GIF_OK       - OK
                    816:  *                GIF_ERRWRITE - Error writing to the file
                    817:  */
                    818: static int
                    819: WriteImageDescriptor(ImageDescriptor *id)
                    820: {
                    821:     Byte tmp;
                    822: 
                    823:     if (WriteByte(id->Separator) != GIF_OK)
                    824:         return GIF_ERRWRITE;
                    825:     if (WriteWord(id->LeftPosition) != GIF_OK)
                    826:         return GIF_ERRWRITE;
                    827:     if (WriteWord(id->TopPosition) != GIF_OK)
                    828:         return GIF_ERRWRITE;
                    829:     if (WriteWord(id->Width) != GIF_OK)
                    830:         return GIF_ERRWRITE;
                    831:     if (WriteWord(id->Height) != GIF_OK)
                    832:         return GIF_ERRWRITE;
                    833:     tmp = (id->LocalColorTableFlag << 7)
                    834:           | (id->InterlaceFlag << 6)
                    835:           | (id->SortFlag << 5)
                    836:           | (id->Reserved << 3)
                    837:           | id->LocalColorTableSize;
                    838:     if (WriteByte(tmp) != GIF_OK)
                    839:         return GIF_ERRWRITE;
                    840: 
                    841:     return GIF_OK;
                    842: }
                    843: 
                    844: 
                    845: 
                    846: /**************************************************************************
                    847:  *                                                                        *
                    848:  *                    P U B L I C    F U N C T I O N S                    *
                    849:  *                                                                        *
                    850:  **************************************************************************/
                    851: 
                    852: /*-------------------------------------------------------------------------
                    853:  *
                    854:  *  NAME          GIF_Create
                    855:  *
                    856:  *  DESCRIPTION   Create a GIF-file, and write headers for both screen
                    857:  *                and image.
                    858:  *
                    859:  *  INPUT         filename
                    860:  *                        name of file to create (including extension)
                    861:  *                width   number of horisontal pixels on screen
                    862:  *                height  number of vertical pixels on screen
                    863:  *                numcolors
                    864:  *                        number of colors in the colormaps
                    865:  *                colorres
                    866:  *                        color resolution. Number of bits for each
                    867:  *                        primary color
                    868:  *
                    869:  *  RETURNS       GIF_OK        - OK
                    870:  *                GIF_ERRCREATE - Couldn't create file
                    871:  *                GIF_ERRWRITE  - Error writing to the file
                    872:  *                GIF_OUTMEM    - Out of memory allocating color table
                    873:  */
                    874: int
                    875: GIF_Create(const char *filename, int width, int height,
                    876: 	   int numcolors, int colorres)
                    877: {
                    878:     int q, tabsize;
                    879:     Byte *bp;
                    880:     ScreenDescriptor SD;
                    881: 
                    882:     /* initiate variables for new GIF-file */
                    883:     NumColors = numcolors ? (1 << BitsNeeded(numcolors)) : 0;
                    884:     BitsPrPrimColor = colorres;
                    885:     ScreenHeight = height;
                    886:     ScreenWidth = width;
                    887: 
                    888:     /* create file specified */
                    889:     if (Create(filename) != GIF_OK)
                    890:         return GIF_ERRCREATE;
                    891: 
                    892:     /* write GIF signature */
                    893:     if ((Write("GIF87a", 6)) != GIF_OK)
                    894:         return GIF_ERRWRITE;
                    895: 
                    896:     /* initiate and write screen descriptor */
                    897:     SD.LocalScreenWidth = width;
                    898:     SD.LocalScreenHeight = height;
                    899:     if (NumColors) {
                    900:         SD.GlobalColorTableSize = BitsNeeded(NumColors) - 1;
                    901:         SD.GlobalColorTableFlag = 1;
                    902:     } else {
                    903:         SD.GlobalColorTableSize = 0;
                    904:         SD.GlobalColorTableFlag = 0;
                    905:     }
                    906:     SD.SortFlag = 0;
                    907:     SD.ColorResolution = colorres - 1;
                    908:     SD.BackgroundColorIndex = 0;
                    909:     SD.PixelAspectRatio = 0;
                    910:     if (WriteScreenDescriptor(&SD) != GIF_OK)
                    911:         return GIF_ERRWRITE;
                    912: 
                    913:     /* allocate color table */
                    914:     if (ColorTable) {
                    915:         free(ColorTable);
                    916:         ColorTable = NULL;
                    917:     }
                    918:     if (NumColors) {
                    919:         tabsize = NumColors * 3;
                    920:         if ((ColorTable = (Byte *) malloc(tabsize * sizeof(Byte))) == NULL)
                    921:             return GIF_OUTMEM;
                    922:         else {
                    923:             bp = ColorTable;
                    924:             for (q = 0; q < tabsize; q++)
                    925:                 *bp++ = 0;
                    926:         }
                    927:     }
                    928:     return 0;
                    929: }
                    930: 
                    931: 
                    932: 
                    933: /*-------------------------------------------------------------------------
                    934:  *
                    935:  *  NAME          GIF_SetColor
                    936:  *
                    937:  *  DESCRIPTION   Set red, green and blue components of one of the
                    938:  *                colors. The color components are all in the range
                    939:  *                [0, (1 << BitsPrPrimColor) - 1]
                    940:  *
                    941:  *  INPUT         colornum
                    942:  *                        color number to set. [0, NumColors - 1]
                    943:  *                red     red component of color
                    944:  *                green   green component of color
                    945:  *                blue    blue component of color
                    946:  */
                    947: void
                    948: GIF_SetColor(int colornum, int red, int green, int blue)
                    949: {
                    950:     long maxcolor;
                    951:     Byte *p;
                    952: 
                    953:     maxcolor = (1L << BitsPrPrimColor) - 1L;
                    954:     p = ColorTable + colornum * 3;
                    955:     *p++ = (Byte) ((red * 255L) / maxcolor);
                    956:     *p++ = (Byte) ((green * 255L) / maxcolor);
                    957:     *p++ = (Byte) ((blue * 255L) / maxcolor);
                    958: }
                    959: 
                    960: 
                    961: 
                    962: /*-------------------------------------------------------------------------
                    963:  *
                    964:  *  NAME          GIF_SetTransparent (added by j.forkosh)
                    965:  *
                    966:  *  DESCRIPTION   Set colormap index of color to be transparent
                    967:  *
                    968:  *  INPUT         colornum
                    969:  *                        color number to set transparent. [0, NumColors - 1]
                    970:  */
                    971: void
                    972: GIF_SetTransparent(int colornum)
                    973: {
                    974:     TransparentColorIndex = colornum;
                    975: }
                    976: 
                    977: 
                    978: 
                    979: /*-------------------------------------------------------------------------
                    980:  *
                    981:  *  NAME          GIF_CompressImage
                    982:  *
                    983:  *  DESCRIPTION   Compress an image into the GIF-file previousely
                    984:  *                created using GIF_Create(). All color values should
                    985:  *                have been specified before this function is called.
                    986:  *
                    987:  *                The pixels are retrieved using a user defined callback
                    988:  *                function. This function should accept two parameters,
                    989:  *                x and y, specifying which pixel to retrieve. The pixel
                    990:  *                values sent to this function are as follows:
                    991:  *
                    992:  *                    x : [ImageLeft, ImageLeft + ImageWidth - 1]
                    993:  *                    y : [ImageTop, ImageTop + ImageHeight - 1]
                    994:  *
                    995:  *                The function should return the pixel value for the
                    996:  *                point given, in the interval [0, NumColors - 1]
                    997:  *
                    998:  *  INPUT         left    screen-relative leftmost pixel x-coordinate
                    999:  *                        of the image
                   1000:  *                top     screen-relative uppermost pixel y-coordinate
                   1001:  *                        of the image
                   1002:  *                width   width of the image, or -1 if as wide as
                   1003:  *                        the screen
                   1004:  *                height  height of the image, or -1 if as high as
                   1005:  *                        the screen
                   1006:  *                getpixel
                   1007:  *                        address of user defined callback function.
                   1008:  *                        (see above)
                   1009:  *
                   1010:  *  RETURNS       GIF_OK       - OK
                   1011:  *                GIF_OUTMEM   - Out of memory
                   1012:  *                GIF_ERRWRITE - Error writing to the file
                   1013:  */
                   1014: int
                   1015: GIF_CompressImage(int left, int top, int width, int height,
                   1016: 		  int (*getpixel)(int x, int y))
                   1017: {
                   1018:     int codesize, errcode;
                   1019:     ImageDescriptor ID;
                   1020: 
                   1021:     if (width < 0) {
                   1022:         width = ScreenWidth;
                   1023:         left = 0;
                   1024:     }
                   1025:     if (height < 0) {
                   1026:         height = ScreenHeight;
                   1027:         top = 0;
                   1028:     }
                   1029:     if (left < 0)
                   1030:         left = 0;
                   1031:     if (top < 0)
                   1032:         top = 0;
                   1033: 
                   1034:     /* write global colortable if any */
                   1035:     if (NumColors)
                   1036:         if ((Write(ColorTable, NumColors * 3)) != GIF_OK)
                   1037:             return GIF_ERRWRITE;
                   1038: 
                   1039:     /* write graphic extension block with transparent color index */
                   1040:     if ( TransparentColorIndex >= 0 )     /* (added by j.forkosh) */
                   1041:       if ( WriteTransparentColorIndex(TransparentColorIndex)
                   1042:       !=   GIF_OK ) return GIF_ERRWRITE;
                   1043: 
                   1044:     /* initiate and write image descriptor */
                   1045:     ID.Separator = ',';
                   1046:     ID.LeftPosition = ImageLeft = left;
                   1047:     ID.TopPosition = ImageTop = top;
                   1048:     ID.Width = ImageWidth = width;
                   1049:     ID.Height = ImageHeight = height;
                   1050:     ID.LocalColorTableSize = 0;
                   1051:     ID.Reserved = 0;
                   1052:     ID.SortFlag = 0;
                   1053:     ID.InterlaceFlag = 0;
                   1054:     ID.LocalColorTableFlag = 0;
                   1055: 
                   1056:     if (WriteImageDescriptor(&ID) != GIF_OK)
                   1057:         return GIF_ERRWRITE;
                   1058: 
                   1059:     /* write code size */
                   1060:     codesize = BitsNeeded(NumColors);
                   1061:     if (codesize == 1)
                   1062:         ++codesize;
                   1063:     if (WriteByte(codesize) != GIF_OK)
                   1064:         return GIF_ERRWRITE;
                   1065: 
                   1066:     /* perform compression */
                   1067:     RelPixX = RelPixY = 0;
                   1068:     GetPixel = getpixel;
                   1069:     if ((errcode = LZW_Compress(codesize, InputByte)) != GIF_OK)
                   1070:         return errcode;
                   1071: 
                   1072:     /* write terminating 0-byte */
                   1073:     if (WriteByte(0) != GIF_OK)
                   1074:         return GIF_ERRWRITE;
                   1075: 
                   1076:     return GIF_OK;
                   1077: }
                   1078: 
                   1079: 
                   1080: 
                   1081: /*-------------------------------------------------------------------------
                   1082:  *
                   1083:  *  NAME          GIF_Close
                   1084:  *
                   1085:  *  DESCRIPTION   Close the GIF-file
                   1086:  *
                   1087:  *  RETURNS       GIF_OK       - OK
                   1088:  *                GIF_ERRWRITE - Error writing to file
                   1089:  */
                   1090: int
                   1091: GIF_Close(void)
                   1092: {
                   1093:     ImageDescriptor ID;
                   1094: 
                   1095:     /* initiate and write ending image descriptor */
                   1096:     ID.Separator = ';';
                   1097:     ID.LeftPosition = 0;	/* (added by j.forkosh) */
                   1098:     ID.TopPosition = 0;		/* " initialize entire ID structure */
                   1099:     ID.Width = 0;		/* " and ditto for other ID.x=0; below */
                   1100:     ID.Height = 0;
                   1101:     ID.LocalColorTableSize = 0;
                   1102:     ID.Reserved = 0;
                   1103:     ID.SortFlag = 0;
                   1104:     ID.InterlaceFlag = 0;
                   1105:     ID.LocalColorTableFlag = 0;
                   1106: 
                   1107:     if (WriteImageDescriptor(&ID) != GIF_OK)
                   1108:         return GIF_ERRWRITE;
                   1109: 
                   1110:     /* close file */
                   1111:     Close();
                   1112: 
                   1113:     /* release color table */
                   1114:     if (ColorTable) {
                   1115:         free(ColorTable);
                   1116:         ColorTable = NULL;
                   1117:     }
                   1118: 
                   1119:     return GIF_OK;
                   1120: }
                   1121: /* --- end-of-file gifsave.c --- */

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>