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

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

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