📄 gifsave.c
字号:
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)
{
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -