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

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

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