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

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

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