File:  [LON-CAPA] / loncom / cgi / mimeTeX / gifsave.c
Revision 1.3: download - view: text, annotated - select for diffs
Tue Oct 9 21:41:41 2007 UTC (16 years, 8 months ago) by albertel
Branches: MAIN
CVS tags: version_2_7_X, version_2_7_1, version_2_7_0, version_2_6_X, version_2_6_99_1, version_2_6_99_0, version_2_6_3, version_2_6_2, version_2_6_1, version_2_6_0, version_2_5_99_1, version_2_5_99_0, HEAD
- latest revison of mimetex

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

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