📄 gifsave.c
字号:
/* $Id: gifsave.c,v 1.1 2006/04/05 07:22:17 pcool 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; /* " */
int gifSize = 0; /* " #bytes comprising gif */
int maxgifSize = 64000; /* " max #bytes written to OutBuffer */
/* 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) */
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)
{
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -