478 lines
18 KiB
Plaintext
478 lines
18 KiB
Plaintext
GIF library document
|
|
--------------------
|
|
|
|
Gershon Elber, May 1991
|
|
-----------------------
|
|
|
|
Version 1.2
|
|
-----------
|
|
|
|
The Graphics Interchange Format(c) is the Copyright property of
|
|
CompuServe Incorporated. GIF(sm) is a Service Mark property of CompuServe
|
|
Incorporated.
|
|
|
|
This library was written once I didnt find anything similar and I
|
|
wanted one. I was inspired from the rle Utah tool kit, which I hoped to port
|
|
to an IBM PC, but found it to be too machine specific, and its compression
|
|
ratio too low. I compromised on the GIF format while I am not sure how long
|
|
8 bits per pixel will be enough.
|
|
|
|
|
|
This document explains the GIF library kernel on directory GIF/LIB.
|
|
The kernel is built to the gif_libl.lib which is used in all the utilities
|
|
on GIF/UTIL, or can be used in any application needs to read/write GIF file
|
|
format. This document does NOT explain the GIF file format and assumes it
|
|
is known, at list to the level of the GIF file structure.
|
|
|
|
When a GIF file is opened, a GIF file descriptor is maintained which
|
|
is a pointer to GifFileType structure as follows:
|
|
|
|
typedef struct GifFileType {
|
|
int SWidth, SHeight, /* Screen dimensions */
|
|
SColorResolution, SBitsPerPixel; /* How many colors can we generate? */
|
|
SBackGroundColor, /* I hope you understand this one... */
|
|
ILeft, ITop, IWidth, IHeight, /* Current image dimensions */
|
|
IInterlace, /* Sequential/Interlaced lines */
|
|
IBitsPerPixel; /* How many colors this image has? */
|
|
GifColorType *SColorMap, *IColorMap; /* NULL if not exists */
|
|
void *Private; /* The regular user should not mess with this one! */
|
|
} GifFileType;
|
|
|
|
This structure was copied from gif_lib.h - the header file for the GIF
|
|
library. Any application program that uses the gif_libl.lib library should
|
|
include it. All items begin with S refer to GIF Screen, while the ones with I
|
|
to current image (note GIF file may have more than one image). The user NEVER
|
|
writes into this structure, but can read any of these items at any time it is
|
|
proper (image information is invalid until first image was read/write).
|
|
As the library needs to save its own internal data also, a Private
|
|
pointer to internal structure is also saved there. Applications should ignore
|
|
this item.
|
|
The library has no static data. This means that it is fully reentrant
|
|
and any number of GIF files (up to memory limits) can be opened for
|
|
read/write. Instead of the static data, internal structure pointed by the
|
|
Private pointer is used.
|
|
The library do allocates its own memory dynamically, on opening of
|
|
file, and releases that once closed. The user is NEVER requires to allocate
|
|
any memory for any of the functions of this library (unless the provided
|
|
parameters, such as image line, were prefered to be allocated dynammically by
|
|
the user) nor to free them directly. In order to reduce disk access, the file
|
|
buffer is increased to FILE_BUFFER_SIZE (defined in gif_lib.h). The library
|
|
was compiled in large model as the memory allocated per file is quite big:
|
|
about 17k for decoding (DGIF_LIB.C), and 32k for encoding (EGIF_LIB.C),
|
|
excluding the FILE_BUFFER_SIZE.
|
|
|
|
We now can see what the library contains (directory GIF/LIB):
|
|
|
|
1. EGIF_LIB.C - Encoding routines, all prefixed with E.
|
|
2. DGIF_LIB.C - Decoding routines, all prefixed with D.
|
|
3. DEV2GIF.C - Routines to convert specific device buffers into GIF files.
|
|
4. GIF_ERR.C - Error handler for the library.
|
|
The library has fifth hashing table file in which is accessed internally
|
|
only.
|
|
Major part of the routines returns ERROR (see gif_lib.h) if something went
|
|
wrong or OK otherwise. Once ERROR received, GIF_ERR.C module can be used to
|
|
do something about it.
|
|
|
|
In addition a module to scan the command line arguments was added.
|
|
This module is called GETARG.C and its headers are in GETARG.H. see header
|
|
of GETARG.C for details on its usage.
|
|
|
|
|
|
ENCODING (EGIF_LIB.C)
|
|
---------------------
|
|
|
|
GifFileType *EGifOpenFileName(char *GifFileName, int GifTestExistance);
|
|
|
|
Open a new GIF file using the given GifFileName. If GifTestExistance
|
|
is TRUE, and file exists, the file is not destroyed, and NULL returned.
|
|
If any error occurs, NULL is returned and Error handler can be used
|
|
to get the exact error (see GIF_ERR.C).
|
|
The file is opened in binary mode, and its buffer size is set to
|
|
FILE_BUFFER_SIZE bytes.
|
|
|
|
|
|
GifFileType *EGifOpenFileHandle(int GifFileHandle);
|
|
|
|
Open a new GIF file using the given GifFileHandle
|
|
If any error occurs, NULL is returned and Error handler can be used
|
|
to get the exact error (see GIF_ERR.C)
|
|
The file is opened in binary mode, and its buffer size is set to
|
|
FILE_BUFFER_SIZE bytes.
|
|
|
|
|
|
void EGifSetGifVersion(char *Version);
|
|
|
|
Sets the GIF version of all files to be open from this point (until
|
|
another call to this routine is made. Version is a 3 characters
|
|
string of the form "87a" or "89a". No test is made to validate this
|
|
string.
|
|
|
|
|
|
int EGifPutScreenDesc(GifFileType *GifFile,
|
|
int GifWidth, int GifHeight, int GifColorRes, int GifBackGround,
|
|
int GifBitsPerPixel, GifColorType *GifColorMap);
|
|
|
|
Update GifFile Screen parameters, in GifFile structure and in real
|
|
file. if error occurs returns ERROR (see gif_lib.h), otherwise OK.
|
|
This routine should be called immediately after the GIF file was
|
|
opened.
|
|
|
|
|
|
int EGifPutImageDesc(GifFileType *GifFile,
|
|
int GifLeft, int GifTop, int Width, int GifHeight, int GifInterlace,
|
|
int GifBitsPerPixel, GifColorType *GifColorMap);
|
|
|
|
Update GifFile Image parameters, in GifFile structure and in real
|
|
file. if error occurs returns ERROR (see gif_lib.h), otherwise OK.
|
|
This routine should be called each time a new image should be
|
|
dumped to the file.
|
|
|
|
|
|
int EGifPutLine(GifFileType *GifFile, PixelType *GifLine, int GifLineLen);
|
|
|
|
Dumps block of pixels out to the GIF file. The line length can be
|
|
of any length. More than that, this routine may be interleaved with
|
|
EGifPutPixel, until all pixels were sent.
|
|
Returns ERROR if something went wrong, OK otherwise.
|
|
|
|
|
|
int EGifPutPixel(GifFileType *GifFile, PixelType GifPixel);
|
|
|
|
Dumps one pixel to the GIF file. This routine may be interleaved
|
|
with EGifPutLine, until all pixels were sent. Because of the overhead
|
|
per each call, the usage of this routine is not recommended.
|
|
Returns ERROR if something went wrong, OK otherwise.
|
|
|
|
|
|
int EGifPutComment(GifFileType *GifFile, char *GifComment);
|
|
|
|
Uses extension GIF records to save a string as a comment is the file.
|
|
The extension code is 'C' (for Comment). This is optional in GIF file.
|
|
Returns ERROR if something went wrong, OK otherwise.
|
|
|
|
|
|
int EGifPutExtension(GifFileType *GifFile, int GifExtCode, int GifExtLen,
|
|
void *GifExtension);
|
|
|
|
Dumps the given extension block into the GIF file. Extension blocks
|
|
are optional in GIF file. Extension blocks of more than 255 bytes or
|
|
more than one block are not supported.
|
|
Returns ERROR if something went wrong, OK otherwise.
|
|
|
|
|
|
int EGifPutCode(GifFileType *GifFile, int *GifCodeSize,
|
|
ByteType **GifCodeBlock);
|
|
|
|
It sometimes may be desired to write the compressed code as is
|
|
without decoding it. For example a filter for GIF file that change
|
|
only screen size (GifPos), does not need the exact pixel values and
|
|
pipes out the compressed image as is, make this process much faster.
|
|
This routine do exactly that (with EGifPutCodeNext), and can be
|
|
used instead of EGifPutLine. This usually works with the
|
|
DGifGetCode/DgifGetCodeNext routines, which reads the compressed
|
|
code, while EGifPutCode/EGifPutCodeNext write it out. See GifPos.c
|
|
for example.
|
|
Returns ERROR if something went wrong, OK otherwise.
|
|
|
|
|
|
int EGifPutCodeNext(GifFileType *GifFile, ByteType **GifCodeBlock);
|
|
|
|
See EGifPutCode above.
|
|
|
|
|
|
int EGifCloseFile(GifFileType *GifFile);
|
|
|
|
Close GIF file and free all memory allocated for it. GifFile should
|
|
not be used, once this routine was called.
|
|
Returns ERROR if something went wrong, OK otherwise.
|
|
|
|
|
|
DECODING (DGIF_LIB.C)
|
|
---------------------
|
|
|
|
GifFileType *DGifOpenFileName(char *GifFileName);
|
|
|
|
Open a new GIF file using the given GifFileName, and read its Screen
|
|
information.
|
|
If any error occurs, NULL is returned and Error handler can be used
|
|
to get the exact error (see GIF_ERR.C).
|
|
The file is opened in binary mode, and its buffer size is set to
|
|
FILE_BUFFER_SIZE bytes.
|
|
|
|
|
|
GifFileType *DGifOpenFileHandle(int GifFileHandle);
|
|
|
|
Open a new GIF file using the given GifFileHandle, and read its
|
|
Screen information.
|
|
If any error occurs, NULL is returned and Error handler can be used
|
|
to get the exact error (see GIF_ERR.C)
|
|
The file is opened in binary mode, and its buffer size is set to
|
|
FILE_BUFFER_SIZE bytes.
|
|
|
|
|
|
int DGifGetScreenDesc(GifFileType *GifFile);
|
|
|
|
Reads the screen information into the GifFile structure. Note this
|
|
routine is automatically called once a file is opened, and therefore
|
|
usually not needed.
|
|
Returns ERROR if something went wrong, OK otherwise.
|
|
|
|
|
|
int DGifGetRecordType(GifFileType *GifFile, GifRecordType *GifType);
|
|
|
|
As the GIF file can have different records in arbitrary order, this
|
|
routine should be called once the file was open to detect the next
|
|
record type, and act upon it. Few types might be returned in GifType:
|
|
1. UndefinedRecordType - something is wrong!
|
|
2. ScreenDescRecordType - screen information. As the screen information
|
|
is automatically read in when the file is open, this usually would
|
|
not happen.
|
|
3. ImageDescRecordType - next record is Image.
|
|
4. ExtensionRecordType - next record is extension block.
|
|
5. TerminateRecordType - last record reached, can close the file.
|
|
The first Two types can usually be ignored.
|
|
Returns ERROR if something went wrong, OK otherwise.
|
|
|
|
|
|
int DGifGetImageDesc(GifFileType *GifFile);
|
|
|
|
Reads the image information into the GifFile structure.
|
|
Returns ERROR if something went wrong, OK otherwise.
|
|
|
|
|
|
int DGifGetLine(GifFileType *GifFile, PixelType *GifLine, int GifLineLen);
|
|
|
|
Load block of pixels from the GIF file. The line length can be
|
|
of any length. More than that, this routine may be interleaved with
|
|
DGifGetPixel, until all pixels were read.
|
|
Returns ERROR if something went wrong, OK otherwise.
|
|
|
|
int DGifGetPixel(GifFileType *GifFile, PixelType GifPixel);
|
|
|
|
Loads one pixel from the GIF file. This routine may be interleaved
|
|
with DGifGetLine, until all pixels were read. Because of the overhead
|
|
per each call, the usage of this routine is not recommended.
|
|
Returns ERROR if something went wrong, OK otherwise.
|
|
|
|
int DGifGetComment(GifFileType *GifFile, char *GifComment);
|
|
|
|
Load comment from the GIF file. Because DGifGetRecordType will
|
|
only tell this records is of type extension, this routine should be
|
|
called iff it is known %100 that is must be a comment.
|
|
For definition of comment, see EGifPutComment.
|
|
Returns ERROR if something went wrong, OK otherwise.
|
|
|
|
|
|
int DGifGetExtension(GifFileType *GifFile, int *GifExtCode,
|
|
ByteType **GifExtension);
|
|
|
|
Loads the given extension block from the GIF file. Extension blocks
|
|
are optional in GIF file. This routine should be follows by
|
|
DGifGetExtensionNext - see below
|
|
Returns ERROR if something went wrong, OK otherwise.
|
|
|
|
|
|
int DGifGetExtensionNext(GifFileType *GifFile, ByteType **GifExtension);
|
|
|
|
As extensions may contain more than one block, use this routine to
|
|
continue after DGifGetExtension, until *GifExtension is NULL.
|
|
Returns ERROR if something went wrong, OK otherwise.
|
|
|
|
|
|
int DGifGetCode(GifFileType *GifFile, int *GifCodeSize,
|
|
ByteType **GifCodeBlock);
|
|
|
|
It sometimes may be desired to read the compressed code as is
|
|
without decoding it. This routine do exactly that (with
|
|
DGifGetCodeNext), and can be used instead of DGifGetLine.
|
|
This compressed code information can be written out using the
|
|
EGifPutCode/EGifPutCodeNext sequence (see GifPos.c for example).
|
|
Returns ERROR if something went wrong, OK otherwise.
|
|
|
|
|
|
int DGifGetCodeNext(GifFileType *GifFile, ByteType **GifCodeBlock);
|
|
|
|
See DGifGetCode above.
|
|
|
|
|
|
int DGifGetLZCodes(GifFileType *GifFile, int *GifCode);
|
|
|
|
This routine can be called instead of DGifGetLine/DGifGetPixel or
|
|
DGifGetCode/DGifGetCodeNext to get the 12 bits LZ codes of the images.
|
|
It may be used mainly for debugging purposes (see GifText.c for
|
|
example).
|
|
Returns ERROR if something went wrong, OK otherwise.
|
|
|
|
|
|
int DGifCloseFile(GifFileType *GifFile);
|
|
|
|
Close GIF file and free all memory allocated for it. GifFile should
|
|
not be used, once this routine was called.
|
|
Returns ERROR if something went wrong, OK otherwise.
|
|
|
|
|
|
|
|
ERROR HANDLING (EGIF_LIB.C)
|
|
---------------------------
|
|
|
|
void PrintGifError(void)
|
|
|
|
Print one line diagnostic on the last gif_lib error to stderr.
|
|
|
|
|
|
int GifLastError(void)
|
|
|
|
Return last gif_lib error, and clear the error.
|
|
Note it is the user responsibility to call the file closing routine,
|
|
so the file will be closed (if was opened), and memory will be released
|
|
(if was allocated).
|
|
The different error types are defined in gif_lib.h.
|
|
|
|
|
|
DEVICE SPECIFIC (XXX2GIF.C)
|
|
---------------------------
|
|
|
|
int DumpScreen2Gif(char *FileName, int ReqGraphDriver, int ReqGraphMode1,
|
|
int ReqGraphMode2);
|
|
|
|
Dumps the whole device buffer as specified by GraphDriver and
|
|
GraphMode (as defined in TC 2.0 graphics.h) into FileName as GIF file.
|
|
Current devices supported:
|
|
1. Hercules.
|
|
2. EGA, EGA64, EGAMONO (all modes - see TC graphics.h).
|
|
3. VGA (all modes - see TC graphics.h).
|
|
4. SVGA_SPECIAL. This mode is special and not supported by Borland
|
|
graphics.h. ReqGraphDriver must be equal to 999, and ReqGraphMode
|
|
is ignored. This modes assumes 800 by 600 in 16 colors.
|
|
Returns ERROR if something went wrong, OK otherwise.
|
|
5. SGI 4D using gl graphic library - window dump.
|
|
6. X11 window dump.
|
|
|
|
|
|
COMMAND LINE PARSING (GETARG.C)
|
|
-------------------------------
|
|
|
|
int GAGetArgs(int argc, char **argv, char *CtrlStr, ...);
|
|
|
|
Main routine of this module. Given the argc & argv as received by
|
|
the main procedure, the command line CtrlStr, and the addresses of
|
|
all parameters, parse the command line, and update the parameters.
|
|
The CtrlStr defines what types of variables should follow. Look
|
|
at the beginning of getarg.c for exact usage.
|
|
Returns 0 if successful, error number (as defined by getarg.h)
|
|
otherwise.
|
|
|
|
|
|
void GAPrintErrMsg(int Error);
|
|
|
|
If error occurred in GAGetARgs, this routine may be used to print
|
|
one line diagnostic to stderr.
|
|
|
|
|
|
void GAPrintHowTo(char *CtrlStr);
|
|
|
|
Given same CtrlStr as for GAGetArgs, can be used to print a
|
|
one line 'how to use'
|
|
|
|
|
|
Skeleton of GIF filter
|
|
----------------------
|
|
|
|
This completes the functions, application can access. An application
|
|
skeleton usually will look like (assuming it is a filter - read GIF file,
|
|
modifies it, and write new GIF file) the following example, which only copy
|
|
a GIF file from stdin to stdout. Please give a pick to the utilities on the
|
|
util directory to get more idea once you fill comfortable with this skeleton.
|
|
Also try to follow the coding standards of this package if you want me to
|
|
officially add your new utility to it.
|
|
|
|
#include "getarg.h"
|
|
|
|
main(... )
|
|
{
|
|
GifFile *GifFileIn, *GifFileOut;
|
|
|
|
GAGetArgs( argc, argv, CtrlStr, ... ); /* Process command line */
|
|
|
|
/* Use the stdin as input (note this also read screen descriptor in: */
|
|
if ((GifFileIn = DGifOpenFileHandle(0)) == NULL)
|
|
QuitGifError(GifFileIn, GifFileOut);
|
|
|
|
/* Use the stdout as output: */
|
|
if ((GifFileOut = EGifOpenFileHandle(1)) == NULL)
|
|
QuitGifError(GifFileIn, GifFileOut);
|
|
/* And dump out its screen information: */
|
|
if (EGifPutScreenDesc(GifFileOut,
|
|
GifFileIn -> SWidth, GifFileIn -> SHeight,
|
|
GifFileIn -> SColorResolution, GifFileIn -> SBackGroundColor,
|
|
GifFileIn -> SBitsPerPixel, GifFileIn -> SColorMap) == ERROR)
|
|
QuitGifError(GifFileIn, GifFileOut);
|
|
|
|
/* Scan the content of the input GIF file and load the image(s) in: */
|
|
do {
|
|
if (DGifGetRecordType(GifFileIn, &RecordType) == ERROR)
|
|
QuitGifError(GifFileIn, GifFileOut);
|
|
|
|
switch (RecordType) {
|
|
case IMAGE_DESC_RECORD_TYPE:
|
|
if (DGifGetImageDesc(GifFileIn) == ERROR)
|
|
QuitGifError(GifFileIn, GifFileOut);
|
|
/* Put image descriptor to out file: */
|
|
if (EGifPutImageDesc(GifFileOut,
|
|
GifFileIn -> ILeft, GifFileIn -> ITop,
|
|
GifFileIn -> IWidth, GifFileIn -> IHeight,
|
|
GifFileIn -> IInterlace, GifFileIn -> IBitsPerPixel,
|
|
GifFileIn -> IColorMap) == ERROR)
|
|
QuitGifError(GifFileIn, GifFileOut);
|
|
|
|
/* Now read image itself in decoded form as we dont really */
|
|
/* care what we have there, and this is much faster. */
|
|
if (DGifGetCode(GifFileIn, &CodeSize, &CodeBlock) == ERROR ||
|
|
EGifPutCode(GifFileOut, CodeSize, CodeBlock) == ERROR)
|
|
QuitGifError(GifFileIn, GifFileOut);
|
|
while (CodeBlock != NULL) {
|
|
if (DGifGetCodeNext(GifFileIn, &CodeBlock) == ERROR ||
|
|
EGifPutCodeNext(GifFileOut, CodeBlock) == ERROR)
|
|
QuitGifError(GifFileIn, GifFileOut);
|
|
}
|
|
break;
|
|
case EXTENSION_RECORD_TYPE:
|
|
/* Skip any extension blocks in file: */
|
|
if (DGifGetExtension(GifFileIn, &ExtCode, &Extension) == ERROR)
|
|
QuitGifError(GifFileIn, GifFileOut);
|
|
if (EGifPutExtension(GifFileOut, ExtCode, Extension[0],
|
|
Extension) == ERROR)
|
|
QuitGifError(GifFileIn, GifFileOut);
|
|
|
|
/* No support to more than one extension blocks, so discard: */
|
|
while (Extension != NULL) {
|
|
if (DGifGetExtensionNext(GifFileIn, &Extension) == ERROR)
|
|
QuitGifError(GifFileIn, GifFileOut);
|
|
}
|
|
break;
|
|
case TERMINATE_RECORD_TYPE:
|
|
break;
|
|
default: /* Should be traps by DGifGetRecordType */
|
|
break;
|
|
}
|
|
}
|
|
while (RecordType != TERMINATE_RECORD_TYPE);
|
|
|
|
if (DGifCloseFile(GifFileIn) == ERROR)
|
|
QuitGifError(GifFileIn, GifFileOut);
|
|
if (EGifCloseFile(GifFileOut) == ERROR)
|
|
QuitGifError(GifFileIn, GifFileOut);
|
|
}
|
|
|
|
|
|
/******************************************************************************
|
|
* Close both input and output file (if open), and exit. *
|
|
******************************************************************************/
|
|
static void QuitGifError(GifFileType *GifFileIn, GifFileType *GifFileOut)
|
|
{
|
|
PrintGifError();
|
|
if (GifFileIn != NULL) DGifCloseFile(GifFileIn);
|
|
if (GifFileOut != NULL) EGifCloseFile(GifFileOut);
|
|
exit(1);
|
|
}
|