diff options
Diffstat (limited to 'support/mimetex/gifsave.c')
-rw-r--r-- | support/mimetex/gifsave.c | 1129 |
1 files changed, 1129 insertions, 0 deletions
diff --git a/support/mimetex/gifsave.c b/support/mimetex/gifsave.c new file mode 100644 index 0000000000..a0727c9375 --- /dev/null +++ b/support/mimetex/gifsave.c @@ -0,0 +1,1129 @@ +/* $Id: gifsave.c,v 1.2 1998/07/05 16:29:56 sverrehu Exp $ */ +/************************************************************************** + * + * FILE gifsave.c + * + * DESCRIPTION Routines to create a GIF-file. See README for + * a description. + * + * The functions were originally written using Borland's + * C-compiler on an IBM PC -compatible computer, but they + * are compiled and tested on Linux and SunOS as well. + * + * WRITTEN BY Sverre H. Huseby <sverrehu@online.no> + * + **************************************************************************/ + +#include <stdlib.h> +#include <stdio.h> +/* #include <unistd.h> */ /* (added by j.forkosh) to get STDOUT_FILENO*/ +#include <string.h> /* " */ +/* --- windows-specific header info --- */ +#ifndef WINDOWS /* -DWINDOWS not supplied by user */ + #if defined(_WINDOWS) || defined(_WIN32) || defined(WIN32) \ + || defined(DJGPP) /* try to recognize windows compilers */ \ + || defined(_USRDLL) /* must be WINDOWS if compiling for DLL */ + #define WINDOWS /* signal windows */ + #endif +#endif +#ifdef WINDOWS /* " if filename=NULL passed to GIF_Create()*/ + #include <fcntl.h> /* " OutFile=stdout used. But Windows opens*/ + #include <io.h> /* " stdout in char mode, and precedes every*/ + /* " 0x0A with spurious 0x0D. */ + #if defined(_O_BINARY) && !defined(O_BINARY) /* only have _O_BINARY */ + #define O_BINARY _O_BINARY /* make O_BINARY available, etc... */ + #define setmode _setmode + #define fileno _fileno + #endif + #if defined(_O_BINARY) || defined(O_BINARY) /* setmode() now available */ + #define HAVE_SETMODE /* so we'll use setmode() */ + #endif +#endif + +/* #include "gifsave.h" */ /* (j.forkosh) explcitly include header */ +enum GIF_Code { + GIF_OK = 0, + GIF_ERRCREATE, + GIF_ERRWRITE, + GIF_OUTMEM +}; + +int GIF_Create(const char *filename, int width, int height, + int numcolors, int colorres); +void GIF_SetColor(int colornum, int red, int green, int blue); +void GIF_SetTransparent(int colornum); /* (added by j.forkosh) */ +int GIF_CompressImage(int left, int top, int width, int height, + int (*getpixel)(int x, int y)); +int GIF_Close(void); +/* --- end-of-header gifsave.h --- */ + + +/************************************************************************** + * * + * P R I V A T E D A T A * + * * + **************************************************************************/ + +typedef unsigned Word; /* at least two bytes (16 bits) */ +typedef unsigned char Byte; /* exactly one byte (8 bits) */ + +/* used by IO-routines */ +static FILE *OutFile = NULL; /* file to write to */ +static Byte *OutBuffer = NULL; /* (added by j.forkosh) */ +static int isCloseOutFile = 0; /* " */ +#if !defined(MAXGIFSZ) /* " */ + #define MAXGIFSZ 131072 /* " max #bytes comprising gif image */ +#endif /* " */ +int gifSize = 0; /* " #bytes comprising gif */ +int maxgifSize = MAXGIFSZ; /* " max #bytes written to OutBuffer */ +extern int iscachecontenttype; /* " true to cache mime content-type */ +extern char contenttype[2048]; /* " content-type:, etc. buffer */ + +/* used when writing to a file bitwise */ +static Byte Buffer[256]; /* there must be one more than `needed' */ +static int Index, /* current byte in buffer */ + BitsLeft; /* bits left to fill in current byte. These + * are right-justified */ + +/* used by routines maintaining an LZW string table */ +#define RES_CODES 2 + +#define HASH_FREE 0xFFFF +#define NEXT_FIRST 0xFFFF + +#define MAXBITS 12 +#define MAXSTR (1 << MAXBITS) + +#define HASHSIZE 9973 +#define HASHSTEP 2039 + +#define HASH(index, lastbyte) (((lastbyte << 8) ^ index) % HASHSIZE) + +static Byte *StrChr = NULL; +static Word *StrNxt = NULL, + *StrHsh = NULL, + NumStrings; + +/* used in the main routines */ +typedef struct { + Word LocalScreenWidth, + LocalScreenHeight; + Byte GlobalColorTableSize : 3, + SortFlag : 1, + ColorResolution : 3, + GlobalColorTableFlag : 1; + Byte BackgroundColorIndex; + Byte PixelAspectRatio; +} ScreenDescriptor; + +typedef struct { + Byte Separator; + Word LeftPosition, + TopPosition; + Word Width, + Height; + Byte LocalColorTableSize : 3, + Reserved : 2, + SortFlag : 1, + InterlaceFlag : 1, + LocalColorTableFlag : 1; +} ImageDescriptor; + +static int BitsPrPrimColor, /* bits pr primary color */ + NumColors; /* number of colors in color table */ +static int TransparentColorIndex=(-1); /* (added by j.forkosh) */ +static Byte *ColorTable = NULL; +static Word ScreenHeight, + ScreenWidth, + ImageHeight, + ImageWidth, + ImageLeft, + ImageTop, + RelPixX, RelPixY; /* used by InputByte() -function */ +static int (*GetPixel)(int x, int y); + + + +/************************************************************************** + * * + * P R I V A T E F U N C T I O N S * + * * + **************************************************************************/ + +/*========================================================================* + = Routines to do file IO = + *========================================================================*/ + +/*------------------------------------------------------------------------- + * + * NAME Create + * + * DESCRIPTION Creates a new file, and enables referencing using the + * global variable OutFile. This variable is only used + * by these IO-functions, making it relatively simple to + * rewrite file IO. + * + * INPUT filename + * name of file to create, + * or NULL for stdout, + * or if *filename='\000' then it's the address of + * a memory buffer to which gif will be written + * + * RETURNS GIF_OK - OK + * GIF_ERRWRITE - Error opening the file + */ +static int +Create(const char *filename) +{ + OutBuffer = NULL; /* (added by j.forkosh) */ + isCloseOutFile = 0; /* " */ + gifSize = 0; /* " */ + if ( filename == NULL ) /* " */ + { OutFile = stdout; /* " */ + /*OutFile = fdopen(STDOUT_FILENO,"wb");*/ /* " doesn't work, */ + #ifdef WINDOWS /* " so instead... */ + #ifdef HAVE_SETMODE /* " try to use setmode()*/ + if ( setmode ( fileno (stdout), O_BINARY) /* to set stdout */ + == -1 ) ; /* handle error */ /* " to binary mode */ + #else /* " setmode not available */ + #if 1 /* " */ + freopen ("CON", "wb", stdout); /* " freopen stdout binary */ + #else /* " */ + stdout = fdopen (STDOUT_FILENO, "wb"); /*fdopen stdout binary*/ + #endif /* " */ + #endif /* " */ + #endif /* " */ + } /* " */ + else /* " */ + if ( *filename != '\000' ) /* " */ + { if ((OutFile = fopen(filename, "wb")) == NULL) + return GIF_ERRCREATE; + isCloseOutFile = 1; /* (added by j.forkosh) */ + if ( iscachecontenttype ) /* " cache headers in file */ + if ( *contenttype != '\000' ) /* " have headers in buffer*/ + fputs(contenttype,OutFile); } /* " write buffered headers*/ + else /* " */ + OutBuffer = (Byte *)filename; /* " */ + return GIF_OK; +} + + + +/*------------------------------------------------------------------------- + * + * NAME Write + * + * DESCRIPTION Output bytes to the current OutFile. + * + * INPUT buf pointer to buffer to write + * len number of bytes to write + * + * RETURNS GIF_OK - OK + * GIF_ERRWRITE - Error writing to the file + */ +static int +Write(const void *buf, unsigned len) +{ + if ( OutBuffer == NULL ) /* (added by j.forkosh) */ + { if (fwrite(buf, sizeof(Byte), len, OutFile) < len) + return GIF_ERRWRITE; } + else /* (added by j.forkosh) */ + { if ( gifSize+len <= maxgifSize ) /* " */ + memcpy(OutBuffer+gifSize,buf,len); } /* " */ + gifSize += len; /* " */ + return GIF_OK; +} + + + +/*------------------------------------------------------------------------- + * + * NAME WriteByte + * + * DESCRIPTION Output one byte to the current OutFile. + * + * INPUT b byte to write + * + * RETURNS GIF_OK - OK + * GIF_ERRWRITE - Error writing to the file + */ +static int +WriteByte(Byte b) +{ + if ( OutBuffer == NULL ) /* (added by j.forkosh) */ + { if (putc(b, OutFile) == EOF) + return GIF_ERRWRITE; } + else /* (added by j.forkosh) */ + { if ( gifSize < maxgifSize ) /* " */ + OutBuffer[gifSize] = b; } /* " */ + gifSize++; /* " */ + return GIF_OK; +} + + + +/*------------------------------------------------------------------------- + * + * NAME WriteWord + * + * DESCRIPTION Output one word (2 bytes with byte-swapping, like on + * the IBM PC) to the current OutFile. + * + * INPUT w word to write + * + * RETURNS GIF_OK - OK + * GIF_ERRWRITE - Error writing to the file + */ +static int +WriteWord(Word w) +{ + if ( OutBuffer == NULL ) /* (added by j.forkosh) */ + { if (putc(w & 0xFF, OutFile) == EOF) + return GIF_ERRWRITE; + if (putc((w >> 8), OutFile) == EOF) + return GIF_ERRWRITE; } + else /* (added by j.forkosh) */ + if ( gifSize+1 < maxgifSize ) /* " */ + { OutBuffer[gifSize] = (Byte)(w & 0xFF); /* " */ + OutBuffer[gifSize+1] = (Byte)(w >> 8); } /* " */ + gifSize += 2; /* " */ + return GIF_OK; +} + + + +/*------------------------------------------------------------------------- + * + * NAME Close + * + * DESCRIPTION Close current OutFile. + */ +static void +Close(void) +{ + if ( isCloseOutFile ) /* (added by j.forkosh) */ + fclose(OutFile); + OutBuffer = NULL; /* (added by j.forkosh) */ + isCloseOutFile = 0; /* " */ +} + + + + + +/*========================================================================* + = = + = Routines to write a bit-file = + = = + *========================================================================*/ + +/*------------------------------------------------------------------------- + * + * NAME InitBitFile + * + * DESCRIPTION Initiate for using a bitfile. All output is sent to + * the current OutFile using the I/O-routines above. + */ +static void +InitBitFile(void) +{ + Buffer[Index = 0] = 0; + BitsLeft = 8; +} + + + +/*------------------------------------------------------------------------- + * + * NAME ResetOutBitFile + * + * DESCRIPTION Tidy up after using a bitfile + * + * RETURNS 0 - OK, -1 - error + */ +static int +ResetOutBitFile(void) +{ + Byte numbytes; + + /* how much is in the buffer? */ + numbytes = Index + (BitsLeft == 8 ? 0 : 1); + + /* write whatever is in the buffer to the file */ + if (numbytes) { + if (WriteByte(numbytes) != GIF_OK) + return -1; + + if (Write(Buffer, numbytes) != GIF_OK) + return -1; + + Buffer[Index = 0] = 0; + BitsLeft = 8; + } + return 0; +} + + + +/*------------------------------------------------------------------------- + * + * NAME WriteBits + * + * DESCRIPTION Put the given number of bits to the outfile. + * + * INPUT bits bits to write from (right justified) + * numbits number of bits to write + * + * RETURNS bits written, or -1 on error. + * + */ +static int +WriteBits(int bits, int numbits) +{ + int bitswritten = 0; + Byte numbytes = 255; + + do { + /* if the buffer is full, write it */ + if ((Index == 254 && !BitsLeft) || Index > 254) { + if (WriteByte(numbytes) != GIF_OK) + return -1; + + if (Write(Buffer, numbytes) != GIF_OK) + return -1; + + Buffer[Index = 0] = 0; + BitsLeft = 8; + } + + /* now take care of the two specialcases */ + if (numbits <= BitsLeft) { + Buffer[Index] |= (bits & ((1 << numbits) - 1)) << (8 - BitsLeft); + bitswritten += numbits; + BitsLeft -= numbits; + numbits = 0; + } else { + Buffer[Index] |= (bits & ((1 << BitsLeft) - 1)) << (8 - BitsLeft); + bitswritten += BitsLeft; + bits >>= BitsLeft; + numbits -= BitsLeft; + + Buffer[++Index] = 0; + BitsLeft = 8; + } + } while (numbits); + + return bitswritten; +} + + + +/*========================================================================* + = Routines to maintain an LZW-string table = + *========================================================================*/ + +/*------------------------------------------------------------------------- + * + * NAME FreeStrtab + * + * DESCRIPTION Free arrays used in string table routines + */ +static void +FreeStrtab(void) +{ + if (StrHsh) { + free(StrHsh); + StrHsh = NULL; + } + if (StrNxt) { + free(StrNxt); + StrNxt = NULL; + } + if (StrChr) { + free(StrChr); + StrChr = NULL; + } +} + + + +/*------------------------------------------------------------------------- + * + * NAME AllocStrtab + * + * DESCRIPTION Allocate arrays used in string table routines + * + * RETURNS GIF_OK - OK + * GIF_OUTMEM - Out of memory + */ +static int +AllocStrtab(void) +{ + /* just in case */ + FreeStrtab(); + + if ((StrChr = (Byte *) malloc(MAXSTR * sizeof(Byte))) == 0) { + FreeStrtab(); + return GIF_OUTMEM; + } + if ((StrNxt = (Word *) malloc(MAXSTR * sizeof(Word))) == 0) { + FreeStrtab(); + return GIF_OUTMEM; + } + if ((StrHsh = (Word *) malloc(HASHSIZE * sizeof(Word))) == 0) { + FreeStrtab(); + return GIF_OUTMEM; + } + return GIF_OK; +} + + + +/*------------------------------------------------------------------------- + * + * NAME AddCharString + * + * DESCRIPTION Add a string consisting of the string of index plus + * the byte b. + * + * If a string of length 1 is wanted, the index should + * be 0xFFFF. + * + * INPUT index index to first part of string, or 0xFFFF is + * only 1 byte is wanted + * b last byte in new string + * + * RETURNS Index to new string, or 0xFFFF if no more room + */ +static Word +AddCharString(Word index, Byte b) +{ + Word hshidx; + + /* check if there is more room */ + if (NumStrings >= MAXSTR) + return 0xFFFF; + + /* search the string table until a free position is found */ + hshidx = HASH(index, b); + while (StrHsh[hshidx] != 0xFFFF) + hshidx = (hshidx + HASHSTEP) % HASHSIZE; + + /* insert new string */ + StrHsh[hshidx] = NumStrings; + StrChr[NumStrings] = b; + StrNxt[NumStrings] = (index != 0xFFFF) ? index : NEXT_FIRST; + + return NumStrings++; +} + + + +/*------------------------------------------------------------------------- + * + * NAME FindCharString + * + * DESCRIPTION Find index of string consisting of the string of index + * plus the byte b. + * + * If a string of length 1 is wanted, the index should + * be 0xFFFF. + * + * INPUT index index to first part of string, or 0xFFFF is + * only 1 byte is wanted + * b last byte in string + * + * RETURNS Index to string, or 0xFFFF if not found + */ +static Word +FindCharString(Word index, Byte b) +{ + Word hshidx, nxtidx; + + /* check if index is 0xFFFF. in that case we need only return b, + * since all one-character strings has their bytevalue as their + * index */ + if (index == 0xFFFF) + return b; + + /* search the string table until the string is found, or we find + * HASH_FREE. in that case the string does not exist. */ + hshidx = HASH(index, b); + while ((nxtidx = StrHsh[hshidx]) != 0xFFFF) { + if (StrNxt[nxtidx] == index && StrChr[nxtidx] == b) + return nxtidx; + hshidx = (hshidx + HASHSTEP) % HASHSIZE; + } + + /* no match is found */ + return 0xFFFF; +} + + + +/*------------------------------------------------------------------------- + * + * NAME ClearStrtab + * + * DESCRIPTION Mark the entire table as free, enter the 2**codesize + * one-byte strings, and reserve the RES_CODES reserved + * codes. + * + * INPUT codesize + * number of bits to encode one pixel + */ +static void +ClearStrtab(int codesize) +{ + int q, w; + Word *wp; + + /* no strings currently in the table */ + NumStrings = 0; + + /* mark entire hashtable as free */ + wp = StrHsh; + for (q = 0; q < HASHSIZE; q++) + *wp++ = HASH_FREE; + + /* insert 2**codesize one-character strings, and reserved codes */ + w = (1 << codesize) + RES_CODES; + for (q = 0; q < w; q++) + AddCharString(0xFFFF, q); +} + + + +/*========================================================================* + = LZW compression routine = + *========================================================================*/ + +/*------------------------------------------------------------------------- + * + * NAME LZW_Compress + * + * DESCRIPTION Perform LZW compression as specified in the + * GIF-standard. + * + * INPUT codesize + * number of bits needed to represent + * one pixelvalue. + * inputbyte + * function that fetches each byte to compress. + * must return -1 when no more bytes. + * + * RETURNS GIF_OK - OK + * GIF_OUTMEM - Out of memory + */ +static int +LZW_Compress(int codesize, int (*inputbyte)(void)) +{ + register int c; + register Word index; + int clearcode, endofinfo, numbits, limit, errcode; + Word prefix = 0xFFFF; + + /* set up the given outfile */ + InitBitFile(); + + /* set up variables and tables */ + clearcode = 1 << codesize; + endofinfo = clearcode + 1; + + numbits = codesize + 1; + limit = (1 << numbits) - 1; + + if ((errcode = AllocStrtab()) != GIF_OK) + return errcode; + ClearStrtab(codesize); + + /* first send a code telling the unpacker to clear the stringtable */ + WriteBits(clearcode, numbits); + + /* pack image */ + while ((c = inputbyte()) != -1) { + /* now perform the packing. check if the prefix + the new + * character is a string that exists in the table */ + if ((index = FindCharString(prefix, c)) != 0xFFFF) { + /* the string exists in the table. make this string the + * new prefix. */ + prefix = index; + } else { + /* the string does not exist in the table. first write + * code of the old prefix to the file. */ + WriteBits(prefix, numbits); + + /* add the new string (the prefix + the new character) to + * the stringtable */ + if (AddCharString(prefix, c) > limit) { + if (++numbits > 12) { + WriteBits(clearcode, numbits - 1); + ClearStrtab(codesize); + numbits = codesize + 1; + } + limit = (1 << numbits) - 1; + } + + /* set prefix to a string containing only the character + * read. since all possible one-character strings exists + * int the table, there's no need to check if it is found. */ + prefix = c; + } + } + + /* end of info is reached. write last prefix. */ + if (prefix != 0xFFFF) + WriteBits(prefix, numbits); + + /* erite end of info -mark, flush the buffer, and tidy up */ + WriteBits(endofinfo, numbits); + ResetOutBitFile(); + FreeStrtab(); + + return GIF_OK; +} + + + +/*========================================================================* + = Other routines = + *========================================================================*/ + +/*------------------------------------------------------------------------- + * + * NAME BitsNeeded + * + * DESCRIPTION Calculates number of bits needed to store numbers + * between 0 and n - 1 + * + * INPUT n number of numbers to store (0 to n - 1) + * + * RETURNS Number of bits needed + */ +static int +BitsNeeded(Word n) +{ + int ret = 1; + + if (!n--) + return 0; + while (n >>= 1) + ++ret; + return ret; +} + + + +/*------------------------------------------------------------------------- + * + * NAME InputByte + * + * DESCRIPTION Get next pixel from image. Called by the + * LZW_Compress()-function + * + * RETURNS Next pixelvalue, or -1 if no more pixels + */ +static int +InputByte(void) +{ + int ret; + + if (RelPixY >= ImageHeight) + return -1; + ret = GetPixel(ImageLeft + RelPixX, ImageTop + RelPixY); + if (++RelPixX >= ImageWidth) { + RelPixX = 0; + ++RelPixY; + } + return ret; +} + + + +/*------------------------------------------------------------------------- + * + * NAME WriteScreenDescriptor + * + * DESCRIPTION Output a screen descriptor to the current GIF-file + * + * INPUT sd pointer to screen descriptor to output + * + * RETURNS GIF_OK - OK + * GIF_ERRWRITE - Error writing to the file + */ +static int +WriteScreenDescriptor(ScreenDescriptor *sd) +{ + Byte tmp; + + if (WriteWord(sd->LocalScreenWidth) != GIF_OK) + return GIF_ERRWRITE; + if (WriteWord(sd->LocalScreenHeight) != GIF_OK) + return GIF_ERRWRITE; + tmp = (sd->GlobalColorTableFlag << 7) + | (sd->ColorResolution << 4) + | (sd->SortFlag << 3) + | sd->GlobalColorTableSize; + if (WriteByte(tmp) != GIF_OK) + return GIF_ERRWRITE; + if (WriteByte(sd->BackgroundColorIndex) != GIF_OK) + return GIF_ERRWRITE; + if (WriteByte(sd->PixelAspectRatio) != GIF_OK) + return GIF_ERRWRITE; + + return GIF_OK; +} + + + +/*------------------------------------------------------------------------- + * + * NAME WriteTransparentColorIndex (added by j.forkosh) + * + * DESCRIPTION Output a graphic extension block setting transparent + * colormap index + * + * INPUT colornum colormap index of color to be transparent + * + * RETURNS GIF_OK - OK + * GIF_ERRWRITE - Error writing to the file + */ +static int +WriteTransparentColorIndex(int colornum) +{ + if ( colornum < 0 ) return GIF_OK; /*no transparent color set*/ + if (WriteByte((Byte)(0x21)) != GIF_OK) /*magic:Extension Introducer*/ + return GIF_ERRWRITE; + if (WriteByte((Byte)(0xf9)) != GIF_OK) /*magic:Graphic Control Label*/ + return GIF_ERRWRITE; + if (WriteByte((Byte)(4)) != GIF_OK) /* #bytes in block */ + return GIF_ERRWRITE; + if (WriteByte((Byte)(1)) != GIF_OK) /*transparent index indicator*/ + return GIF_ERRWRITE; + if (WriteWord((Word)(0)) != GIF_OK) /* delay time */ + return GIF_ERRWRITE; + if (WriteByte((Byte)(colornum)) != GIF_OK) /* transparent color index */ + return GIF_ERRWRITE; + if (WriteByte((Byte)(0)) != GIF_OK) /* terminator */ + return GIF_ERRWRITE; + + return GIF_OK; +} + + + +/*------------------------------------------------------------------------- + * + * NAME WriteImageDescriptor + * + * DESCRIPTION Output an image descriptor to the current GIF-file + * + * INPUT id pointer to image descriptor to output + * + * RETURNS GIF_OK - OK + * GIF_ERRWRITE - Error writing to the file + */ +static int +WriteImageDescriptor(ImageDescriptor *id) +{ + Byte tmp; + + if (WriteByte(id->Separator) != GIF_OK) + return GIF_ERRWRITE; + if (WriteWord(id->LeftPosition) != GIF_OK) + return GIF_ERRWRITE; + if (WriteWord(id->TopPosition) != GIF_OK) + return GIF_ERRWRITE; + if (WriteWord(id->Width) != GIF_OK) + return GIF_ERRWRITE; + if (WriteWord(id->Height) != GIF_OK) + return GIF_ERRWRITE; + tmp = (id->LocalColorTableFlag << 7) + | (id->InterlaceFlag << 6) + | (id->SortFlag << 5) + | (id->Reserved << 3) + | id->LocalColorTableSize; + if (WriteByte(tmp) != GIF_OK) + return GIF_ERRWRITE; + + return GIF_OK; +} + + + +/************************************************************************** + * * + * P U B L I C F U N C T I O N S * + * * + **************************************************************************/ + +/*------------------------------------------------------------------------- + * + * NAME GIF_Create + * + * DESCRIPTION Create a GIF-file, and write headers for both screen + * and image. + * + * INPUT filename + * name of file to create (including extension) + * width number of horisontal pixels on screen + * height number of vertical pixels on screen + * numcolors + * number of colors in the colormaps + * colorres + * color resolution. Number of bits for each + * primary color + * + * RETURNS GIF_OK - OK + * GIF_ERRCREATE - Couldn't create file + * GIF_ERRWRITE - Error writing to the file + * GIF_OUTMEM - Out of memory allocating color table + */ +int +GIF_Create(const char *filename, int width, int height, + int numcolors, int colorres) +{ + int q, tabsize; + Byte *bp; + ScreenDescriptor SD; + + /* initiate variables for new GIF-file */ + NumColors = numcolors ? (1 << BitsNeeded(numcolors)) : 0; + BitsPrPrimColor = colorres; + ScreenHeight = height; + ScreenWidth = width; + + /* create file specified */ + if (Create(filename) != GIF_OK) + return GIF_ERRCREATE; + + /* write GIF signature */ + if ((Write("GIF87a", 6)) != GIF_OK) + return GIF_ERRWRITE; + + /* initiate and write screen descriptor */ + SD.LocalScreenWidth = width; + SD.LocalScreenHeight = height; + if (NumColors) { + SD.GlobalColorTableSize = BitsNeeded(NumColors) - 1; + SD.GlobalColorTableFlag = 1; + } else { + SD.GlobalColorTableSize = 0; + SD.GlobalColorTableFlag = 0; + } + SD.SortFlag = 0; + SD.ColorResolution = colorres - 1; + SD.BackgroundColorIndex = 0; + SD.PixelAspectRatio = 0; + if (WriteScreenDescriptor(&SD) != GIF_OK) + return GIF_ERRWRITE; + + /* allocate color table */ + if (ColorTable) { + free(ColorTable); + ColorTable = NULL; + } + if (NumColors) { + tabsize = NumColors * 3; + if ((ColorTable = (Byte *) malloc(tabsize * sizeof(Byte))) == NULL) + return GIF_OUTMEM; + else { + bp = ColorTable; + for (q = 0; q < tabsize; q++) + *bp++ = 0; + } + } + return 0; +} + + + +/*------------------------------------------------------------------------- + * + * NAME GIF_SetColor + * + * DESCRIPTION Set red, green and blue components of one of the + * colors. The color components are all in the range + * [0, (1 << BitsPrPrimColor) - 1] + * + * INPUT colornum + * color number to set. [0, NumColors - 1] + * red red component of color + * green green component of color + * blue blue component of color + */ +void +GIF_SetColor(int colornum, int red, int green, int blue) +{ + long maxcolor; + Byte *p; + + maxcolor = (1L << BitsPrPrimColor) - 1L; + p = ColorTable + colornum * 3; + *p++ = (Byte) ((red * 255L) / maxcolor); + *p++ = (Byte) ((green * 255L) / maxcolor); + *p++ = (Byte) ((blue * 255L) / maxcolor); +} + + + +/*------------------------------------------------------------------------- + * + * NAME GIF_SetTransparent (added by j.forkosh) + * + * DESCRIPTION Set colormap index of color to be transparent + * + * INPUT colornum + * color number to set transparent. [0, NumColors - 1] + */ +void +GIF_SetTransparent(int colornum) +{ + TransparentColorIndex = colornum; +} + + + +/*------------------------------------------------------------------------- + * + * NAME GIF_CompressImage + * + * DESCRIPTION Compress an image into the GIF-file previousely + * created using GIF_Create(). All color values should + * have been specified before this function is called. + * + * The pixels are retrieved using a user defined callback + * function. This function should accept two parameters, + * x and y, specifying which pixel to retrieve. The pixel + * values sent to this function are as follows: + * + * x : [ImageLeft, ImageLeft + ImageWidth - 1] + * y : [ImageTop, ImageTop + ImageHeight - 1] + * + * The function should return the pixel value for the + * point given, in the interval [0, NumColors - 1] + * + * INPUT left screen-relative leftmost pixel x-coordinate + * of the image + * top screen-relative uppermost pixel y-coordinate + * of the image + * width width of the image, or -1 if as wide as + * the screen + * height height of the image, or -1 if as high as + * the screen + * getpixel + * address of user defined callback function. + * (see above) + * + * RETURNS GIF_OK - OK + * GIF_OUTMEM - Out of memory + * GIF_ERRWRITE - Error writing to the file + */ +int +GIF_CompressImage(int left, int top, int width, int height, + int (*getpixel)(int x, int y)) +{ + int codesize, errcode; + ImageDescriptor ID; + + if (width < 0) { + width = ScreenWidth; + left = 0; + } + if (height < 0) { + height = ScreenHeight; + top = 0; + } + if (left < 0) + left = 0; + if (top < 0) + top = 0; + + /* write global colortable if any */ + if (NumColors) + if ((Write(ColorTable, NumColors * 3)) != GIF_OK) + return GIF_ERRWRITE; + + /* write graphic extension block with transparent color index */ + if ( TransparentColorIndex >= 0 ) /* (added by j.forkosh) */ + if ( WriteTransparentColorIndex(TransparentColorIndex) + != GIF_OK ) return GIF_ERRWRITE; + + /* initiate and write image descriptor */ + ID.Separator = ','; + ID.LeftPosition = ImageLeft = left; + ID.TopPosition = ImageTop = top; + ID.Width = ImageWidth = width; + ID.Height = ImageHeight = height; + ID.LocalColorTableSize = 0; + ID.Reserved = 0; + ID.SortFlag = 0; + ID.InterlaceFlag = 0; + ID.LocalColorTableFlag = 0; + + if (WriteImageDescriptor(&ID) != GIF_OK) + return GIF_ERRWRITE; + + /* write code size */ + codesize = BitsNeeded(NumColors); + if (codesize == 1) + ++codesize; + if (WriteByte(codesize) != GIF_OK) + return GIF_ERRWRITE; + + /* perform compression */ + RelPixX = RelPixY = 0; + GetPixel = getpixel; + if ((errcode = LZW_Compress(codesize, InputByte)) != GIF_OK) + return errcode; + + /* write terminating 0-byte */ + if (WriteByte(0) != GIF_OK) + return GIF_ERRWRITE; + + return GIF_OK; +} + + + +/*------------------------------------------------------------------------- + * + * NAME GIF_Close + * + * DESCRIPTION Close the GIF-file + * + * RETURNS GIF_OK - OK + * GIF_ERRWRITE - Error writing to file + */ +int +GIF_Close(void) +{ + ImageDescriptor ID; + + /* initiate and write ending image descriptor */ + ID.Separator = ';'; + ID.LeftPosition = 0; /* (added by j.forkosh) */ + ID.TopPosition = 0; /* " initialize entire ID structure */ + ID.Width = 0; /* " and ditto for other ID.x=0; below */ + ID.Height = 0; + ID.LocalColorTableSize = 0; + ID.Reserved = 0; + ID.SortFlag = 0; + ID.InterlaceFlag = 0; + ID.LocalColorTableFlag = 0; + + if (WriteImageDescriptor(&ID) != GIF_OK) + return GIF_ERRWRITE; + + /* close file */ + Close(); + + /* release color table */ + if (ColorTable) { + free(ColorTable); + ColorTable = NULL; + } + + return GIF_OK; +} +/* --- end-of-file gifsave.c --- */ |