This source file includes following definitions.
- EGifOpenFileName
- EGifOpenFileHandle
- EGifOpen
- EGifGetGifVersion
- EGifSetGifVersion
- InternalWrite
- EGifPutScreenDesc
- EGifPutImageDesc
- EGifPutLine
- EGifPutPixel
- EGifPutComment
- EGifPutExtensionLeader
- EGifPutExtensionBlock
- EGifPutExtensionTrailer
- EGifPutExtension
- EGifGCBToExtension
- EGifGCBToSavedExtension
- EGifPutCode
- EGifPutCodeNext
- EGifCloseFile
- EGifPutWord
- EGifSetupCompress
- EGifCompressLine
- EGifCompressOutput
- EGifBufferedOutput
- EGifWriteExtensions
- EGifSpew
#include <unistd.h>
#include <stdint.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#ifdef _WIN32
#include <io.h>
#else
#include <sys/types.h>
#endif
#include <sys/stat.h>
#include "gif_lib.h"
#include "gif_lib_private.h"
static const GifPixelType CodeMask[] = {
0x00, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff
};
static int EGifPutWord(int Word, GifFileType * GifFile);
static int EGifSetupCompress(GifFileType * GifFile);
static int EGifCompressLine(GifFileType * GifFile, GifPixelType * Line,
int LineLen);
static int EGifCompressOutput(GifFileType * GifFile, int Code);
static int EGifBufferedOutput(GifFileType * GifFile, GifByteType * Buf,
int c);
#define LOBYTE(x) ((x) & 0xff)
#define HIBYTE(x) (((x) >> 8) & 0xff)
GifFileType *
EGifOpenFileName(const char *FileName, const bool TestExistence, int *Error)
{
int FileHandle;
GifFileType *GifFile;
if (TestExistence)
FileHandle = open(FileName, O_WRONLY | O_CREAT | O_EXCL,
S_IREAD | S_IWRITE);
else
FileHandle = open(FileName, O_WRONLY | O_CREAT | O_TRUNC,
S_IREAD | S_IWRITE);
if (FileHandle == -1) {
if (Error != NULL)
*Error = E_GIF_ERR_OPEN_FAILED;
return NULL;
}
GifFile = EGifOpenFileHandle(FileHandle, Error);
if (GifFile == (GifFileType *) NULL)
(void)close(FileHandle);
return GifFile;
}
GifFileType *
EGifOpenFileHandle(const int FileHandle, int *Error)
{
GifFileType *GifFile;
GifFilePrivateType *Private;
FILE *f;
GifFile = (GifFileType *) malloc(sizeof(GifFileType));
if (GifFile == NULL) {
return NULL;
}
memset(GifFile, '\0', sizeof(GifFileType));
Private = (GifFilePrivateType *)malloc(sizeof(GifFilePrivateType));
if (Private == NULL) {
free(GifFile);
if (Error != NULL)
*Error = E_GIF_ERR_NOT_ENOUGH_MEM;
return NULL;
}
if ((Private->HashTable = _InitHashTable()) == NULL) {
free(GifFile);
free(Private);
if (Error != NULL)
*Error = E_GIF_ERR_NOT_ENOUGH_MEM;
return NULL;
}
#ifdef _WIN32
_setmode(FileHandle, O_BINARY);
#endif
f = fdopen(FileHandle, "wb");
GifFile->Private = (void *)Private;
Private->FileHandle = FileHandle;
Private->File = f;
Private->FileState = FILE_STATE_WRITE;
Private->Write = (OutputFunc) 0;
GifFile->UserData = (void *)NULL;
GifFile->Error = 0;
return GifFile;
}
GifFileType *
EGifOpen(void *userData, OutputFunc writeFunc, int *Error)
{
GifFileType *GifFile;
GifFilePrivateType *Private;
GifFile = (GifFileType *)malloc(sizeof(GifFileType));
if (GifFile == NULL) {
if (Error != NULL)
*Error = E_GIF_ERR_NOT_ENOUGH_MEM;
return NULL;
}
memset(GifFile, '\0', sizeof(GifFileType));
Private = (GifFilePrivateType *)malloc(sizeof(GifFilePrivateType));
if (Private == NULL) {
free(GifFile);
if (Error != NULL)
*Error = E_GIF_ERR_NOT_ENOUGH_MEM;
return NULL;
}
Private->HashTable = _InitHashTable();
if (Private->HashTable == NULL) {
free (GifFile);
free (Private);
if (Error != NULL)
*Error = E_GIF_ERR_NOT_ENOUGH_MEM;
return NULL;
}
GifFile->Private = (void *)Private;
Private->FileHandle = 0;
Private->File = (FILE *) 0;
Private->FileState = FILE_STATE_WRITE;
Private->Write = writeFunc;
GifFile->UserData = userData;
Private->gif89 = false;
GifFile->Error = 0;
return GifFile;
}
const char *
EGifGetGifVersion(GifFileType *GifFile)
{
GifFilePrivateType *Private = (GifFilePrivateType *) GifFile->Private;
int i, j;
for (i = 0; i < GifFile->ImageCount; i++) {
for (j = 0; j < GifFile->SavedImages[i].ExtensionBlockCount; j++) {
int function =
GifFile->SavedImages[i].ExtensionBlocks[j].Function;
if (function == COMMENT_EXT_FUNC_CODE
|| function == GRAPHICS_EXT_FUNC_CODE
|| function == PLAINTEXT_EXT_FUNC_CODE
|| function == APPLICATION_EXT_FUNC_CODE)
Private->gif89 = true;
}
}
for (i = 0; i < GifFile->ExtensionBlockCount; i++) {
int function = GifFile->ExtensionBlocks[i].Function;
if (function == COMMENT_EXT_FUNC_CODE
|| function == GRAPHICS_EXT_FUNC_CODE
|| function == PLAINTEXT_EXT_FUNC_CODE
|| function == APPLICATION_EXT_FUNC_CODE)
Private->gif89 = true;
}
if (Private->gif89)
return GIF89_STAMP;
else
return GIF87_STAMP;
}
void EGifSetGifVersion(GifFileType *GifFile, const bool gif89)
{
GifFilePrivateType *Private = (GifFilePrivateType *) GifFile->Private;
Private->gif89 = gif89;
}
static int InternalWrite(GifFileType *GifFileOut,
const unsigned char *buf, size_t len)
{
GifFilePrivateType *Private = (GifFilePrivateType*)GifFileOut->Private;
if (Private->Write)
return Private->Write(GifFileOut,buf,len);
else
return fwrite(buf, 1, len, Private->File);
}
int
EGifPutScreenDesc(GifFileType *GifFile,
const int Width,
const int Height,
const int ColorRes,
const int BackGround,
const ColorMapObject *ColorMap)
{
GifByteType Buf[3];
GifFilePrivateType *Private = (GifFilePrivateType *) GifFile->Private;
const char *write_version;
if (Private->FileState & FILE_STATE_SCREEN) {
GifFile->Error = E_GIF_ERR_HAS_SCRN_DSCR;
return GIF_ERROR;
}
if (!IS_WRITEABLE(Private)) {
GifFile->Error = E_GIF_ERR_NOT_WRITEABLE;
return GIF_ERROR;
}
write_version = EGifGetGifVersion(GifFile);
if (InternalWrite(GifFile, (unsigned char *)write_version,
strlen(write_version)) != strlen(write_version)) {
GifFile->Error = E_GIF_ERR_WRITE_FAILED;
return GIF_ERROR;
}
GifFile->SWidth = Width;
GifFile->SHeight = Height;
GifFile->SColorResolution = ColorRes;
GifFile->SBackGroundColor = BackGround;
if (ColorMap) {
GifFile->SColorMap = GifMakeMapObject(ColorMap->ColorCount,
ColorMap->Colors);
if (GifFile->SColorMap == NULL) {
GifFile->Error = E_GIF_ERR_NOT_ENOUGH_MEM;
return GIF_ERROR;
}
} else
GifFile->SColorMap = NULL;
(void)EGifPutWord(Width, GifFile);
(void)EGifPutWord(Height, GifFile);
Buf[0] = (ColorMap ? 0x80 : 0x00) |
((ColorRes - 1) << 4) |
(ColorMap ? ColorMap->BitsPerPixel - 1 : 0x07 );
if (ColorMap != NULL && ColorMap->SortFlag)
Buf[0] |= 0x08;
Buf[1] = BackGround;
Buf[2] = GifFile->AspectByte;
InternalWrite(GifFile, Buf, 3);
if (ColorMap != NULL) {
int i;
for (i = 0; i < ColorMap->ColorCount; i++) {
Buf[0] = ColorMap->Colors[i].Red;
Buf[1] = ColorMap->Colors[i].Green;
Buf[2] = ColorMap->Colors[i].Blue;
if (InternalWrite(GifFile, Buf, 3) != 3) {
GifFile->Error = E_GIF_ERR_WRITE_FAILED;
return GIF_ERROR;
}
}
}
Private->FileState |= FILE_STATE_SCREEN;
return GIF_OK;
}
int
EGifPutImageDesc(GifFileType *GifFile,
const int Left,
const int Top,
const int Width,
const int Height,
const bool Interlace,
const ColorMapObject *ColorMap)
{
GifByteType Buf[3];
GifFilePrivateType *Private = (GifFilePrivateType *)GifFile->Private;
if (Private->FileState & FILE_STATE_IMAGE &&
Private->PixelCount > 0xffff0000UL) {
GifFile->Error = E_GIF_ERR_HAS_IMAG_DSCR;
return GIF_ERROR;
}
if (!IS_WRITEABLE(Private)) {
GifFile->Error = E_GIF_ERR_NOT_WRITEABLE;
return GIF_ERROR;
}
GifFile->Image.Left = Left;
GifFile->Image.Top = Top;
GifFile->Image.Width = Width;
GifFile->Image.Height = Height;
GifFile->Image.Interlace = Interlace;
if (ColorMap) {
if (GifFile->Image.ColorMap != NULL) {
GifFreeMapObject(GifFile->Image.ColorMap);
GifFile->Image.ColorMap = NULL;
}
GifFile->Image.ColorMap = GifMakeMapObject(ColorMap->ColorCount,
ColorMap->Colors);
if (GifFile->Image.ColorMap == NULL) {
GifFile->Error = E_GIF_ERR_NOT_ENOUGH_MEM;
return GIF_ERROR;
}
} else {
GifFile->Image.ColorMap = NULL;
}
Buf[0] = DESCRIPTOR_INTRODUCER;
InternalWrite(GifFile, Buf, 1);
(void)EGifPutWord(Left, GifFile);
(void)EGifPutWord(Top, GifFile);
(void)EGifPutWord(Width, GifFile);
(void)EGifPutWord(Height, GifFile);
Buf[0] = (ColorMap ? 0x80 : 0x00) |
(Interlace ? 0x40 : 0x00) |
(ColorMap ? ColorMap->BitsPerPixel - 1 : 0);
InternalWrite(GifFile, Buf, 1);
if (ColorMap != NULL) {
int i;
for (i = 0; i < ColorMap->ColorCount; i++) {
Buf[0] = ColorMap->Colors[i].Red;
Buf[1] = ColorMap->Colors[i].Green;
Buf[2] = ColorMap->Colors[i].Blue;
if (InternalWrite(GifFile, Buf, 3) != 3) {
GifFile->Error = E_GIF_ERR_WRITE_FAILED;
return GIF_ERROR;
}
}
}
if (GifFile->SColorMap == NULL && GifFile->Image.ColorMap == NULL) {
GifFile->Error = E_GIF_ERR_NO_COLOR_MAP;
return GIF_ERROR;
}
Private->FileState |= FILE_STATE_IMAGE;
Private->PixelCount = (long)Width *(long)Height;
(void)EGifSetupCompress(GifFile);
return GIF_OK;
}
int
EGifPutLine(GifFileType * GifFile, GifPixelType *Line, int LineLen)
{
int i;
GifPixelType Mask;
GifFilePrivateType *Private = (GifFilePrivateType *) GifFile->Private;
if (!IS_WRITEABLE(Private)) {
GifFile->Error = E_GIF_ERR_NOT_WRITEABLE;
return GIF_ERROR;
}
if (!LineLen)
LineLen = GifFile->Image.Width;
if (Private->PixelCount < (unsigned)LineLen) {
GifFile->Error = E_GIF_ERR_DATA_TOO_BIG;
return GIF_ERROR;
}
Private->PixelCount -= LineLen;
Mask = CodeMask[Private->BitsPerPixel];
for (i = 0; i < LineLen; i++)
Line[i] &= Mask;
return EGifCompressLine(GifFile, Line, LineLen);
}
int
EGifPutPixel(GifFileType *GifFile, GifPixelType Pixel)
{
GifFilePrivateType *Private = (GifFilePrivateType *)GifFile->Private;
if (!IS_WRITEABLE(Private)) {
GifFile->Error = E_GIF_ERR_NOT_WRITEABLE;
return GIF_ERROR;
}
if (Private->PixelCount == 0) {
GifFile->Error = E_GIF_ERR_DATA_TOO_BIG;
return GIF_ERROR;
}
--Private->PixelCount;
Pixel &= CodeMask[Private->BitsPerPixel];
return EGifCompressLine(GifFile, &Pixel, 1);
}
int
EGifPutComment(GifFileType *GifFile, const char *Comment)
{
unsigned int length;
char *buf;
length = strlen(Comment);
if (length <= 255) {
return EGifPutExtension(GifFile, COMMENT_EXT_FUNC_CODE,
length, Comment);
} else {
buf = (char *)Comment;
if (EGifPutExtensionLeader(GifFile, COMMENT_EXT_FUNC_CODE)
== GIF_ERROR) {
return GIF_ERROR;
}
while (length > 255) {
if (EGifPutExtensionBlock(GifFile, 255, buf) == GIF_ERROR) {
return GIF_ERROR;
}
buf = buf + 255;
length -= 255;
}
if (length > 0) {
if (EGifPutExtensionBlock(GifFile, length, buf) == GIF_ERROR) {
return GIF_ERROR;
}
}
if (EGifPutExtensionTrailer(GifFile) == GIF_ERROR) {
return GIF_ERROR;
}
}
return GIF_OK;
}
int
EGifPutExtensionLeader(GifFileType *GifFile, const int ExtCode)
{
GifByteType Buf[3];
GifFilePrivateType *Private = (GifFilePrivateType *)GifFile->Private;
if (!IS_WRITEABLE(Private)) {
GifFile->Error = E_GIF_ERR_NOT_WRITEABLE;
return GIF_ERROR;
}
Buf[0] = EXTENSION_INTRODUCER;
Buf[1] = ExtCode;
InternalWrite(GifFile, Buf, 2);
return GIF_OK;
}
int
EGifPutExtensionBlock(GifFileType *GifFile,
const int ExtLen,
const void *Extension)
{
GifByteType Buf;
GifFilePrivateType *Private = (GifFilePrivateType *)GifFile->Private;
if (!IS_WRITEABLE(Private)) {
GifFile->Error = E_GIF_ERR_NOT_WRITEABLE;
return GIF_ERROR;
}
Buf = ExtLen;
InternalWrite(GifFile, &Buf, 1);
InternalWrite(GifFile, Extension, ExtLen);
return GIF_OK;
}
int
EGifPutExtensionTrailer(GifFileType *GifFile) {
GifByteType Buf;
GifFilePrivateType *Private = (GifFilePrivateType *)GifFile->Private;
if (!IS_WRITEABLE(Private)) {
GifFile->Error = E_GIF_ERR_NOT_WRITEABLE;
return GIF_ERROR;
}
Buf = 0;
InternalWrite(GifFile, &Buf, 1);
return GIF_OK;
}
int
EGifPutExtension(GifFileType *GifFile,
const int ExtCode,
const int ExtLen,
const void *Extension) {
GifByteType Buf[3];
GifFilePrivateType *Private = (GifFilePrivateType *)GifFile->Private;
if (!IS_WRITEABLE(Private)) {
GifFile->Error = E_GIF_ERR_NOT_WRITEABLE;
return GIF_ERROR;
}
if (ExtCode == 0)
InternalWrite(GifFile, (GifByteType *)&ExtLen, 1);
else {
Buf[0] = EXTENSION_INTRODUCER;
Buf[1] = ExtCode;
Buf[2] = ExtLen;
InternalWrite(GifFile, Buf, 3);
}
InternalWrite(GifFile, Extension, ExtLen);
Buf[0] = 0;
InternalWrite(GifFile, Buf, 1);
return GIF_OK;
}
size_t EGifGCBToExtension(const GraphicsControlBlock *GCB,
GifByteType *GifExtension)
{
GifExtension[0] = 0;
GifExtension[0] |= (GCB->TransparentColor == NO_TRANSPARENT_COLOR) ? 0x00 : 0x01;
GifExtension[0] |= GCB->UserInputFlag ? 0x02 : 0x00;
GifExtension[0] |= ((GCB->DisposalMode & 0x07) << 2);
GifExtension[1] = LOBYTE(GCB->DelayTime);
GifExtension[2] = HIBYTE(GCB->DelayTime);
GifExtension[3] = (char)GCB->TransparentColor;
return 4;
}
int EGifGCBToSavedExtension(const GraphicsControlBlock *GCB,
GifFileType *GifFile, int ImageIndex)
{
int i;
size_t Len;
GifByteType buf[sizeof(GraphicsControlBlock)];
if (ImageIndex < 0 || ImageIndex > GifFile->ImageCount - 1)
return GIF_ERROR;
for (i = 0; i < GifFile->SavedImages[ImageIndex].ExtensionBlockCount; i++) {
ExtensionBlock *ep = &GifFile->SavedImages[ImageIndex].ExtensionBlocks[i];
if (ep->Function == GRAPHICS_EXT_FUNC_CODE) {
EGifGCBToExtension(GCB, ep->Bytes);
return GIF_OK;
}
}
Len = EGifGCBToExtension(GCB, (GifByteType *)buf);
if (GifAddExtensionBlock(&GifFile->SavedImages[ImageIndex].ExtensionBlockCount,
&GifFile->SavedImages[ImageIndex].ExtensionBlocks,
GRAPHICS_EXT_FUNC_CODE,
Len,
(unsigned char *)buf) == GIF_ERROR)
return (GIF_ERROR);
return (GIF_OK);
}
int
EGifPutCode(GifFileType *GifFile, int CodeSize, const GifByteType *CodeBlock)
{
GifFilePrivateType *Private = (GifFilePrivateType *)GifFile->Private;
if (!IS_WRITEABLE(Private)) {
GifFile->Error = E_GIF_ERR_NOT_WRITEABLE;
return GIF_ERROR;
}
return EGifPutCodeNext(GifFile, CodeBlock);
}
int
EGifPutCodeNext(GifFileType *GifFile, const GifByteType *CodeBlock)
{
GifByteType Buf;
GifFilePrivateType *Private = (GifFilePrivateType *)GifFile->Private;
if (CodeBlock != NULL) {
if (InternalWrite(GifFile, CodeBlock, CodeBlock[0] + 1)
!= (unsigned)(CodeBlock[0] + 1)) {
GifFile->Error = E_GIF_ERR_WRITE_FAILED;
return GIF_ERROR;
}
} else {
Buf = 0;
if (InternalWrite(GifFile, &Buf, 1) != 1) {
GifFile->Error = E_GIF_ERR_WRITE_FAILED;
return GIF_ERROR;
}
Private->PixelCount = 0;
}
return GIF_OK;
}
int
EGifCloseFile(GifFileType *GifFile, int *ErrorCode)
{
GifByteType Buf;
GifFilePrivateType *Private;
FILE *File;
if (GifFile == NULL)
return GIF_ERROR;
Private = (GifFilePrivateType *) GifFile->Private;
if (Private == NULL)
return GIF_ERROR;
if (!IS_WRITEABLE(Private)) {
if (ErrorCode != NULL)
*ErrorCode = E_GIF_ERR_NOT_WRITEABLE;
free(GifFile);
return GIF_ERROR;
}
File = Private->File;
Buf = TERMINATOR_INTRODUCER;
InternalWrite(GifFile, &Buf, 1);
if (GifFile->Image.ColorMap) {
GifFreeMapObject(GifFile->Image.ColorMap);
GifFile->Image.ColorMap = NULL;
}
if (GifFile->SColorMap) {
GifFreeMapObject(GifFile->SColorMap);
GifFile->SColorMap = NULL;
}
if (Private) {
if (Private->HashTable) {
free((char *) Private->HashTable);
}
free((char *) Private);
}
if (File && fclose(File) != 0) {
if (ErrorCode != NULL)
*ErrorCode = E_GIF_ERR_CLOSE_FAILED;
free(GifFile);
return GIF_ERROR;
}
free(GifFile);
if (ErrorCode != NULL)
*ErrorCode = E_GIF_SUCCEEDED;
return GIF_OK;
}
static int
EGifPutWord(int Word, GifFileType *GifFile)
{
unsigned char c[2];
c[0] = LOBYTE(Word);
c[1] = HIBYTE(Word);
if (InternalWrite(GifFile, c, 2) == 2)
return GIF_OK;
else
return GIF_ERROR;
}
static int
EGifSetupCompress(GifFileType *GifFile)
{
int BitsPerPixel;
GifByteType Buf;
GifFilePrivateType *Private = (GifFilePrivateType *) GifFile->Private;
if (GifFile->Image.ColorMap)
BitsPerPixel = GifFile->Image.ColorMap->BitsPerPixel;
else if (GifFile->SColorMap)
BitsPerPixel = GifFile->SColorMap->BitsPerPixel;
else {
GifFile->Error = E_GIF_ERR_NO_COLOR_MAP;
return GIF_ERROR;
}
Buf = BitsPerPixel = (BitsPerPixel < 2 ? 2 : BitsPerPixel);
InternalWrite(GifFile, &Buf, 1);
Private->Buf[0] = 0;
Private->BitsPerPixel = BitsPerPixel;
Private->ClearCode = (1 << BitsPerPixel);
Private->EOFCode = Private->ClearCode + 1;
Private->RunningCode = Private->EOFCode + 1;
Private->RunningBits = BitsPerPixel + 1;
Private->MaxCode1 = 1 << Private->RunningBits;
Private->CrntCode = FIRST_CODE;
Private->CrntShiftState = 0;
Private->CrntShiftDWord = 0;
_ClearHashTable(Private->HashTable);
if (EGifCompressOutput(GifFile, Private->ClearCode) == GIF_ERROR) {
GifFile->Error = E_GIF_ERR_DISK_IS_FULL;
return GIF_ERROR;
}
return GIF_OK;
}
static int
EGifCompressLine(GifFileType *GifFile,
GifPixelType *Line,
const int LineLen)
{
int i = 0, CrntCode, NewCode;
unsigned long NewKey;
GifPixelType Pixel;
GifHashTableType *HashTable;
GifFilePrivateType *Private = (GifFilePrivateType *) GifFile->Private;
HashTable = Private->HashTable;
if (Private->CrntCode == FIRST_CODE)
CrntCode = Line[i++];
else
CrntCode = Private->CrntCode;
while (i < LineLen) {
Pixel = Line[i++];
NewKey = (((uint32_t) CrntCode) << 8) + Pixel;
if ((NewCode = _ExistsHashTable(HashTable, NewKey)) >= 0) {
CrntCode = NewCode;
} else {
if (EGifCompressOutput(GifFile, CrntCode) == GIF_ERROR) {
GifFile->Error = E_GIF_ERR_DISK_IS_FULL;
return GIF_ERROR;
}
CrntCode = Pixel;
if (Private->RunningCode >= LZ_MAX_CODE) {
if (EGifCompressOutput(GifFile, Private->ClearCode)
== GIF_ERROR) {
GifFile->Error = E_GIF_ERR_DISK_IS_FULL;
return GIF_ERROR;
}
Private->RunningCode = Private->EOFCode + 1;
Private->RunningBits = Private->BitsPerPixel + 1;
Private->MaxCode1 = 1 << Private->RunningBits;
_ClearHashTable(HashTable);
} else {
_InsertHashTable(HashTable, NewKey, Private->RunningCode++);
}
}
}
Private->CrntCode = CrntCode;
if (Private->PixelCount == 0) {
if (EGifCompressOutput(GifFile, CrntCode) == GIF_ERROR) {
GifFile->Error = E_GIF_ERR_DISK_IS_FULL;
return GIF_ERROR;
}
if (EGifCompressOutput(GifFile, Private->EOFCode) == GIF_ERROR) {
GifFile->Error = E_GIF_ERR_DISK_IS_FULL;
return GIF_ERROR;
}
if (EGifCompressOutput(GifFile, FLUSH_OUTPUT) == GIF_ERROR) {
GifFile->Error = E_GIF_ERR_DISK_IS_FULL;
return GIF_ERROR;
}
}
return GIF_OK;
}
static int
EGifCompressOutput(GifFileType *GifFile,
const int Code)
{
GifFilePrivateType *Private = (GifFilePrivateType *) GifFile->Private;
int retval = GIF_OK;
if (Code == FLUSH_OUTPUT) {
while (Private->CrntShiftState > 0) {
if (EGifBufferedOutput(GifFile, Private->Buf,
Private->CrntShiftDWord & 0xff) == GIF_ERROR)
retval = GIF_ERROR;
Private->CrntShiftDWord >>= 8;
Private->CrntShiftState -= 8;
}
Private->CrntShiftState = 0;
if (EGifBufferedOutput(GifFile, Private->Buf,
FLUSH_OUTPUT) == GIF_ERROR)
retval = GIF_ERROR;
} else {
Private->CrntShiftDWord |= ((long)Code) << Private->CrntShiftState;
Private->CrntShiftState += Private->RunningBits;
while (Private->CrntShiftState >= 8) {
if (EGifBufferedOutput(GifFile, Private->Buf,
Private->CrntShiftDWord & 0xff) == GIF_ERROR)
retval = GIF_ERROR;
Private->CrntShiftDWord >>= 8;
Private->CrntShiftState -= 8;
}
}
if (Private->RunningCode >= Private->MaxCode1 && Code <= 4095) {
Private->MaxCode1 = 1 << ++Private->RunningBits;
}
return retval;
}
static int
EGifBufferedOutput(GifFileType *GifFile,
GifByteType *Buf,
int c)
{
if (c == FLUSH_OUTPUT) {
if (Buf[0] != 0
&& InternalWrite(GifFile, Buf, Buf[0] + 1) != (unsigned)(Buf[0] + 1)) {
GifFile->Error = E_GIF_ERR_WRITE_FAILED;
return GIF_ERROR;
}
Buf[0] = 0;
if (InternalWrite(GifFile, Buf, 1) != 1) {
GifFile->Error = E_GIF_ERR_WRITE_FAILED;
return GIF_ERROR;
}
} else {
if (Buf[0] == 255) {
if (InternalWrite(GifFile, Buf, Buf[0] + 1) != (unsigned)(Buf[0] + 1)) {
GifFile->Error = E_GIF_ERR_WRITE_FAILED;
return GIF_ERROR;
}
Buf[0] = 0;
}
Buf[++Buf[0]] = c;
}
return GIF_OK;
}
static int
EGifWriteExtensions(GifFileType *GifFileOut,
ExtensionBlock *ExtensionBlocks,
int ExtensionBlockCount)
{
if (ExtensionBlocks) {
ExtensionBlock *ep;
int j;
for (j = 0; j < ExtensionBlockCount; j++) {
ep = &ExtensionBlocks[j];
if (ep->Function != CONTINUE_EXT_FUNC_CODE)
if (EGifPutExtensionLeader(GifFileOut, ep->Function) == GIF_ERROR)
return (GIF_ERROR);
if (EGifPutExtensionBlock(GifFileOut, ep->ByteCount, ep->Bytes) == GIF_ERROR)
return (GIF_ERROR);
if (j == ExtensionBlockCount - 1 || (ep+1)->Function != CONTINUE_EXT_FUNC_CODE)
if (EGifPutExtensionTrailer(GifFileOut) == GIF_ERROR)
return (GIF_ERROR);
}
}
return (GIF_OK);
}
int
EGifSpew(GifFileType *GifFileOut)
{
int i, j;
if (EGifPutScreenDesc(GifFileOut,
GifFileOut->SWidth,
GifFileOut->SHeight,
GifFileOut->SColorResolution,
GifFileOut->SBackGroundColor,
GifFileOut->SColorMap) == GIF_ERROR) {
return (GIF_ERROR);
}
for (i = 0; i < GifFileOut->ImageCount; i++) {
SavedImage *sp = &GifFileOut->SavedImages[i];
int SavedHeight = sp->ImageDesc.Height;
int SavedWidth = sp->ImageDesc.Width;
if (sp->RasterBits == NULL)
continue;
if (EGifWriteExtensions(GifFileOut,
sp->ExtensionBlocks,
sp->ExtensionBlockCount) == GIF_ERROR)
return (GIF_ERROR);
if (EGifPutImageDesc(GifFileOut,
sp->ImageDesc.Left,
sp->ImageDesc.Top,
SavedWidth,
SavedHeight,
sp->ImageDesc.Interlace,
sp->ImageDesc.ColorMap) == GIF_ERROR)
return (GIF_ERROR);
if (sp->ImageDesc.Interlace) {
int InterlacedOffset[] = { 0, 4, 2, 1 };
int InterlacedJumps[] = { 8, 8, 4, 2 };
int k;
for (k = 0; k < 4; k++)
for (j = InterlacedOffset[k];
j < SavedHeight;
j += InterlacedJumps[k]) {
if (EGifPutLine(GifFileOut,
sp->RasterBits + j * SavedWidth,
SavedWidth) == GIF_ERROR)
return (GIF_ERROR);
}
} else {
for (j = 0; j < SavedHeight; j++) {
if (EGifPutLine(GifFileOut,
sp->RasterBits + j * SavedWidth,
SavedWidth) == GIF_ERROR)
return (GIF_ERROR);
}
}
}
if (EGifWriteExtensions(GifFileOut,
GifFileOut->ExtensionBlocks,
GifFileOut->ExtensionBlockCount) == GIF_ERROR)
return (GIF_ERROR);
if (EGifCloseFile(GifFileOut, NULL) == GIF_ERROR)
return (GIF_ERROR);
return (GIF_OK);
}