First commit ~0,10
This commit is contained in:
512
G/LIB/DEV2GIF.C
Normal file
512
G/LIB/DEV2GIF.C
Normal file
@ -0,0 +1,512 @@
|
||||
/*****************************************************************************
|
||||
* "Gif-Lib" - Yet another gif library. *
|
||||
* *
|
||||
* Written by: Gershon Elber IBM PC Ver 1.1, Jun. 1989 *
|
||||
******************************************************************************
|
||||
* Module to dump graphic devices into a GIF file. Current supported devices: *
|
||||
* 1. EGA, VGA, SVGA (800x600), Hercules on the IBM PC (#define __MSDOS__). *
|
||||
* 2. SGI 4D Irix using gl library (#define __SGI_GL__). *
|
||||
* 3. X11 using libX.a (#define __X11__). *
|
||||
******************************************************************************
|
||||
* History: *
|
||||
* 22 Jun 89 - Version 1.0 by Gershon Elber. *
|
||||
* 12 Aug 90 - Version 1.1 by Gershon Elber (added devices). *
|
||||
*****************************************************************************/
|
||||
|
||||
#ifdef __MSDOS__
|
||||
#include <dos.h>
|
||||
#include <alloc.h>
|
||||
#include <graphics.h>
|
||||
#endif /* __MSDOS__ */
|
||||
|
||||
#ifdef __SGI_GL__
|
||||
#include <gl/gl.h>
|
||||
#endif /* __SGI_GL__ */
|
||||
|
||||
#ifdef __X11__
|
||||
#include <X11/Xlib.h>
|
||||
#endif /* __X11__ */
|
||||
|
||||
#include <stdio.h>
|
||||
#include "gif_lib.h"
|
||||
|
||||
#define PROGRAM_NAME "GIF_LIBRARY"
|
||||
|
||||
#define SVGA_SPECIAL 999 /* 800 by 600 Super VGA mode. */
|
||||
|
||||
static int GraphDriver = -1, /* Device parameters - reasonable values. */
|
||||
GraphMode = -1,
|
||||
ScreenColorBits = 1;
|
||||
static long ScreenXMax = 100,
|
||||
ScreenYMax = 100;
|
||||
static unsigned int ScreenBase;
|
||||
|
||||
#ifdef SYSV
|
||||
static char *VersionStr =
|
||||
"Gif library module,\t\tGershon Elber\n\
|
||||
(C) Copyright 1989 Gershon Elber, Non commercial use only.\n";
|
||||
#else
|
||||
static char *VersionStr =
|
||||
PROGRAM_NAME
|
||||
" IBMPC "
|
||||
GIF_LIB_VERSION
|
||||
" Gershon Elber, "
|
||||
__DATE__ ", " __TIME__ "\n"
|
||||
"(C) Copyright 1989 Gershon Elber, Non commercial use only.\n";
|
||||
#endif /* SYSV */
|
||||
|
||||
#if defined(__SGI_GL__) || defined(__X11__)
|
||||
GifByteType *GlblGifBuffer = NULL, *GlblGifBufferPtr = NULL;
|
||||
#endif /* __SGI_GL__ || __X11__ */
|
||||
|
||||
#ifdef __SGI_GL__
|
||||
static int QuantizeRGBBuffer(int Width, int Height, long *RGBBuffer,
|
||||
GifColorType *ColorMap, GifByteType *GIFBuffer);
|
||||
#endif /* __SGI_GL__ */
|
||||
|
||||
static void GetScanLine(GifPixelType *ScanLine, int Y);
|
||||
static int HandleGifError(GifFileType *GifFile);
|
||||
|
||||
/******************************************************************************
|
||||
* Dump the given Device, into given File as GIF format: *
|
||||
* Return 0 on success, -1 if device not supported, or GIF-LIB error number. *
|
||||
* Device is selected via the ReqGraphDriver. Device mode is selected via *
|
||||
* ReqGraphMode1/2 as follows: *
|
||||
* 1. IBM PC Hercules card: HERCMONO (one mode only) in ReqGraphMode1, *
|
||||
* ReqGraphMode2/3 are ignored. *
|
||||
* 2. IBM PC EGA card: EGALO/EGAHI in ReqGraphMode1, *
|
||||
* ReqGraphMode2/3 are ignored. *
|
||||
* 3. IBM PC EGA64 card: EGA64LO/EGA64HI in ReqGraphMode1, *
|
||||
* ReqGraphMode2/3 are ignored. *
|
||||
* 4. IBM PC EGAMONO card: EGAMONOHI (one mode only) in ReqGraphMode1, *
|
||||
* ReqGraphMode2/3 are ignored. *
|
||||
* 5. IBM PC VGA card: VGALO/VGAMED/VGAHI in ReqGraphMode1, *
|
||||
* ReqGraphMode2/3 are ignored. *
|
||||
* 6. IBM PC SVGA card: ReqGraphMode1/2 are both ignored. Fixed mode (800x600 *
|
||||
* 16 colors) is assumed. *
|
||||
* 7. SGI 4D using GL: window id to dump (as returned by winget()) in *
|
||||
* ReqGraphMode1, ReqGraphMode2/3 are ignored. *
|
||||
* 8. X11: Window id in ReqGraphMode1, Display id in ReqGraphMode2, Color *
|
||||
* map id in ReqGraphMode3. *
|
||||
******************************************************************************/
|
||||
int DumpScreen2Gif(char *FileName, int ReqGraphDriver, int ReqGraphMode1,
|
||||
int ReqGraphMode2,
|
||||
int ReqGraphMode3)
|
||||
{
|
||||
int i, j, k;
|
||||
GifPixelType *ScanLine;
|
||||
GifFileType *GifFile;
|
||||
GifColorType *ColorMap = NULL;
|
||||
#ifdef __MSDOS__
|
||||
static GifColorType MonoChromeColorMap[] = {
|
||||
{ 0, 0, 0 },
|
||||
{ 255, 255, 255 }
|
||||
};
|
||||
/* I have no idea what default EGA64 (4 colors) should be (I guessed...).*/
|
||||
static GifColorType EGA64ColorMap[] = {
|
||||
{ 0, 0, 0 }, /* 0. Black */
|
||||
{ 255, 0, 0 }, /* 1. Red */
|
||||
{ 0, 255, 0 }, /* 2. Green */
|
||||
{ 0, 0, 255 }, /* 3. Blue */
|
||||
};
|
||||
static GifColorType EGAColorMap[] = {
|
||||
{ 0, 0, 0 }, /* 0. Black */
|
||||
{ 0, 0, 170 }, /* 1. Blue */
|
||||
{ 0, 170, 0 }, /* 2. Green */
|
||||
{ 0, 170, 170 }, /* 3. Cyan */
|
||||
{ 170, 0, 0 }, /* 4. Red */
|
||||
{ 170, 0, 170 }, /* 5. Magenta */
|
||||
{ 170, 170, 0 }, /* 6. Brown */
|
||||
{ 170, 170, 170 }, /* 7. LightGray */
|
||||
{ 85, 85, 85 }, /* 8. DarkGray */
|
||||
{ 85, 85, 255 }, /* 9. LightBlue */
|
||||
{ 85, 255, 85 }, /* 10. LightGreen */
|
||||
{ 85, 255, 255 }, /* 11. LightCyan */
|
||||
{ 255, 85, 85 }, /* 12. LightRed */
|
||||
{ 255, 85, 255 }, /* 13. LightMagenta */
|
||||
{ 255, 255, 85 }, /* 14. Yellow */
|
||||
{ 255, 255, 255 }, /* 15. White */
|
||||
};
|
||||
#endif /* __MSDOS__ */
|
||||
#if defined(__SGI_GL__) || defined(__X11__)
|
||||
long *RGBBuffer;
|
||||
GifColorType ColorMap256[256];
|
||||
#endif
|
||||
#ifdef __X11__
|
||||
XImage *XImg;
|
||||
unsigned long XPixel;
|
||||
XColor XColorTable[256]; /* Up to 256 colors in X. */
|
||||
XWindowAttributes WinAttr;
|
||||
#endif /* __X11__ */
|
||||
|
||||
switch (ReqGraphDriver) { /* Return on non supported screens. */
|
||||
#ifdef __MSDOS__
|
||||
case HERCMONO:
|
||||
ScreenXMax = 720;
|
||||
ScreenYMax = 350;
|
||||
ScreenColorBits = 1;
|
||||
ScreenBase = 0xb000;
|
||||
ColorMap = MonoChromeColorMap;
|
||||
break;
|
||||
case EGA:
|
||||
switch (ReqGraphMode1) {
|
||||
case EGALO:
|
||||
ScreenYMax = 200;
|
||||
break;
|
||||
case EGAHI:
|
||||
ScreenYMax = 350;
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
ScreenXMax = 640;
|
||||
ScreenColorBits = 4;
|
||||
ScreenBase = 0xa000;
|
||||
ColorMap = EGAColorMap;
|
||||
break;
|
||||
case EGA64:
|
||||
switch (ReqGraphMode1) {
|
||||
case EGA64LO:
|
||||
ScreenYMax = 200;
|
||||
break;
|
||||
case EGA64HI:
|
||||
ScreenYMax = 350;
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
ScreenXMax = 640;
|
||||
ScreenColorBits = 2;
|
||||
ScreenBase = 0xa000;
|
||||
ColorMap = EGA64ColorMap;
|
||||
break;
|
||||
case EGAMONO:
|
||||
switch (ReqGraphMode1) {
|
||||
case EGAMONOHI:
|
||||
ScreenYMax = 350;
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
ScreenXMax = 640;
|
||||
ScreenColorBits = 1;
|
||||
ScreenBase = 0xa000;
|
||||
ColorMap = MonoChromeColorMap;
|
||||
break;
|
||||
case VGA:
|
||||
switch (ReqGraphMode1) {
|
||||
case VGALO:
|
||||
ScreenYMax = 200;
|
||||
break;
|
||||
case VGAMED:
|
||||
ScreenYMax = 350;
|
||||
break;
|
||||
case VGAHI:
|
||||
ScreenYMax = 480;
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
ScreenXMax = 640;
|
||||
ScreenColorBits = 4;
|
||||
ScreenBase = 0xa000;
|
||||
ColorMap = EGAColorMap;
|
||||
break;
|
||||
case SVGA_SPECIAL:
|
||||
ScreenXMax = 800;
|
||||
ScreenYMax = 600;
|
||||
ScreenColorBits = 4;
|
||||
ScreenBase = 0xa000;
|
||||
ColorMap = EGAColorMap;
|
||||
break;
|
||||
#endif /* __MSDOS__ */
|
||||
#ifdef __SGI_GL__
|
||||
case GIF_DUMP_SGI_WINDOW:
|
||||
winset(ReqGraphMode1); /* Select window as active window. */
|
||||
getsize(&ScreenXMax, &ScreenYMax);
|
||||
|
||||
RGBBuffer = (long *) malloc(sizeof(long) * ScreenXMax * ScreenYMax);
|
||||
readsource(SRC_FRONT);
|
||||
if (lrectread((short) 0,
|
||||
(short) 0,
|
||||
(short) (ScreenXMax - 1),
|
||||
(short) (ScreenYMax - 1), RGBBuffer) !=
|
||||
ScreenXMax * ScreenYMax) { /* Get data. */
|
||||
free(RGBBuffer);
|
||||
return -1;
|
||||
}
|
||||
GlblGifBuffer = (GifByteType *) malloc(sizeof(GifByteType) *
|
||||
ScreenXMax * ScreenYMax);
|
||||
i = QuantizeRGBBuffer(ScreenXMax, ScreenYMax, RGBBuffer,
|
||||
ColorMap256, GlblGifBuffer);
|
||||
/* Find minimum color map size to hold all quantized colors. */
|
||||
for (ScreenColorBits = 1;
|
||||
(1 << ScreenColorBits) < i && ScreenColorBits < 8;
|
||||
ScreenColorBits++);
|
||||
|
||||
/* Start to dump with top line as GIF expects it. */
|
||||
GlblGifBufferPtr = GlblGifBuffer + ScreenXMax * (ScreenYMax - 1);
|
||||
ColorMap = ColorMap256;
|
||||
free(RGBBuffer);
|
||||
break;
|
||||
#endif /* __SGI_GL__ */
|
||||
#ifdef __X11__
|
||||
case GIF_DUMP_X_WINDOW:
|
||||
XGetWindowAttributes((Display *) ReqGraphMode2,
|
||||
(Window) ReqGraphMode1,
|
||||
&WinAttr);
|
||||
ScreenXMax = WinAttr.width;
|
||||
ScreenYMax = WinAttr.height;
|
||||
|
||||
XImg = XGetImage((Display *) ReqGraphMode2,
|
||||
(Window) ReqGraphMode1,
|
||||
0, 0, ScreenXMax - 1, ScreenYMax - 1,
|
||||
AllPlanes, XYPixmap);
|
||||
|
||||
GlblGifBuffer = (GifByteType *) malloc(sizeof(GifByteType) *
|
||||
ScreenXMax * ScreenYMax);
|
||||
|
||||
/* Scan the image for all different colors exists. */
|
||||
for (i = 0; i < 256; i++) XColorTable[i].pixel = 0;
|
||||
k = FALSE;
|
||||
for (i = 0; i < ScreenXMax; i++)
|
||||
for (j = 0; j < ScreenYMax; j++) {
|
||||
XPixel = XGetPixel(XImg, i, j);
|
||||
if (XPixel > 255) {
|
||||
if (!k) {
|
||||
/* Make sure we state it once only.*/
|
||||
fprintf(stderr, "X Color table - truncated.\n");
|
||||
k = TRUE;
|
||||
}
|
||||
XPixel = 255;
|
||||
}
|
||||
XColorTable[XPixel].pixel = XPixel;
|
||||
}
|
||||
/* Find the RGB representation of the colors. */
|
||||
XQueryColors((Display *) ReqGraphMode2,
|
||||
(Colormap) ReqGraphMode3,
|
||||
XColorTable,
|
||||
256);
|
||||
/* Count number of active colors (Note color 0 is always in) */
|
||||
/* and create the Gif color map from it. */
|
||||
ColorMap = ColorMap256;
|
||||
ColorMap[0].Red = ColorMap[0].Green = ColorMap[0].Blue = 0;
|
||||
for (i = j = 1; i < 256; i++)
|
||||
if (XColorTable[i].pixel) {
|
||||
ColorMap[j].Red = XColorTable[i].red / 256;
|
||||
ColorMap[j].Green = XColorTable[i].green / 256;
|
||||
ColorMap[j].Blue = XColorTable[i].blue / 256;
|
||||
/* Save the X color index into the Gif table: */
|
||||
XColorTable[i].pixel = j++;
|
||||
}
|
||||
/* and set the number of colors in the Gif color map. */
|
||||
for (ScreenColorBits = 1;
|
||||
(1 << ScreenColorBits) < j && ScreenColorBits < 8;
|
||||
ScreenColorBits++);
|
||||
|
||||
/* Prepare the Gif image buffer as indices into the Gif color */
|
||||
/* map from the X image. */
|
||||
GlblGifBufferPtr = GlblGifBuffer;
|
||||
for (i = 0; i < ScreenXMax; i++)
|
||||
for (j = 0; j < ScreenYMax; j++)
|
||||
*GlblGifBufferPtr++ =
|
||||
XColorTable[XGetPixel(XImg, j, i) & 0xff].pixel;
|
||||
XDestroyImage(XImg);
|
||||
|
||||
GlblGifBufferPtr = GlblGifBuffer;
|
||||
ColorMap = ColorMap256;
|
||||
break;
|
||||
#endif /* __X11__ */
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
|
||||
ScanLine = (GifPixelType *) malloc(sizeof(GifPixelType) * ScreenXMax);
|
||||
|
||||
GraphDriver = ReqGraphDriver;
|
||||
GraphMode = ReqGraphMode1;
|
||||
|
||||
if ((GifFile = EGifOpenFileName(FileName, FALSE)) == NULL ||
|
||||
EGifPutScreenDesc(GifFile, ScreenXMax, ScreenYMax, ScreenColorBits,
|
||||
0, ScreenColorBits, ColorMap) == GIF_ERROR ||
|
||||
EGifPutImageDesc(GifFile, 0, 0, ScreenXMax, ScreenYMax, FALSE, 1,
|
||||
NULL) == GIF_ERROR) {
|
||||
free((char *) ScanLine);
|
||||
#if defined(__SGI_GL__) || defined(__X11__)
|
||||
free((char *) GlblGifBuffer);
|
||||
#endif
|
||||
return HandleGifError(GifFile);
|
||||
}
|
||||
|
||||
for (i = 0; i < ScreenYMax; i++) {
|
||||
GetScanLine(ScanLine, i);
|
||||
if (EGifPutLine(GifFile, ScanLine, ScreenXMax) == GIF_ERROR) {
|
||||
free((char *) ScanLine);
|
||||
#if defined(__SGI_GL__) || defined(__X11__)
|
||||
free((char *) GlblGifBuffer);
|
||||
#endif
|
||||
return HandleGifError(GifFile);
|
||||
}
|
||||
}
|
||||
|
||||
if (EGifCloseFile(GifFile) == GIF_ERROR) {
|
||||
free((char *) ScanLine);
|
||||
#if defined(__SGI_GL__) || defined(__X11__)
|
||||
free((char *) GlblGifBuffer);
|
||||
#endif
|
||||
return HandleGifError(GifFile);
|
||||
}
|
||||
|
||||
free((char *) ScanLine);
|
||||
#if defined(__SGI_GL__) || defined(__X11__)
|
||||
free((char *) GlblGifBuffer);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef __SGI_GL__
|
||||
/******************************************************************************
|
||||
* Quantize the given 24 bit (8 per RGB) into 256 colors. *
|
||||
******************************************************************************/
|
||||
static int QuantizeRGBBuffer(int Width, int Height, long *RGBBuffer,
|
||||
GifColorType *ColorMap, GifByteType *GIFBuffer)
|
||||
{
|
||||
int i;
|
||||
GifByteType *RedInput, *GreenInput, *BlueInput;
|
||||
|
||||
/* Convert the RGB Buffer into 3 seperated buffers: */
|
||||
RedInput = (GifByteType *) malloc(sizeof(GifByteType) * Width * Height);
|
||||
GreenInput = (GifByteType *) malloc(sizeof(GifByteType) * Width * Height);
|
||||
BlueInput = (GifByteType *) malloc(sizeof(GifByteType) * Width * Height);
|
||||
|
||||
for (i = 0; i < Width * Height; i++) {
|
||||
RedInput[i] = RGBBuffer[i] & 0xff;
|
||||
GreenInput[i] = (RGBBuffer[i] >> 8) & 0xff;
|
||||
BlueInput[i] = (RGBBuffer[i] >> 16) & 0xff;
|
||||
}
|
||||
for (i = 0; i < 256; i++)
|
||||
ColorMap[i].Red = ColorMap[i].Green = ColorMap[i].Blue = 0;
|
||||
|
||||
i = 256;
|
||||
QuantizeBuffer(Width, Height, &i,
|
||||
RedInput, GreenInput, BlueInput,
|
||||
GIFBuffer, ColorMap);
|
||||
|
||||
free(RedInput);
|
||||
free(GreenInput);
|
||||
free(BlueInput);
|
||||
|
||||
return i; /* Real number of colors in color table. */
|
||||
}
|
||||
#endif /* __SGI_GL__ */
|
||||
|
||||
/******************************************************************************
|
||||
* Update the given scan line buffer with the pixel levels of the Y line. *
|
||||
* This routine is device specific, so make sure you know was you are doing *
|
||||
******************************************************************************/
|
||||
static void GetScanLine(GifPixelType *ScanLine, int Y)
|
||||
{
|
||||
unsigned char ScreenByte;
|
||||
int i, j, k;
|
||||
unsigned int BufferOffset, Bit;
|
||||
#ifdef __MSDOS__
|
||||
union REGS InRegs, OutRegs;
|
||||
#endif /* __MSDOS__ */
|
||||
|
||||
switch (GraphDriver) {
|
||||
#ifdef __MSDOS__
|
||||
case HERCMONO:
|
||||
BufferOffset = 0x2000 * (Y % 4) + (Y / 4) * (ScreenXMax / 8);
|
||||
/* In one scan lines we have ScreenXMax / 8 bytes: */
|
||||
for (i = 0, k = 0; i < ScreenXMax / 8; i++) {
|
||||
ScreenByte = (unsigned char) peekb(ScreenBase, BufferOffset++);
|
||||
for (j = 0, Bit = 0x80; j < 8; j++) {
|
||||
ScanLine[k++] = (ScreenByte & Bit ? 1 : 0);
|
||||
Bit >>= 1;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case EGA:
|
||||
case EGA64:
|
||||
case EGAMONO:
|
||||
case VGA:
|
||||
case SVGA_SPECIAL:
|
||||
InRegs.x.dx = Y;
|
||||
InRegs.h.bh = 0;
|
||||
InRegs.h.ah = 0x0d; /* BIOS Read dot. */
|
||||
for (i = 0; i < ScreenXMax; i++) {
|
||||
InRegs.x.cx = i;
|
||||
int86(0x10, &InRegs, &OutRegs);
|
||||
ScanLine[i] = OutRegs.h.al;
|
||||
}
|
||||
|
||||
/* Makr this line as done by putting a xored dot on the left. */
|
||||
InRegs.x.dx = Y;
|
||||
InRegs.h.bh = 0;
|
||||
InRegs.h.ah = 0x0c; /* BIOS Write dot (xor mode). */
|
||||
InRegs.h.al = 0x81; /* Xor with color 1. */
|
||||
InRegs.x.cx = 0;
|
||||
int86(0x10, &InRegs, &OutRegs);
|
||||
InRegs.x.dx = Y;
|
||||
InRegs.h.bh = 0;
|
||||
InRegs.h.ah = 0x0c; /* BIOS Write dot (xor mode). */
|
||||
InRegs.h.al = 0x81; /* Xor with color 1. */
|
||||
InRegs.x.cx = 1;
|
||||
int86(0x10, &InRegs, &OutRegs);
|
||||
|
||||
if (Y == ScreenYMax - 1) {/* Last row - clear all marks we made. */
|
||||
for (i = 0; i < ScreenYMax; i++) {
|
||||
InRegs.h.bh = 0;
|
||||
InRegs.h.ah = 0x0c; /* BIOS Write dot (xor mode). */
|
||||
InRegs.h.al = 0x81; /* Xor back with color 1. */
|
||||
InRegs.x.dx = i;
|
||||
InRegs.x.cx = 0;
|
||||
int86(0x10, &InRegs, &OutRegs);
|
||||
InRegs.h.bh = 0;
|
||||
InRegs.h.ah = 0x0c; /* BIOS Write dot (xor mode). */
|
||||
InRegs.h.al = 0x81; /* Xor back with color 1. */
|
||||
InRegs.x.dx = i;
|
||||
InRegs.x.cx = 1;
|
||||
int86(0x10, &InRegs, &OutRegs);
|
||||
}
|
||||
}
|
||||
break;
|
||||
#endif /* __MSDOS__ */
|
||||
#ifdef __SGI_GL__
|
||||
case GIF_DUMP_SGI_WINDOW:
|
||||
memcpy(ScanLine, GlblGifBufferPtr, ScreenXMax * sizeof(GifPixelType));
|
||||
GlblGifBufferPtr -= ScreenXMax;
|
||||
break;
|
||||
#endif /* __SGI_GL__ */
|
||||
#ifdef __X11__
|
||||
case GIF_DUMP_X_WINDOW:
|
||||
memcpy(ScanLine, GlblGifBufferPtr, ScreenXMax * sizeof(GifPixelType));
|
||||
GlblGifBufferPtr += ScreenXMax;
|
||||
break;
|
||||
#endif /* __X11__ */
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* Handle last GIF error. Try to close the file and free all allocated memory. *
|
||||
******************************************************************************/
|
||||
static int HandleGifError(GifFileType *GifFile)
|
||||
{
|
||||
int i = GifLastError();
|
||||
|
||||
if (EGifCloseFile(GifFile) == GIF_ERROR) {
|
||||
GifLastError();
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
837
G/LIB/DGIF_LIB.C
Normal file
837
G/LIB/DGIF_LIB.C
Normal file
@ -0,0 +1,837 @@
|
||||
/******************************************************************************
|
||||
* "Gif-Lib" - Yet another gif library. *
|
||||
* *
|
||||
* Written by: Gershon Elber IBM PC Ver 1.1, Aug. 1990 *
|
||||
*******************************************************************************
|
||||
* The kernel of the GIF Decoding process can be found here. *
|
||||
*******************************************************************************
|
||||
* History: *
|
||||
* 16 Jun 89 - Version 1.0 by Gershon Elber. *
|
||||
* 3 Sep 90 - Version 1.1 by Gershon Elber (Support for Gif89, Unique names). *
|
||||
******************************************************************************/
|
||||
|
||||
|
||||
#ifdef __MSDOS__
|
||||
#include <io.h>
|
||||
#include <alloc.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys\stat.h>
|
||||
#else
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#endif /* __MSDOS__ */
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "gif_lib.h"
|
||||
#include "gif_hash.h"
|
||||
|
||||
#define PROGRAM_NAME "GIF_LIBRARY"
|
||||
|
||||
#define COMMENT_EXT_FUNC_CODE 0xfe /* Extension function code for comment. */
|
||||
#define GIF_STAMP "GIFVER" /* First chars in file - GIF stamp. */
|
||||
#define GIF_STAMP_LEN sizeof(GIF_STAMP) - 1
|
||||
#define GIF_VERSION_POS 3 /* Version first character in stamp. */
|
||||
|
||||
#define LZ_MAX_CODE 4095 /* Biggest code possible in 12 bits. */
|
||||
#define LZ_BITS 12
|
||||
|
||||
#define FILE_STATE_READ 0x01/* 1 write, 0 read - EGIF_LIB compatible.*/
|
||||
|
||||
#define FLUSH_OUTPUT 4096 /* Impossible code, to signal flush. */
|
||||
#define FIRST_CODE 4097 /* Impossible code, to signal first. */
|
||||
#define NO_SUCH_CODE 4098 /* Impossible code, to signal empty. */
|
||||
|
||||
#define IS_READABLE(Private) (!(Private -> FileState & FILE_STATE_READ))
|
||||
|
||||
typedef struct GifFilePrivateType {
|
||||
int FileState,
|
||||
FileHandle, /* Where all this data goes to! */
|
||||
BitsPerPixel, /* Bits per pixel (Codes uses at list this + 1). */
|
||||
ClearCode, /* The CLEAR LZ code. */
|
||||
EOFCode, /* The EOF LZ code. */
|
||||
RunningCode, /* The next code algorithm can generate. */
|
||||
RunningBits,/* The number of bits required to represent RunningCode. */
|
||||
MaxCode1, /* 1 bigger than max. possible code, in RunningBits bits. */
|
||||
LastCode, /* The code before the current code. */
|
||||
CrntCode, /* Current algorithm code. */
|
||||
StackPtr, /* For character stack (see below). */
|
||||
CrntShiftState; /* Number of bits in CrntShiftDWord. */
|
||||
unsigned long CrntShiftDWord, /* For bytes decomposition into codes. */
|
||||
PixelCount; /* Number of pixels in image. */
|
||||
FILE *File; /* File as stream. */
|
||||
GifByteType Buf[256]; /* Compressed input is buffered here. */
|
||||
GifByteType Stack[LZ_MAX_CODE]; /* Decoded pixels are stacked here. */
|
||||
GifByteType Suffix[LZ_MAX_CODE+1]; /* So we can trace the codes. */
|
||||
unsigned int Prefix[LZ_MAX_CODE+1];
|
||||
} GifFilePrivateType;
|
||||
|
||||
#ifdef SYSV
|
||||
static char *VersionStr =
|
||||
"Gif library module,\t\tGershon Elber\n\
|
||||
(C) Copyright 1989 Gershon Elber, Non commercial use only.\n";
|
||||
#else
|
||||
static char *VersionStr =
|
||||
PROGRAM_NAME
|
||||
" IBMPC "
|
||||
GIF_LIB_VERSION
|
||||
" Gershon Elber, "
|
||||
__DATE__ ", " __TIME__ "\n"
|
||||
"(C) Copyright 1989 Gershon Elber, Non commercial use only.\n";
|
||||
#endif /* SYSV */
|
||||
|
||||
extern int _GifError;
|
||||
|
||||
static int DGifGetWord(FILE *File, int *Word);
|
||||
static int DGifSetupDecompress(GifFileType *GifFile);
|
||||
static int DGifDecompressLine(GifFileType *GifFile, GifPixelType *Line,
|
||||
int LineLen);
|
||||
static int DGifGetPrefixChar(unsigned int *Prefix, int Code, int ClearCode);
|
||||
static int DGifDecompressInput(GifFilePrivateType *Private, int *Code);
|
||||
static int DGifBufferedInput(FILE *File, GifByteType *Buf,
|
||||
GifByteType *NextByte);
|
||||
|
||||
/******************************************************************************
|
||||
* Open a new gif file for read, given by its name. *
|
||||
* Returns GifFileType pointer dynamically allocated which serves as the gif *
|
||||
* info record. _GifError is cleared if succesfull. *
|
||||
******************************************************************************/
|
||||
GifFileType *DGifOpenFileName(char *FileName)
|
||||
{
|
||||
int FileHandle;
|
||||
|
||||
if ((FileHandle = open(FileName, O_RDONLY
|
||||
#ifdef __MSDOS__
|
||||
| O_BINARY
|
||||
#endif /* __MSDOS__ */
|
||||
)) == -1) {
|
||||
_GifError = D_GIF_ERR_OPEN_FAILED;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return DGifOpenFileHandle(FileHandle);
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* Update a new gif file, given its file handle. *
|
||||
* Returns GifFileType pointer dynamically allocated which serves as the gif *
|
||||
* info record. _GifError is cleared if succesfull. *
|
||||
******************************************************************************/
|
||||
GifFileType *DGifOpenFileHandle(int FileHandle)
|
||||
{
|
||||
char Buf[GIF_STAMP_LEN+1];
|
||||
GifFileType *GifFile;
|
||||
GifFilePrivateType *Private;
|
||||
FILE *f;
|
||||
|
||||
#ifdef __MSDOS__
|
||||
setmode(FileHandle, O_BINARY); /* Make sure it is in binary mode. */
|
||||
f = fdopen(FileHandle, "rb"); /* Make it into a stream: */
|
||||
setvbuf(f, NULL, _IOFBF, GIF_FILE_BUFFER_SIZE);/* And inc. stream buffer.*/
|
||||
#else
|
||||
f = fdopen(FileHandle, "r"); /* Make it into a stream: */
|
||||
#endif /* __MSDOS__ */
|
||||
|
||||
if ((GifFile = (GifFileType *) malloc(sizeof(GifFileType))) == NULL) {
|
||||
_GifError = D_GIF_ERR_NOT_ENOUGH_MEM;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if ((Private = (GifFilePrivateType *) malloc(sizeof(GifFilePrivateType)))
|
||||
== NULL) {
|
||||
_GifError = D_GIF_ERR_NOT_ENOUGH_MEM;
|
||||
free((char *) GifFile);
|
||||
return NULL;
|
||||
}
|
||||
GifFile -> Private = (VoidPtr) Private;
|
||||
GifFile -> SColorMap = GifFile -> IColorMap = NULL;
|
||||
Private -> FileHandle = FileHandle;
|
||||
Private -> File = f;
|
||||
Private -> FileState = 0; /* Make sure bit 0 = 0 (File open for read). */
|
||||
|
||||
/* Lets see if this is GIF file: */
|
||||
if (fread(Buf, 1, GIF_STAMP_LEN, Private -> File) != GIF_STAMP_LEN) {
|
||||
_GifError = D_GIF_ERR_READ_FAILED;
|
||||
free((char *) Private);
|
||||
free((char *) GifFile);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* The GIF Version number is ignored at this time. Maybe we should do */
|
||||
/* something more useful with it. */
|
||||
Buf[GIF_STAMP_LEN] = 0;
|
||||
if (strncmp(GIF_STAMP, Buf, GIF_VERSION_POS) != 0) {
|
||||
_GifError = D_GIF_ERR_NOT_GIF_FILE;
|
||||
free((char *) Private);
|
||||
free((char *) GifFile);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (DGifGetScreenDesc(GifFile) == GIF_ERROR) {
|
||||
free((char *) Private);
|
||||
free((char *) GifFile);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
_GifError = 0;
|
||||
|
||||
return GifFile;
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* This routine should be called before any other DGif calls. Note that *
|
||||
* this routine is called automatically from DGif file open routines. *
|
||||
******************************************************************************/
|
||||
int DGifGetScreenDesc(GifFileType *GifFile)
|
||||
{
|
||||
int Size, i;
|
||||
GifByteType Buf[3];
|
||||
GifFilePrivateType *Private = (GifFilePrivateType *) GifFile -> Private;
|
||||
|
||||
if (!IS_READABLE(Private)) {
|
||||
/* This file was NOT open for reading: */
|
||||
_GifError = D_GIF_ERR_NOT_READABLE;
|
||||
return GIF_ERROR;
|
||||
}
|
||||
|
||||
/* Put the screen descriptor into the file: */
|
||||
if (DGifGetWord(Private -> File, &GifFile -> SWidth) == GIF_ERROR ||
|
||||
DGifGetWord(Private -> File, &GifFile -> SHeight) == GIF_ERROR)
|
||||
return GIF_ERROR;
|
||||
|
||||
if (fread(Buf, 1, 3, Private -> File) != 3) {
|
||||
_GifError = D_GIF_ERR_READ_FAILED;
|
||||
return GIF_ERROR;
|
||||
}
|
||||
GifFile -> SColorResolution = (((Buf[0] & 0x70) + 1) >> 4) + 1;
|
||||
GifFile -> SBitsPerPixel = (Buf[0] & 0x07) + 1;
|
||||
GifFile -> SBackGroundColor = Buf[1];
|
||||
if (Buf[0] & 0x80) { /* Do we have global color map? */
|
||||
Size = (1 << GifFile -> SBitsPerPixel);
|
||||
GifFile -> SColorMap =
|
||||
(GifColorType *) malloc(sizeof(GifColorType) * Size);
|
||||
for (i = 0; i < Size; i++) { /* Get the global color map: */
|
||||
if (fread(Buf, 1, 3, Private -> File) != 3) {
|
||||
_GifError = D_GIF_ERR_READ_FAILED;
|
||||
return GIF_ERROR;
|
||||
}
|
||||
GifFile -> SColorMap[i].Red = Buf[0];
|
||||
GifFile -> SColorMap[i].Green = Buf[1];
|
||||
GifFile -> SColorMap[i].Blue = Buf[2];
|
||||
}
|
||||
}
|
||||
|
||||
return GIF_OK;
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* This routine should be called before any attemp to read an image. *
|
||||
******************************************************************************/
|
||||
int DGifGetRecordType(GifFileType *GifFile, GifRecordType *Type)
|
||||
{
|
||||
GifByteType Buf;
|
||||
GifFilePrivateType *Private = (GifFilePrivateType *) GifFile -> Private;
|
||||
|
||||
if (!IS_READABLE(Private)) {
|
||||
/* This file was NOT open for reading: */
|
||||
_GifError = D_GIF_ERR_NOT_READABLE;
|
||||
return GIF_ERROR;
|
||||
}
|
||||
|
||||
if (fread(&Buf, 1, 1, Private -> File) != 1) {
|
||||
_GifError = D_GIF_ERR_READ_FAILED;
|
||||
return GIF_ERROR;
|
||||
}
|
||||
|
||||
switch (Buf) {
|
||||
case ',':
|
||||
*Type = IMAGE_DESC_RECORD_TYPE;
|
||||
break;
|
||||
case '!':
|
||||
*Type = EXTENSION_RECORD_TYPE;
|
||||
break;
|
||||
case ';':
|
||||
*Type = TERMINATE_RECORD_TYPE;
|
||||
break;
|
||||
default:
|
||||
*Type = UNDEFINED_RECORD_TYPE;
|
||||
_GifError = D_GIF_ERR_WRONG_RECORD;
|
||||
return GIF_ERROR;
|
||||
}
|
||||
|
||||
return GIF_OK;
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* This routine should be called before any attemp to read an image. *
|
||||
* Note it is assumed the Image desc. header (',') has been read. *
|
||||
******************************************************************************/
|
||||
int DGifGetImageDesc(GifFileType *GifFile)
|
||||
{
|
||||
int Size, i;
|
||||
GifByteType Buf[3];
|
||||
GifFilePrivateType *Private = (GifFilePrivateType *) GifFile -> Private;
|
||||
|
||||
if (!IS_READABLE(Private)) {
|
||||
/* This file was NOT open for reading: */
|
||||
_GifError = D_GIF_ERR_NOT_READABLE;
|
||||
return GIF_ERROR;
|
||||
}
|
||||
|
||||
if (DGifGetWord(Private -> File, &GifFile -> ILeft) == GIF_ERROR ||
|
||||
DGifGetWord(Private -> File, &GifFile -> ITop) == GIF_ERROR ||
|
||||
DGifGetWord(Private -> File, &GifFile -> IWidth) == GIF_ERROR ||
|
||||
DGifGetWord(Private -> File, &GifFile -> IHeight) == GIF_ERROR)
|
||||
return GIF_ERROR;
|
||||
if (fread(Buf, 1, 1, Private -> File) != 1) {
|
||||
_GifError = D_GIF_ERR_READ_FAILED;
|
||||
return GIF_ERROR;
|
||||
}
|
||||
GifFile -> IBitsPerPixel = (Buf[0] & 0x07) + 1;
|
||||
GifFile -> IInterlace = (Buf[0] & 0x40);
|
||||
if (Buf[0] & 0x80) { /* Does this image have local color map? */
|
||||
Size = (1 << GifFile -> IBitsPerPixel);
|
||||
if (GifFile -> IColorMap) free((char *) GifFile -> IColorMap);
|
||||
GifFile -> IColorMap =
|
||||
(GifColorType *) malloc(sizeof(GifColorType) * Size);
|
||||
for (i = 0; i < Size; i++) { /* Get the image local color map: */
|
||||
if (fread(Buf, 1, 3, Private -> File) != 3) {
|
||||
_GifError = D_GIF_ERR_READ_FAILED;
|
||||
return GIF_ERROR;
|
||||
}
|
||||
GifFile -> IColorMap[i].Red = Buf[0];
|
||||
GifFile -> IColorMap[i].Green = Buf[1];
|
||||
GifFile -> IColorMap[i].Blue = Buf[2];
|
||||
}
|
||||
}
|
||||
|
||||
Private -> PixelCount = (long) GifFile -> IWidth *
|
||||
(long) GifFile -> IHeight;
|
||||
|
||||
DGifSetupDecompress(GifFile); /* Reset decompress algorithm parameters. */
|
||||
|
||||
return GIF_OK;
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* Get one full scanned line (Line) of length LineLen from GIF file. *
|
||||
******************************************************************************/
|
||||
int DGifGetLine(GifFileType *GifFile, GifPixelType *Line, int LineLen)
|
||||
{
|
||||
GifByteType *Dummy;
|
||||
GifFilePrivateType *Private = (GifFilePrivateType *) GifFile -> Private;
|
||||
|
||||
if (!IS_READABLE(Private)) {
|
||||
/* This file was NOT open for reading: */
|
||||
_GifError = D_GIF_ERR_NOT_READABLE;
|
||||
return GIF_ERROR;
|
||||
}
|
||||
|
||||
if (!LineLen) LineLen = GifFile -> IWidth;
|
||||
|
||||
#ifdef __MSDOS__
|
||||
if ((Private -> PixelCount -= LineLen) > 0xffff0000UL) {
|
||||
#else
|
||||
if ((Private -> PixelCount -= LineLen) > 0xffff0000) {
|
||||
#endif /* __MSDOS__ */
|
||||
_GifError = D_GIF_ERR_DATA_TOO_BIG;
|
||||
return GIF_ERROR;
|
||||
}
|
||||
|
||||
if (DGifDecompressLine(GifFile, Line, LineLen) == GIF_OK) {
|
||||
if (Private -> PixelCount == 0) {
|
||||
/* We probably would not be called any more, so lets clean */
|
||||
/* everything before we return: need to flush out all rest of */
|
||||
/* image until empty block (size 0) detected. We use GetCodeNext.*/
|
||||
do if (DGifGetCodeNext(GifFile, &Dummy) == GIF_ERROR)
|
||||
return GIF_ERROR;
|
||||
while (Dummy != NULL);
|
||||
}
|
||||
return GIF_OK;
|
||||
}
|
||||
else
|
||||
return GIF_ERROR;
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* Put one pixel (Pixel) into GIF file. *
|
||||
******************************************************************************/
|
||||
int DGifGetPixel(GifFileType *GifFile, GifPixelType Pixel)
|
||||
{
|
||||
GifByteType *Dummy;
|
||||
GifFilePrivateType *Private = (GifFilePrivateType *) GifFile -> Private;
|
||||
|
||||
if (!IS_READABLE(Private)) {
|
||||
/* This file was NOT open for reading: */
|
||||
_GifError = D_GIF_ERR_NOT_READABLE;
|
||||
return GIF_ERROR;
|
||||
}
|
||||
|
||||
#ifdef __MSDOS__
|
||||
if (--Private -> PixelCount > 0xffff0000UL)
|
||||
#else
|
||||
if (--Private -> PixelCount > 0xffff0000)
|
||||
#endif /* __MSDOS__ */
|
||||
{
|
||||
_GifError = D_GIF_ERR_DATA_TOO_BIG;
|
||||
return GIF_ERROR;
|
||||
}
|
||||
|
||||
if (DGifDecompressLine(GifFile, &Pixel, 1) == GIF_OK) {
|
||||
if (Private -> PixelCount == 0) {
|
||||
/* We probably would not be called any more, so lets clean */
|
||||
/* everything before we return: need to flush out all rest of */
|
||||
/* image until empty block (size 0) detected. We use GetCodeNext.*/
|
||||
do if (DGifGetCodeNext(GifFile, &Dummy) == GIF_ERROR)
|
||||
return GIF_ERROR;
|
||||
while (Dummy != NULL);
|
||||
}
|
||||
return GIF_OK;
|
||||
}
|
||||
else
|
||||
return GIF_ERROR;
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* Get an extension block (see GIF manual) from gif file. This routine only *
|
||||
* returns the first data block, and DGifGetExtensionNext shouldbe called *
|
||||
* after this one until NULL extension is returned. *
|
||||
* The Extension should NOT be freed by the user (not dynamically allocated).*
|
||||
* Note it is assumed the Extension desc. header ('!') has been read. *
|
||||
******************************************************************************/
|
||||
int DGifGetExtension(GifFileType *GifFile, int *ExtCode,
|
||||
GifByteType **Extension)
|
||||
{
|
||||
GifByteType Buf;
|
||||
GifFilePrivateType *Private = (GifFilePrivateType *) GifFile -> Private;
|
||||
|
||||
if (!IS_READABLE(Private)) {
|
||||
/* This file was NOT open for reading: */
|
||||
_GifError = D_GIF_ERR_NOT_READABLE;
|
||||
return GIF_ERROR;
|
||||
}
|
||||
|
||||
if (fread(&Buf, 1, 1, Private -> File) != 1) {
|
||||
_GifError = D_GIF_ERR_READ_FAILED;
|
||||
return GIF_ERROR;
|
||||
}
|
||||
*ExtCode = Buf;
|
||||
|
||||
return DGifGetExtensionNext(GifFile, Extension);
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* Get a following extension block (see GIF manual) from gif file. This *
|
||||
* routine sould be called until NULL Extension is returned. *
|
||||
* The Extension should NOT be freed by the user (not dynamically allocated).*
|
||||
******************************************************************************/
|
||||
int DGifGetExtensionNext(GifFileType *GifFile, GifByteType **Extension)
|
||||
{
|
||||
GifByteType Buf;
|
||||
GifFilePrivateType *Private = (GifFilePrivateType *) GifFile -> Private;
|
||||
|
||||
if (fread(&Buf, 1, 1, Private -> File) != 1) {
|
||||
_GifError = D_GIF_ERR_READ_FAILED;
|
||||
return GIF_ERROR;
|
||||
}
|
||||
if (Buf > 0) {
|
||||
*Extension = Private -> Buf; /* Use private unused buffer. */
|
||||
(*Extension)[0] = Buf; /* Pascal strings notation (pos. 0 is len.). */
|
||||
if (fread(&((*Extension)[1]), 1, Buf, Private -> File) != Buf) {
|
||||
_GifError = D_GIF_ERR_READ_FAILED;
|
||||
return GIF_ERROR;
|
||||
}
|
||||
}
|
||||
else
|
||||
*Extension = NULL;
|
||||
|
||||
return GIF_OK;
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* This routine should be called last, to close GIF file. *
|
||||
******************************************************************************/
|
||||
int DGifCloseFile(GifFileType *GifFile)
|
||||
{
|
||||
GifFilePrivateType *Private;
|
||||
FILE *File;
|
||||
|
||||
if (GifFile == NULL) return GIF_ERROR;
|
||||
|
||||
Private = (GifFilePrivateType *) GifFile -> Private;
|
||||
|
||||
if (!IS_READABLE(Private)) {
|
||||
/* This file was NOT open for reading: */
|
||||
_GifError = D_GIF_ERR_NOT_READABLE;
|
||||
return GIF_ERROR;
|
||||
}
|
||||
|
||||
File = Private -> File;
|
||||
|
||||
if (GifFile -> IColorMap) free((char *) GifFile -> IColorMap);
|
||||
if (GifFile -> SColorMap) free((char *) GifFile -> SColorMap);
|
||||
if (Private) free((char *) Private);
|
||||
free(GifFile);
|
||||
|
||||
if (fclose(File) != 0) {
|
||||
_GifError = D_GIF_ERR_CLOSE_FAILED;
|
||||
return GIF_ERROR;
|
||||
}
|
||||
return GIF_OK;
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* Get 2 bytes (word) from the given file: *
|
||||
******************************************************************************/
|
||||
static int DGifGetWord(FILE *File, int *Word)
|
||||
{
|
||||
unsigned char c[2];
|
||||
|
||||
if (fread(c, 1, 2, File) != 2) {
|
||||
_GifError = D_GIF_ERR_READ_FAILED;
|
||||
return GIF_ERROR;
|
||||
}
|
||||
|
||||
*Word = (((unsigned int) c[1]) << 8) + c[0];
|
||||
return GIF_OK;
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* Get the image code in compressed form. his routine can be called if the *
|
||||
* information needed to be piped out as is. Obviously this is much faster *
|
||||
* than decoding and encoding again. This routine should be followed by calls *
|
||||
* to DGifGetCodeNext, until NULL block is returned. *
|
||||
* The block should NOT be freed by the user (not dynamically allocated). *
|
||||
******************************************************************************/
|
||||
int DGifGetCode(GifFileType *GifFile, int *CodeSize, GifByteType **CodeBlock)
|
||||
{
|
||||
GifFilePrivateType *Private = (GifFilePrivateType *) GifFile -> Private;
|
||||
|
||||
if (!IS_READABLE(Private)) {
|
||||
/* This file was NOT open for reading: */
|
||||
_GifError = D_GIF_ERR_NOT_READABLE;
|
||||
return GIF_ERROR;
|
||||
}
|
||||
|
||||
*CodeSize = Private -> BitsPerPixel;
|
||||
|
||||
return DGifGetCodeNext(GifFile, CodeBlock);
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* Continue to get the image code in compressed form. This routine should be *
|
||||
* called until NULL block is returned. *
|
||||
* The block should NOT be freed by the user (not dynamically allocated). *
|
||||
******************************************************************************/
|
||||
int DGifGetCodeNext(GifFileType *GifFile, GifByteType **CodeBlock)
|
||||
{
|
||||
GifByteType Buf;
|
||||
GifFilePrivateType *Private = (GifFilePrivateType *) GifFile -> Private;
|
||||
|
||||
if (fread(&Buf, 1, 1, Private -> File) != 1) {
|
||||
_GifError = D_GIF_ERR_READ_FAILED;
|
||||
return GIF_ERROR;
|
||||
}
|
||||
|
||||
if (Buf > 0) {
|
||||
*CodeBlock = Private -> Buf; /* Use private unused buffer. */
|
||||
(*CodeBlock)[0] = Buf; /* Pascal strings notation (pos. 0 is len.). */
|
||||
if (fread(&((*CodeBlock)[1]), 1, Buf, Private -> File) != Buf) {
|
||||
_GifError = D_GIF_ERR_READ_FAILED;
|
||||
return GIF_ERROR;
|
||||
}
|
||||
}
|
||||
else {
|
||||
*CodeBlock = NULL;
|
||||
Private -> Buf[0] = 0; /* Make sure the buffer is empty! */
|
||||
Private -> PixelCount = 0; /* And local info. indicate image read. */
|
||||
}
|
||||
|
||||
return GIF_OK;
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* Setup the LZ decompression for this image: *
|
||||
******************************************************************************/
|
||||
static int DGifSetupDecompress(GifFileType *GifFile)
|
||||
{
|
||||
int i, BitsPerPixel;
|
||||
GifByteType CodeSize;
|
||||
unsigned int *Prefix;
|
||||
GifFilePrivateType *Private = (GifFilePrivateType *) GifFile -> Private;
|
||||
|
||||
fread(&CodeSize, 1, 1, Private -> File); /* Read Code size from file. */
|
||||
BitsPerPixel = CodeSize;
|
||||
|
||||
Private -> Buf[0] = 0; /* Input Buffer empty. */
|
||||
Private -> BitsPerPixel = BitsPerPixel;
|
||||
Private -> ClearCode = (1 << BitsPerPixel);
|
||||
Private -> EOFCode = Private -> ClearCode + 1;
|
||||
Private -> RunningCode = Private -> EOFCode + 1;
|
||||
Private -> RunningBits = BitsPerPixel + 1; /* Number of bits per code. */
|
||||
Private -> MaxCode1 = 1 << Private -> RunningBits; /* Max. code + 1. */
|
||||
Private -> StackPtr = 0; /* No pixels on the pixel stack. */
|
||||
Private -> LastCode = NO_SUCH_CODE;
|
||||
Private -> CrntShiftState = 0; /* No information in CrntShiftDWord. */
|
||||
Private -> CrntShiftDWord = 0;
|
||||
|
||||
Prefix = Private -> Prefix;
|
||||
for (i = 0; i <= LZ_MAX_CODE; i++) Prefix[i] = NO_SUCH_CODE;
|
||||
|
||||
return GIF_OK;
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* The LZ decompression routine: *
|
||||
* This version decompress the given gif file into Line of length LineLen. *
|
||||
* This routine can be called few times (one per scan line, for example), in *
|
||||
* order the complete the whole image. *
|
||||
******************************************************************************/
|
||||
static int DGifDecompressLine(GifFileType *GifFile, GifPixelType *Line,
|
||||
int LineLen)
|
||||
{
|
||||
int i = 0, j, CrntCode, EOFCode, ClearCode, CrntPrefix, LastCode, StackPtr;
|
||||
GifByteType *Stack, *Suffix;
|
||||
unsigned int *Prefix;
|
||||
GifFilePrivateType *Private = (GifFilePrivateType *) GifFile -> Private;
|
||||
|
||||
StackPtr = Private -> StackPtr;
|
||||
Prefix = Private -> Prefix;
|
||||
Suffix = Private -> Suffix;
|
||||
Stack = Private -> Stack;
|
||||
EOFCode = Private -> EOFCode;
|
||||
ClearCode = Private -> ClearCode;
|
||||
LastCode = Private -> LastCode;
|
||||
|
||||
if (StackPtr != 0) {
|
||||
/* Let pop the stack off before continueing to read the gif file: */
|
||||
while (StackPtr != 0 && i < LineLen) Line[i++] = Stack[--StackPtr];
|
||||
}
|
||||
|
||||
while (i < LineLen) { /* Decode LineLen items. */
|
||||
if (DGifDecompressInput(Private, &CrntCode) == GIF_ERROR)
|
||||
return GIF_ERROR;
|
||||
|
||||
if (CrntCode == EOFCode) {
|
||||
/* Note however that usually we will not be here as we will stop */
|
||||
/* decoding as soon as we got all the pixel, or EOF code will */
|
||||
/* not be read at all, and DGifGetLine/Pixel clean everything. */
|
||||
if (i != LineLen - 1 || Private -> PixelCount != 0) {
|
||||
_GifError = D_GIF_ERR_EOF_TOO_SOON;
|
||||
return GIF_ERROR;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
else if (CrntCode == ClearCode) {
|
||||
/* We need to start over again: */
|
||||
for (j = 0; j <= LZ_MAX_CODE; j++) Prefix[j] = NO_SUCH_CODE;
|
||||
Private -> RunningCode = Private -> EOFCode + 1;
|
||||
Private -> RunningBits = Private -> BitsPerPixel + 1;
|
||||
Private -> MaxCode1 = 1 << Private -> RunningBits;
|
||||
LastCode = Private -> LastCode = NO_SUCH_CODE;
|
||||
}
|
||||
else {
|
||||
/* Its regular code - if in pixel range simply add it to output */
|
||||
/* stream, otherwise trace to codes linked list until the prefix */
|
||||
/* is in pixel range: */
|
||||
if (CrntCode < ClearCode) {
|
||||
/* This is simple - its pixel scalar, so add it to output: */
|
||||
Line[i++] = CrntCode;
|
||||
}
|
||||
else {
|
||||
/* Its a code to needed to be traced: trace the linked list */
|
||||
/* until the prefix is a pixel, while pushing the suffix */
|
||||
/* pixels on our stack. If we done, pop the stack in reverse */
|
||||
/* (thats what stack is good for!) order to output. */
|
||||
if (Prefix[CrntCode] == NO_SUCH_CODE) {
|
||||
/* Only allowed if CrntCode is exactly the running code: */
|
||||
/* In that case CrntCode = XXXCode, CrntCode or the */
|
||||
/* prefix code is last code and the suffix char is */
|
||||
/* exactly the prefix of last code! */
|
||||
if (CrntCode == Private -> RunningCode - 2) {
|
||||
CrntPrefix = LastCode;
|
||||
Suffix[Private -> RunningCode - 2] =
|
||||
Stack[StackPtr++] = DGifGetPrefixChar(Prefix,
|
||||
LastCode, ClearCode);
|
||||
}
|
||||
else {
|
||||
_GifError = D_GIF_ERR_IMAGE_DEFECT;
|
||||
return GIF_ERROR;
|
||||
}
|
||||
}
|
||||
else
|
||||
CrntPrefix = CrntCode;
|
||||
|
||||
/* Now (if image is O.K.) we should not get an NO_SUCH_CODE */
|
||||
/* During the trace. As we might loop forever, in case of */
|
||||
/* defective image, we count the number of loops we trace */
|
||||
/* and stop if we got LZ_MAX_CODE. obviously we can not */
|
||||
/* loop more than that. */
|
||||
j = 0;
|
||||
while (j++ <= LZ_MAX_CODE &&
|
||||
CrntPrefix > ClearCode &&
|
||||
CrntPrefix <= LZ_MAX_CODE) {
|
||||
Stack[StackPtr++] = Suffix[CrntPrefix];
|
||||
CrntPrefix = Prefix[CrntPrefix];
|
||||
}
|
||||
if (j >= LZ_MAX_CODE || CrntPrefix > LZ_MAX_CODE) {
|
||||
_GifError = D_GIF_ERR_IMAGE_DEFECT;
|
||||
return GIF_ERROR;
|
||||
}
|
||||
/* Push the last character on stack: */
|
||||
Stack[StackPtr++] = CrntPrefix;
|
||||
|
||||
/* Now lets pop all the stack into output: */
|
||||
while (StackPtr != 0 && i < LineLen)
|
||||
Line[i++] = Stack[--StackPtr];
|
||||
}
|
||||
if (LastCode != NO_SUCH_CODE) {
|
||||
Prefix[Private -> RunningCode - 2] = LastCode;
|
||||
|
||||
if (CrntCode == Private -> RunningCode - 2) {
|
||||
/* Only allowed if CrntCode is exactly the running code: */
|
||||
/* In that case CrntCode = XXXCode, CrntCode or the */
|
||||
/* prefix code is last code and the suffix char is */
|
||||
/* exactly the prefix of last code! */
|
||||
Suffix[Private -> RunningCode - 2] =
|
||||
DGifGetPrefixChar(Prefix, LastCode, ClearCode);
|
||||
}
|
||||
else {
|
||||
Suffix[Private -> RunningCode - 2] =
|
||||
DGifGetPrefixChar(Prefix, CrntCode, ClearCode);
|
||||
}
|
||||
}
|
||||
LastCode = CrntCode;
|
||||
}
|
||||
}
|
||||
|
||||
Private -> LastCode = LastCode;
|
||||
Private -> StackPtr = StackPtr;
|
||||
|
||||
return GIF_OK;
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* Routine to trace the Prefixes linked list until we get a prefix which is *
|
||||
* not code, but a pixel value (less than ClearCode). Returns that pixel value.*
|
||||
* If image is defective, we might loop here forever, so we limit the loops to *
|
||||
* the maximum possible if image O.k. - LZ_MAX_CODE times. *
|
||||
******************************************************************************/
|
||||
static int DGifGetPrefixChar(unsigned int *Prefix, int Code, int ClearCode)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
while (Code > ClearCode && i++ <= LZ_MAX_CODE) Code = Prefix[Code];
|
||||
return Code;
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* Interface for accessing the LZ codes directly. Set Code to the real code *
|
||||
* (12bits), or to -1 if EOF code is returned. *
|
||||
******************************************************************************/
|
||||
int DGifGetLZCodes(GifFileType *GifFile, int *Code)
|
||||
{
|
||||
GifByteType *CodeBlock;
|
||||
GifFilePrivateType *Private = (GifFilePrivateType *) GifFile -> Private;
|
||||
|
||||
if (!IS_READABLE(Private)) {
|
||||
/* This file was NOT open for reading: */
|
||||
_GifError = D_GIF_ERR_NOT_READABLE;
|
||||
return GIF_ERROR;
|
||||
}
|
||||
|
||||
if (DGifDecompressInput(Private, Code) == GIF_ERROR)
|
||||
return GIF_ERROR;
|
||||
|
||||
if (*Code == Private -> EOFCode) {
|
||||
/* Skip rest of codes (hopefully only NULL terminating block): */
|
||||
do if (DGifGetCodeNext(GifFile, &CodeBlock) == GIF_ERROR)
|
||||
return GIF_ERROR;
|
||||
while (CodeBlock != NULL);
|
||||
|
||||
*Code = -1;
|
||||
}
|
||||
else if (*Code == Private -> ClearCode) {
|
||||
/* We need to start over again: */
|
||||
Private -> RunningCode = Private -> EOFCode + 1;
|
||||
Private -> RunningBits = Private -> BitsPerPixel + 1;
|
||||
Private -> MaxCode1 = 1 << Private -> RunningBits;
|
||||
}
|
||||
|
||||
return GIF_OK;
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* The LZ decompression input routine: *
|
||||
* This routine is responsable for the decompression of the bit stream from *
|
||||
* 8 bits (bytes) packets, into the real codes. *
|
||||
* Returns GIF_OK if read succesfully. *
|
||||
******************************************************************************/
|
||||
static int DGifDecompressInput(GifFilePrivateType *Private, int *Code)
|
||||
{
|
||||
GifByteType NextByte;
|
||||
static unsigned int CodeMasks[] = {
|
||||
0x0000, 0x0001, 0x0003, 0x0007,
|
||||
0x000f, 0x001f, 0x003f, 0x007f,
|
||||
0x00ff, 0x01ff, 0x03ff, 0x07ff,
|
||||
0x0fff
|
||||
};
|
||||
|
||||
while (Private -> CrntShiftState < Private -> RunningBits) {
|
||||
/* Needs to get more bytes from input stream for next code: */
|
||||
if (DGifBufferedInput(Private -> File, Private -> Buf, &NextByte)
|
||||
== GIF_ERROR) {
|
||||
return GIF_ERROR;
|
||||
}
|
||||
Private -> CrntShiftDWord |=
|
||||
((unsigned long) NextByte) << Private -> CrntShiftState;
|
||||
Private -> CrntShiftState += 8;
|
||||
}
|
||||
*Code = Private -> CrntShiftDWord & CodeMasks[Private -> RunningBits];
|
||||
|
||||
Private -> CrntShiftDWord >>= Private -> RunningBits;
|
||||
Private -> CrntShiftState -= Private -> RunningBits;
|
||||
|
||||
/* If code cannt fit into RunningBits bits, must raise its size. Note */
|
||||
/* however that codes above 4095 are used for special signaling. */
|
||||
if (++Private -> RunningCode > Private -> MaxCode1 &&
|
||||
Private -> RunningBits < LZ_BITS) {
|
||||
Private -> MaxCode1 <<= 1;
|
||||
Private -> RunningBits++;
|
||||
}
|
||||
return GIF_OK;
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* This routines read one gif data block at a time and buffers it internally *
|
||||
* so that the decompression routine could access it. *
|
||||
* The routine returns the next byte from its internal buffer (or read next *
|
||||
* block in if buffer empty) and returns GIF_OK if succesful. *
|
||||
******************************************************************************/
|
||||
static int DGifBufferedInput(FILE *File, GifByteType *Buf,
|
||||
GifByteType *NextByte)
|
||||
{
|
||||
if (Buf[0] == 0) {
|
||||
/* Needs to read the next buffer - this one is empty: */
|
||||
if (fread(Buf, 1, 1, File) != 1)
|
||||
{
|
||||
_GifError = D_GIF_ERR_READ_FAILED;
|
||||
return GIF_ERROR;
|
||||
}
|
||||
if (fread(&Buf[1], 1, Buf[0], File) != Buf[0])
|
||||
{
|
||||
_GifError = D_GIF_ERR_READ_FAILED;
|
||||
return GIF_ERROR;
|
||||
}
|
||||
*NextByte = Buf[1];
|
||||
Buf[1] = 2; /* We use now the second place as last char read! */
|
||||
Buf[0]--;
|
||||
}
|
||||
else {
|
||||
*NextByte = Buf[Buf[1]++];
|
||||
Buf[0]--;
|
||||
}
|
||||
|
||||
return GIF_OK;
|
||||
}
|
774
G/LIB/EGIF_LIB.C
Normal file
774
G/LIB/EGIF_LIB.C
Normal file
@ -0,0 +1,774 @@
|
||||
/******************************************************************************
|
||||
* "Gif-Lib" - Yet another gif library. *
|
||||
* *
|
||||
* Written by: Gershon Elber Ver 1.1, Aug. 1990 *
|
||||
*******************************************************************************
|
||||
* The kernel of the GIF Encoding process can be found here. *
|
||||
*******************************************************************************
|
||||
* History: *
|
||||
* 14 Jun 89 - Version 1.0 by Gershon Elber. *
|
||||
* 3 Sep 90 - Version 1.1 by Gershon Elber (Support for Gif89, Unique names). *
|
||||
******************************************************************************/
|
||||
|
||||
#ifdef __MSDOS__
|
||||
#include <io.h>
|
||||
#include <alloc.h>
|
||||
#include <sys\stat.h>
|
||||
#else
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#ifdef R6000
|
||||
#include <sys/mode.h>
|
||||
#endif
|
||||
#endif /* __MSDOS__ */
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "gif_lib.h"
|
||||
#include "gif_hash.h"
|
||||
|
||||
#define PROGRAM_NAME "GIF_LIBRARY"
|
||||
|
||||
#define COMMENT_EXT_FUNC_CODE 0xfe /* Extension function code for comment. */
|
||||
#define GIF_STAMP "GIF87a" /* First chars in file - GIF stamp. */
|
||||
#define ZL_MAX_CODE 4095 /* Biggest code possible in 12 bits. */
|
||||
|
||||
#define FILE_STATE_WRITE 0x01/* 1 write, 0 read - DGIF_LIB compatible.*/
|
||||
#define FILE_STATE_SCREEN 0x02
|
||||
#define FILE_STATE_IMAGE 0x04
|
||||
|
||||
#define FLUSH_OUTPUT 4096 /* Impossible code, to signal flush. */
|
||||
#define FIRST_CODE 4097 /* Impossible code, to signal first. */
|
||||
|
||||
#define IS_WRITEABLE(Private) (Private -> FileState & FILE_STATE_WRITE)
|
||||
|
||||
/* #define DEBUG_NO_PREFIX Dump only compressed data. */
|
||||
|
||||
typedef struct GifFilePrivateType {
|
||||
int FileState,
|
||||
FileHandle, /* Where old this data goes to! */
|
||||
BitsPerPixel, /* Bits per pixel (Codes uses at list this + 1). */
|
||||
ClearCode, /* The CLEAR LZ code. */
|
||||
EOFCode, /* The EOF LZ code. */
|
||||
RunningCode, /* The next code algorithm can generate. */
|
||||
RunningBits,/* The number of bits required to represent RunningCode. */
|
||||
MaxCode1, /* 1 bigger than max. possible code, in RunningBits bits. */
|
||||
CrntCode, /* Current algorithm code. */
|
||||
CrntShiftState; /* Number of bits in CrntShiftDWord. */
|
||||
unsigned long CrntShiftDWord, /* For bytes decomposition into codes. */
|
||||
PixelCount;
|
||||
FILE *File; /* File as stream. */
|
||||
GifByteType Buf[256]; /* Compressed output is buffered here. */
|
||||
GifHashTableType *HashTable;
|
||||
} GifFilePrivateType;
|
||||
|
||||
extern int _GifError;
|
||||
|
||||
/* Masks given codes to BitsPerPixel, to make sure all codes are in range: */
|
||||
static GifPixelType CodeMask[] = {
|
||||
0x00, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff
|
||||
};
|
||||
|
||||
#ifdef SYSV
|
||||
static char *VersionStr =
|
||||
"Gif library module,\t\tGershon Elber\n\
|
||||
(C) Copyright 1989 Gershon Elber, Non commercial use only.\n";
|
||||
#else
|
||||
static char *VersionStr =
|
||||
PROGRAM_NAME
|
||||
" IBMPC "
|
||||
GIF_LIB_VERSION
|
||||
" Gershon Elber, "
|
||||
__DATE__ ", " __TIME__ "\n"
|
||||
"(C) Copyright 1989 Gershon Elber, Non commercial use only.\n";
|
||||
#endif /* SYSV */
|
||||
|
||||
static char *GifVersionPrefix = GIF_STAMP;
|
||||
|
||||
static int EGifPutWord(int Word, FILE *File);
|
||||
static int EGifSetupCompress(GifFileType *GifFile);
|
||||
static int EGifCompressLine(GifFileType *GifFile, GifPixelType *Line,
|
||||
int LineLen);
|
||||
static int EGifCompressOutput(GifFilePrivateType *Private, int Code);
|
||||
static int EGifBufferedOutput(FILE *File, GifByteType *Buf, int c);
|
||||
|
||||
/******************************************************************************
|
||||
* Open a new gif file for write, given by its name. If TestExistance then *
|
||||
* if the file exists this routines fails (returns NULL). *
|
||||
* Returns GifFileType pointer dynamically allocated which serves as the gif *
|
||||
* info record. _GifError is cleared if succesfull. *
|
||||
******************************************************************************/
|
||||
GifFileType *EGifOpenFileName(char *FileName, int TestExistance)
|
||||
{
|
||||
int FileHandle;
|
||||
|
||||
if (TestExistance)
|
||||
FileHandle = open(FileName,
|
||||
O_WRONLY | O_CREAT | O_EXCL
|
||||
#ifdef __MSDOS__
|
||||
| O_BINARY
|
||||
#endif /* __MSDOS__ */
|
||||
,
|
||||
S_IREAD | S_IWRITE);
|
||||
else
|
||||
FileHandle = open(FileName,
|
||||
O_WRONLY | O_CREAT | O_TRUNC
|
||||
#ifdef __MSDOS__
|
||||
| O_BINARY
|
||||
#endif /* __MSDOS__ */
|
||||
,
|
||||
S_IREAD | S_IWRITE);
|
||||
|
||||
if (FileHandle == -1) {
|
||||
_GifError = E_GIF_ERR_OPEN_FAILED;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return EGifOpenFileHandle(FileHandle);
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* Update a new gif file, given its file handle, which must be opened for *
|
||||
* write in binary mode. *
|
||||
* Returns GifFileType pointer dynamically allocated which serves as the gif *
|
||||
* info record. _GifError is cleared if succesfull. *
|
||||
******************************************************************************/
|
||||
GifFileType *EGifOpenFileHandle(int FileHandle)
|
||||
{
|
||||
GifFileType *GifFile;
|
||||
GifFilePrivateType *Private;
|
||||
FILE *f;
|
||||
|
||||
#ifdef __MSDOS__
|
||||
setmode(FileHandle, O_BINARY); /* Make sure it is in binary mode. */
|
||||
f = fdopen(FileHandle, "wb"); /* Make it into a stream: */
|
||||
setvbuf(f, NULL, _IOFBF, GIF_FILE_BUFFER_SIZE); /* And inc. stream buffer. */
|
||||
#else
|
||||
f = fdopen(FileHandle, "w"); /* Make it into a stream: */
|
||||
#endif /* __MSDOS__ */
|
||||
|
||||
if ((GifFile = (GifFileType *) malloc(sizeof(GifFileType))) == NULL) {
|
||||
_GifError = E_GIF_ERR_NOT_ENOUGH_MEM;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
GifFile -> SWidth = GifFile -> SHeight =
|
||||
GifFile -> SColorResolution = GifFile -> SBitsPerPixel =
|
||||
GifFile -> SBackGroundColor =
|
||||
GifFile -> ILeft = GifFile -> ITop = GifFile -> IWidth = GifFile -> IHeight =
|
||||
GifFile -> IInterlace =
|
||||
GifFile -> IBitsPerPixel = 0;
|
||||
|
||||
GifFile -> SColorMap = GifFile -> IColorMap = NULL;
|
||||
|
||||
#ifndef DEBUG_NO_PREFIX
|
||||
if (fwrite(GifVersionPrefix, 1, strlen(GifVersionPrefix), f) !=
|
||||
strlen(GifVersionPrefix)) {
|
||||
_GifError = E_GIF_ERR_WRITE_FAILED;
|
||||
free((char *) GifFile);
|
||||
return NULL;
|
||||
}
|
||||
#endif /* DEBUG_NO_PREFIX */
|
||||
|
||||
if ((Private = (GifFilePrivateType *) malloc(sizeof(GifFilePrivateType)))
|
||||
== NULL) {
|
||||
_GifError = E_GIF_ERR_NOT_ENOUGH_MEM;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
GifFile -> Private = (VoidPtr) Private;
|
||||
Private -> FileHandle = FileHandle;
|
||||
Private -> File = f;
|
||||
Private -> FileState = FILE_STATE_WRITE;
|
||||
if ((Private -> HashTable = _InitHashTable()) == NULL) {
|
||||
_GifError = E_GIF_ERR_NOT_ENOUGH_MEM;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
_GifError = 0;
|
||||
|
||||
return GifFile;
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* Routine to set current GIF version. All files open for write will be *
|
||||
* using this version until next call to this routine. Version consists of *
|
||||
* 3 characters as "87a" or "89a". No test is made to validate the version. *
|
||||
******************************************************************************/
|
||||
void EGifSetGifVersion(char *Version)
|
||||
{
|
||||
strncpy(&GifVersionPrefix[3], Version, 3);
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* This routine should be called before any other EGif calls, immediately *
|
||||
* follows the GIF file openning. *
|
||||
******************************************************************************/
|
||||
int EGifPutScreenDesc(GifFileType *GifFile,
|
||||
int Width, int Height, int ColorRes, int BackGround,
|
||||
int BitsPerPixel, GifColorType *ColorMap)
|
||||
{
|
||||
int i, Size;
|
||||
GifByteType Buf[3];
|
||||
GifFilePrivateType *Private = (GifFilePrivateType *) GifFile -> Private;
|
||||
|
||||
if (Private -> FileState & FILE_STATE_SCREEN) {
|
||||
/* If already has screen descriptor - something is wrong! */
|
||||
_GifError = E_GIF_ERR_HAS_SCRN_DSCR;
|
||||
return GIF_ERROR;
|
||||
}
|
||||
if (!IS_WRITEABLE(Private)) {
|
||||
/* This file was NOT open for writing: */
|
||||
_GifError = E_GIF_ERR_NOT_WRITEABLE;
|
||||
return GIF_ERROR;
|
||||
}
|
||||
|
||||
GifFile -> SWidth = Width;
|
||||
GifFile -> SHeight = Height;
|
||||
GifFile -> SColorResolution = ColorRes;
|
||||
GifFile -> SBitsPerPixel = BitsPerPixel;
|
||||
GifFile -> SBackGroundColor = BackGround;
|
||||
if (ColorMap) {
|
||||
Size = sizeof(GifColorType) * (1 << BitsPerPixel);
|
||||
GifFile -> SColorMap = (GifColorType *) malloc(Size);
|
||||
memcpy(GifFile -> SColorMap, ColorMap, Size);
|
||||
}
|
||||
|
||||
/* Put the screen descriptor into the file: */
|
||||
EGifPutWord(Width, Private -> File);
|
||||
EGifPutWord(Height, Private -> File);
|
||||
Buf[0] = (ColorMap ? 0x80 : 0x00) |
|
||||
((ColorRes - 1) << 4) |
|
||||
(BitsPerPixel - 1);
|
||||
Buf[1] = BackGround;
|
||||
Buf[2] = 0;
|
||||
#ifndef DEBUG_NO_PREFIX
|
||||
fwrite(Buf, 1, 3, Private -> File);
|
||||
#endif /* DEBUG_NO_PREFIX */
|
||||
|
||||
/* If we have Global color map - dump it also: */
|
||||
#ifndef DEBUG_NO_PREFIX
|
||||
if (ColorMap != NULL)
|
||||
for (i = 0; i < (1 << BitsPerPixel); i++) {
|
||||
/* Put the ColorMap out also: */
|
||||
Buf[0] = ColorMap[i].Red;
|
||||
Buf[1] = ColorMap[i].Green;
|
||||
Buf[2] = ColorMap[i].Blue;
|
||||
if (fwrite(Buf, 1, 3, Private -> File) != 3) {
|
||||
_GifError = E_GIF_ERR_WRITE_FAILED;
|
||||
return GIF_ERROR;
|
||||
}
|
||||
}
|
||||
#endif /* DEBUG_NO_PREFIX */
|
||||
|
||||
/* Mark this file as has screen descriptor, and no pixel written yet: */
|
||||
Private -> FileState |= FILE_STATE_SCREEN;
|
||||
|
||||
return GIF_OK;
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* This routine should be called before any attemp to dump an image - any *
|
||||
* call to any of the pixel dump routines. *
|
||||
******************************************************************************/
|
||||
int EGifPutImageDesc(GifFileType *GifFile,
|
||||
int Left, int Top, int Width, int Height, int Interlace,
|
||||
int BitsPerPixel, GifColorType *ColorMap)
|
||||
{
|
||||
int i, Size;
|
||||
GifByteType Buf[3];
|
||||
GifFilePrivateType *Private = (GifFilePrivateType *) GifFile -> Private;
|
||||
|
||||
if (Private -> FileState & FILE_STATE_IMAGE &&
|
||||
#ifdef __MSDOS__
|
||||
Private -> PixelCount > 0xffff0000UL) {
|
||||
#else
|
||||
Private -> PixelCount > 0xffff0000) {
|
||||
#endif /* __MSDOS__ */
|
||||
/* If already has active image descriptor - something is wrong! */
|
||||
_GifError = E_GIF_ERR_HAS_IMAG_DSCR;
|
||||
return GIF_ERROR;
|
||||
}
|
||||
if (!IS_WRITEABLE(Private)) {
|
||||
/* This file was NOT open for writing: */
|
||||
_GifError = E_GIF_ERR_NOT_WRITEABLE;
|
||||
return GIF_ERROR;
|
||||
}
|
||||
GifFile -> ILeft = Left;
|
||||
GifFile -> ITop = Top;
|
||||
GifFile -> IWidth = Width;
|
||||
GifFile -> IHeight = Height;
|
||||
GifFile -> IBitsPerPixel = BitsPerPixel;
|
||||
GifFile -> IInterlace = Interlace;
|
||||
if (ColorMap) {
|
||||
Size = sizeof(GifColorType) * (1 << BitsPerPixel);
|
||||
if (GifFile -> IColorMap) free((char *) GifFile -> IColorMap);
|
||||
GifFile -> IColorMap = (GifColorType *) malloc(Size);
|
||||
memcpy(GifFile -> IColorMap, ColorMap, Size);
|
||||
}
|
||||
|
||||
/* Put the image descriptor into the file: */
|
||||
Buf[0] = ','; /* Image seperator character. */
|
||||
#ifndef DEBUG_NO_PREFIX
|
||||
fwrite(Buf, 1, 1, Private -> File);
|
||||
#endif /* DEBUG_NO_PREFIX */
|
||||
EGifPutWord(Left, Private -> File);
|
||||
EGifPutWord(Top, Private -> File);
|
||||
EGifPutWord(Width, Private -> File);
|
||||
EGifPutWord(Height, Private -> File);
|
||||
Buf[0] = (ColorMap ? 0x80 : 0x00) |
|
||||
(Interlace ? 0x40 : 0x00) |
|
||||
(BitsPerPixel - 1);
|
||||
#ifndef DEBUG_NO_PREFIX
|
||||
fwrite(Buf, 1, 1, Private -> File);
|
||||
#endif /* DEBUG_NO_PREFIX */
|
||||
|
||||
/* If we have Global color map - dump it also: */
|
||||
#ifndef DEBUG_NO_PREFIX
|
||||
if (ColorMap != NULL)
|
||||
for (i = 0; i < (1 << BitsPerPixel); i++) {
|
||||
/* Put the ColorMap out also: */
|
||||
Buf[0] = ColorMap[i].Red;
|
||||
Buf[1] = ColorMap[i].Green;
|
||||
Buf[2] = ColorMap[i].Blue;
|
||||
if (fwrite(Buf, 1, 3, Private -> File) != 3) {
|
||||
_GifError = E_GIF_ERR_WRITE_FAILED;
|
||||
return GIF_ERROR;
|
||||
}
|
||||
}
|
||||
#endif /* DEBUG_NO_PREFIX */
|
||||
if (GifFile -> SColorMap == NULL && GifFile -> IColorMap == NULL)
|
||||
{
|
||||
_GifError = E_GIF_ERR_NO_COLOR_MAP;
|
||||
return GIF_ERROR;
|
||||
}
|
||||
|
||||
/* Mark this file as has screen descriptor: */
|
||||
Private -> FileState |= FILE_STATE_IMAGE;
|
||||
Private -> PixelCount = (long) Width * (long) Height;
|
||||
|
||||
EGifSetupCompress(GifFile); /* Reset compress algorithm parameters. */
|
||||
|
||||
return GIF_OK;
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* Put one full scanned line (Line) of length LineLen into GIF file. *
|
||||
******************************************************************************/
|
||||
int EGifPutLine(GifFileType *GifFile, GifPixelType *Line, int LineLen)
|
||||
{
|
||||
int i;
|
||||
GifPixelType Mask;
|
||||
GifFilePrivateType *Private = (GifFilePrivateType *) GifFile -> Private;
|
||||
|
||||
if (!IS_WRITEABLE(Private)) {
|
||||
/* This file was NOT open for writing: */
|
||||
_GifError = E_GIF_ERR_NOT_WRITEABLE;
|
||||
return GIF_ERROR;
|
||||
}
|
||||
|
||||
if (!LineLen) LineLen = GifFile -> IWidth;
|
||||
if ((Private -> PixelCount -= LineLen) < 0) {
|
||||
_GifError = E_GIF_ERR_DATA_TOO_BIG;
|
||||
return GIF_ERROR;
|
||||
}
|
||||
|
||||
/* Make sure the codes are not out of bit range, as we might generate */
|
||||
/* wrong code (because of overflow when we combine them) in this case: */
|
||||
Mask = CodeMask[Private -> BitsPerPixel];
|
||||
for (i = 0; i < LineLen; i++) Line[i] &= Mask;
|
||||
|
||||
return EGifCompressLine(GifFile, Line, LineLen);
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* Put one pixel (Pixel) into GIF file. *
|
||||
******************************************************************************/
|
||||
int EGifPutPixel(GifFileType *GifFile, GifPixelType Pixel)
|
||||
{
|
||||
GifFilePrivateType *Private = (GifFilePrivateType *) GifFile -> Private;
|
||||
|
||||
if (!IS_WRITEABLE(Private)) {
|
||||
/* This file was NOT open for writing: */
|
||||
_GifError = E_GIF_ERR_NOT_WRITEABLE;
|
||||
return GIF_ERROR;
|
||||
}
|
||||
|
||||
if (--Private -> PixelCount < 0)
|
||||
{
|
||||
_GifError = E_GIF_ERR_DATA_TOO_BIG;
|
||||
return GIF_ERROR;
|
||||
}
|
||||
|
||||
/* Make sure the code is not out of bit range, as we might generate */
|
||||
/* wrong code (because of overflow when we combine them) in this case: */
|
||||
Pixel &= CodeMask[Private -> BitsPerPixel];
|
||||
|
||||
return EGifCompressLine(GifFile, &Pixel, 1);
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* Put a comment into GIF file using extension block. *
|
||||
******************************************************************************/
|
||||
int EGifPutComment(GifFileType *GifFile, char *Comment)
|
||||
{
|
||||
return EGifPutExtension(GifFile, COMMENT_EXT_FUNC_CODE, strlen(Comment),
|
||||
Comment);
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* Put an extension block (see GIF manual) into gif file. *
|
||||
******************************************************************************/
|
||||
int EGifPutExtension(GifFileType *GifFile, int ExtCode, int ExtLen,
|
||||
VoidPtr Extension)
|
||||
{
|
||||
GifByteType Buf[3];
|
||||
GifFilePrivateType *Private = (GifFilePrivateType *) GifFile -> Private;
|
||||
|
||||
if (!IS_WRITEABLE(Private)) {
|
||||
/* This file was NOT open for writing: */
|
||||
_GifError = E_GIF_ERR_NOT_WRITEABLE;
|
||||
return GIF_ERROR;
|
||||
}
|
||||
|
||||
Buf[0] = '!';
|
||||
Buf[1] = ExtCode;
|
||||
Buf[2] = ExtLen;
|
||||
fwrite(Buf, 1, 3, Private -> File);
|
||||
fwrite(Extension, 1, ExtLen, Private -> File);
|
||||
Buf[0] = 0;
|
||||
fwrite(Buf, 1, 1, Private -> File);
|
||||
|
||||
return GIF_OK;
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* Put the image code in compressed form. This routine can be called if the *
|
||||
* information needed to be piped out as is. Obviously this is much faster *
|
||||
* than decoding and encoding again. This routine should be followed by calls *
|
||||
* to EGifPutCodeNext, until NULL block is given. *
|
||||
* The block should NOT be freed by the user (not dynamically allocated). *
|
||||
******************************************************************************/
|
||||
int EGifPutCode(GifFileType *GifFile, int CodeSize, GifByteType *CodeBlock)
|
||||
{
|
||||
GifFilePrivateType *Private = (GifFilePrivateType *) GifFile -> Private;
|
||||
|
||||
if (!IS_WRITEABLE(Private)) {
|
||||
/* This file was NOT open for writing: */
|
||||
_GifError = E_GIF_ERR_NOT_WRITEABLE;
|
||||
return GIF_ERROR;
|
||||
}
|
||||
|
||||
/* No need to dump code size as Compression set up does any for us: */
|
||||
/*
|
||||
Buf = CodeSize;
|
||||
if (fwrite(&Buf, 1, 1, Private -> File) != 1) {
|
||||
_GifError = E_GIF_ERR_WRITE_FAILED;
|
||||
return GIF_ERROR;
|
||||
}
|
||||
*/
|
||||
|
||||
return EGifPutCodeNext(GifFile, CodeBlock);
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* Continue to put the image code in compressed form. This routine should be *
|
||||
* called with blocks of code as read via DGifGetCode/DGifGetCodeNext. If *
|
||||
* given buffer pointer is NULL, empty block is written to mark end of code. *
|
||||
******************************************************************************/
|
||||
int EGifPutCodeNext(GifFileType *GifFile, GifByteType *CodeBlock)
|
||||
{
|
||||
GifByteType Buf;
|
||||
GifFilePrivateType *Private = (GifFilePrivateType *) GifFile -> Private;
|
||||
|
||||
if (CodeBlock != NULL) {
|
||||
if (fwrite(CodeBlock, 1, CodeBlock[0] + 1, Private -> File)
|
||||
!= CodeBlock[0] + 1) {
|
||||
_GifError = E_GIF_ERR_WRITE_FAILED;
|
||||
return GIF_ERROR;
|
||||
}
|
||||
}
|
||||
else {
|
||||
Buf = 0;
|
||||
if (fwrite(&Buf, 1, 1, Private -> File) != 1) {
|
||||
_GifError = E_GIF_ERR_WRITE_FAILED;
|
||||
return GIF_ERROR;
|
||||
}
|
||||
Private -> PixelCount = 0; /* And local info. indicate image read. */
|
||||
}
|
||||
|
||||
return GIF_OK;
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* This routine should be called last, to close GIF file. *
|
||||
******************************************************************************/
|
||||
int EGifCloseFile(GifFileType *GifFile)
|
||||
{
|
||||
GifByteType Buf;
|
||||
GifFilePrivateType *Private;
|
||||
FILE *File;
|
||||
|
||||
if (GifFile == NULL) return GIF_ERROR;
|
||||
|
||||
Private = (GifFilePrivateType *) GifFile -> Private;
|
||||
if (!IS_WRITEABLE(Private)) {
|
||||
/* This file was NOT open for writing: */
|
||||
_GifError = E_GIF_ERR_NOT_WRITEABLE;
|
||||
return GIF_ERROR;
|
||||
}
|
||||
|
||||
File = Private -> File;
|
||||
|
||||
Buf = ';';
|
||||
fwrite(&Buf, 1, 1, Private -> File);
|
||||
|
||||
if (GifFile -> IColorMap) free((char *) GifFile -> IColorMap);
|
||||
if (GifFile -> SColorMap) free((char *) GifFile -> SColorMap);
|
||||
if (Private) {
|
||||
if (Private -> HashTable) free((char *) Private -> HashTable);
|
||||
free((char *) Private);
|
||||
}
|
||||
free(GifFile);
|
||||
|
||||
if (fclose(File) != 0) {
|
||||
_GifError = E_GIF_ERR_CLOSE_FAILED;
|
||||
return GIF_ERROR;
|
||||
}
|
||||
return GIF_OK;
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* Put 2 bytes (word) into the given file: *
|
||||
******************************************************************************/
|
||||
static int EGifPutWord(int Word, FILE *File)
|
||||
{
|
||||
char c[2];
|
||||
|
||||
c[0] = Word & 0xff;
|
||||
c[1] = (Word >> 8) & 0xff;
|
||||
#ifndef DEBUG_NO_PREFIX
|
||||
if (fwrite(c, 1, 2, File) == 2)
|
||||
return GIF_OK;
|
||||
else
|
||||
return GIF_ERROR;
|
||||
#else
|
||||
return GIF_OK;
|
||||
#endif /* DEBUG_NO_PREFIX */
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* Setup the LZ compression for this image: *
|
||||
******************************************************************************/
|
||||
static int EGifSetupCompress(GifFileType *GifFile)
|
||||
{
|
||||
int BitsPerPixel;
|
||||
GifByteType Buf;
|
||||
GifFilePrivateType *Private = (GifFilePrivateType *) GifFile -> Private;
|
||||
|
||||
/* Test and see what color map to use, and from it # bits per pixel: */
|
||||
if (GifFile -> IColorMap)
|
||||
BitsPerPixel = GifFile -> IBitsPerPixel;
|
||||
else if (GifFile -> SColorMap)
|
||||
BitsPerPixel = GifFile -> SBitsPerPixel;
|
||||
else {
|
||||
_GifError = E_GIF_ERR_NO_COLOR_MAP;
|
||||
return GIF_ERROR;
|
||||
}
|
||||
|
||||
Buf = BitsPerPixel = (BitsPerPixel < 2 ? 2 : BitsPerPixel);
|
||||
fwrite(&Buf, 1, 1, Private -> File); /* Write the Code size to file. */
|
||||
|
||||
Private -> Buf[0] = 0; /* Nothing was output yet. */
|
||||
Private -> BitsPerPixel = BitsPerPixel;
|
||||
Private -> ClearCode = (1 << BitsPerPixel);
|
||||
Private -> EOFCode = Private -> ClearCode + 1;
|
||||
Private -> RunningCode = Private -> EOFCode + 1;
|
||||
Private -> RunningBits = BitsPerPixel + 1; /* Number of bits per code. */
|
||||
Private -> MaxCode1 = 1 << Private -> RunningBits; /* Max. code + 1. */
|
||||
Private -> CrntCode = FIRST_CODE; /* Signal that this is first one! */
|
||||
Private -> CrntShiftState = 0; /* No information in CrntShiftDWord. */
|
||||
Private -> CrntShiftDWord = 0;
|
||||
|
||||
/* Clear hash table and send Clear to make sure the decoder do the same. */
|
||||
_ClearHashTable(Private -> HashTable);
|
||||
if (EGifCompressOutput(Private, Private -> ClearCode) == GIF_ERROR) {
|
||||
_GifError = E_GIF_ERR_DISK_IS_FULL;
|
||||
return GIF_ERROR;
|
||||
}
|
||||
return GIF_OK;
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* The LZ compression routine: *
|
||||
* This version compress the given buffer Line of length LineLen. *
|
||||
* This routine can be called few times (one per scan line, for example), in *
|
||||
* order the complete the whole image. *
|
||||
******************************************************************************/
|
||||
static int EGifCompressLine(GifFileType *GifFile, GifPixelType *Line,
|
||||
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) /* Its first time! */
|
||||
CrntCode = Line[i++];
|
||||
else
|
||||
CrntCode = Private -> CrntCode; /* Get last code in compression. */
|
||||
|
||||
while (i < LineLen) { /* Decode LineLen items. */
|
||||
Pixel = Line[i++]; /* Get next pixel from stream. */
|
||||
/* Form a new unique key to search hash table for the code combines */
|
||||
/* CrntCode as Prefix string with Pixel as postfix char. */
|
||||
NewKey = (((unsigned long) CrntCode) << 8) + Pixel;
|
||||
if ((NewCode = _ExistsHashTable(HashTable, NewKey)) >= 0) {
|
||||
/* This Key is already there, or the string is old one, so */
|
||||
/* simple take new code as our CrntCode: */
|
||||
CrntCode = NewCode;
|
||||
}
|
||||
else {
|
||||
/* Put it in hash table, output the prefix code, and make our */
|
||||
/* CrntCode equal to Pixel. */
|
||||
if (EGifCompressOutput(Private, CrntCode)
|
||||
== GIF_ERROR) {
|
||||
_GifError = E_GIF_ERR_DISK_IS_FULL;
|
||||
return GIF_ERROR;
|
||||
}
|
||||
CrntCode = Pixel;
|
||||
|
||||
/* If however the HashTable if full, we send a clear first and */
|
||||
/* Clear the hash table. */
|
||||
if (Private -> RunningCode >= ZL_MAX_CODE) {
|
||||
/* Time to do some clearance: */
|
||||
if (EGifCompressOutput(Private, Private -> ClearCode)
|
||||
== GIF_ERROR) {
|
||||
_GifError = 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 {
|
||||
/* Put this unique key with its relative Code in hash table: */
|
||||
_InsertHashTable(HashTable, NewKey, Private -> RunningCode++);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Preserve the current state of the compression algorithm: */
|
||||
Private -> CrntCode = CrntCode;
|
||||
|
||||
if (Private -> PixelCount == 0)
|
||||
{
|
||||
/* We are done - output last Code and flush output buffers: */
|
||||
if (EGifCompressOutput(Private, CrntCode)
|
||||
== GIF_ERROR) {
|
||||
_GifError = E_GIF_ERR_DISK_IS_FULL;
|
||||
return GIF_ERROR;
|
||||
}
|
||||
if (EGifCompressOutput(Private, Private -> EOFCode)
|
||||
== GIF_ERROR) {
|
||||
_GifError = E_GIF_ERR_DISK_IS_FULL;
|
||||
return GIF_ERROR;
|
||||
}
|
||||
if (EGifCompressOutput(Private, FLUSH_OUTPUT) == GIF_ERROR) {
|
||||
_GifError = E_GIF_ERR_DISK_IS_FULL;
|
||||
return GIF_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
return GIF_OK;
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* The LZ compression output routine: *
|
||||
* This routine is responsable for the compression of the bit stream into *
|
||||
* 8 bits (bytes) packets. *
|
||||
* Returns GIF_OK if written succesfully. *
|
||||
******************************************************************************/
|
||||
static int EGifCompressOutput(GifFilePrivateType *Private, int Code)
|
||||
{
|
||||
int retval = GIF_OK;
|
||||
|
||||
if (Code == FLUSH_OUTPUT) {
|
||||
while (Private -> CrntShiftState > 0) {
|
||||
/* Get Rid of what is left in DWord, and flush it. */
|
||||
if (EGifBufferedOutput(Private -> File, Private -> Buf,
|
||||
Private -> CrntShiftDWord & 0xff) == GIF_ERROR)
|
||||
retval = GIF_ERROR;
|
||||
Private -> CrntShiftDWord >>= 8;
|
||||
Private -> CrntShiftState -= 8;
|
||||
}
|
||||
Private -> CrntShiftState = 0; /* For next time. */
|
||||
if (EGifBufferedOutput(Private -> File, Private -> Buf,
|
||||
FLUSH_OUTPUT) == GIF_ERROR)
|
||||
retval = GIF_ERROR;
|
||||
}
|
||||
else {
|
||||
Private -> CrntShiftDWord |= ((long) Code) << Private -> CrntShiftState;
|
||||
Private -> CrntShiftState += Private -> RunningBits;
|
||||
while (Private -> CrntShiftState >= 8) {
|
||||
/* Dump out full bytes: */
|
||||
if (EGifBufferedOutput(Private -> File, Private -> Buf,
|
||||
Private -> CrntShiftDWord & 0xff) == GIF_ERROR)
|
||||
retval = GIF_ERROR;
|
||||
Private -> CrntShiftDWord >>= 8;
|
||||
Private -> CrntShiftState -= 8;
|
||||
}
|
||||
}
|
||||
|
||||
/* If code cannt fit into RunningBits bits, must raise its size. Note */
|
||||
/* however that codes above 4095 are used for special signaling. */
|
||||
if (Private -> RunningCode >= Private -> MaxCode1 && Code <= 4095) {
|
||||
Private -> MaxCode1 = 1 << ++Private -> RunningBits;
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* This routines buffers the given characters until 255 characters are ready *
|
||||
* to be output. If Code is equal to -1 the buffer is flushed (EOF). *
|
||||
* The buffer is Dumped with first byte as its size, as GIF format requires. *
|
||||
* Returns GIF_OK if written succesfully. *
|
||||
******************************************************************************/
|
||||
static int EGifBufferedOutput(FILE *File, GifByteType *Buf, int c)
|
||||
{
|
||||
if (c == FLUSH_OUTPUT) {
|
||||
/* Flush everything out. */
|
||||
if (Buf[0] != 0 && fwrite(Buf, 1, Buf[0]+1, File) != Buf[0] + 1)
|
||||
{
|
||||
_GifError = E_GIF_ERR_WRITE_FAILED;
|
||||
return GIF_ERROR;
|
||||
}
|
||||
/* Mark end of compressed data, by an empty block (see GIF doc): */
|
||||
Buf[0] = 0;
|
||||
if (fwrite(Buf, 1, 1, File) != 1)
|
||||
{
|
||||
_GifError = E_GIF_ERR_WRITE_FAILED;
|
||||
return GIF_ERROR;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (Buf[0] == 255) {
|
||||
/* Dump out this buffer - it is full: */
|
||||
if (fwrite(Buf, 1, Buf[0] + 1, File) != Buf[0] + 1)
|
||||
{
|
||||
_GifError = E_GIF_ERR_WRITE_FAILED;
|
||||
return GIF_ERROR;
|
||||
}
|
||||
Buf[0] = 0;
|
||||
}
|
||||
Buf[++Buf[0]] = c;
|
||||
}
|
||||
|
||||
return GIF_OK;
|
||||
}
|
632
G/LIB/GETARG.C
Normal file
632
G/LIB/GETARG.C
Normal file
@ -0,0 +1,632 @@
|
||||
/***************************************************************************
|
||||
* Routines to grab the parameters from the command line : *
|
||||
* All the routines except the main one, starts with GA (Get Arguments) to *
|
||||
* prevent from names conflicts. *
|
||||
* It is assumed in these routine that any pointer, for any type has the *
|
||||
* same length (i.e. length of int pointer is equal to char pointer etc.) *
|
||||
* *
|
||||
* The following routines are available in this module: *
|
||||
* 1. int GAGetArgs(argc, argv, CtrlStr, Variables...) *
|
||||
* where argc, argv as received on entry. *
|
||||
* CtrlStr is the contrl string (see below) *
|
||||
* Variables are all the variables to be set according to CtrlStr. *
|
||||
* Note that all the variables MUST be transfered by address. *
|
||||
* return 0 on correct parsing, otherwise error number (see GetArg.h). *
|
||||
* 2. GAPrintHowTo(CtrlStr) *
|
||||
* Print the control string to stderr, in the correct format needed. *
|
||||
* This feature is very useful in case of error during GetArgs parsing. *
|
||||
* Chars equal to SPACE_CHAR are not printed (regular spaces are NOT *
|
||||
* allowed, and so using SPACE_CHAR you can create space in PrintHowTo). *
|
||||
* 3. GAPrintErrMsg(Error) *
|
||||
* Print the error to stderr, according to Error (usually returned by *
|
||||
* GAGetArgs). *
|
||||
* *
|
||||
* CtrlStr format: *
|
||||
* The control string passed to GetArgs controls the way argv (argc) are *
|
||||
* parsed. Each entry in this string must not have any spaces in it. The *
|
||||
* First Entry is the name of the program which is usually ignored except *
|
||||
* when GAPrintHowTo is called. All the other entries (except the last one *
|
||||
* which we will come back to it later) must have the following format: *
|
||||
* 1. One letter which sets the option letter. *
|
||||
* 2. '!' or '%' to determines if this option is really optional ('%') or *
|
||||
* it must exists ('!')... *
|
||||
* 3. '-' allways. *
|
||||
* 4. Alpha numeric string, usually ignored, but used by GAPrintHowTo to *
|
||||
* print the meaning of this input. *
|
||||
* 5. Sequences starts with '!' or '%'. Again if '!' then this sequence *
|
||||
* must exists (only if its option flag is given of course), and if '%' *
|
||||
* it is optional. Each sequence will continue with one or two *
|
||||
* characters which defines the kind of the input: *
|
||||
* a. d, x, o, u - integer is expected (decimal, hex, octal base or *
|
||||
* unsigned). *
|
||||
* b. D, X, O, U - long integer is expected (same as above). *
|
||||
* c. f - float number is expected. *
|
||||
* d. F - double number is expected. *
|
||||
* e. s - string is expected. *
|
||||
* f. *? - any number of '?' kind (d, x, o, u, D, X, O, U, f, F, s) *
|
||||
* will match this one. If '?' is numeric, it scans until *
|
||||
* none numeric input is given. If '?' is 's' then it scans *
|
||||
* up to the next option or end of argv. *
|
||||
* *
|
||||
* If the last parameter given in the CtrlStr, is not an option (i.e. the *
|
||||
* second char is not in ['!', '%'] and the third one is not '-'), all what *
|
||||
* remained from argv is linked to it. *
|
||||
* *
|
||||
* The variables passed to GAGetArgs (starting from 4th parameter) MUST *
|
||||
* match the order of the CtrlStr: *
|
||||
* For each option, one integer address must be passed. This integer must *
|
||||
* initialized by 0. If that option is given in the command line, it will *
|
||||
* be set to one. *
|
||||
* In addition, the sequences that might follow an option require the *
|
||||
* following parameters to pass: *
|
||||
* 1. d, x, o, u - pointer to integer (int *). *
|
||||
* 2. D, X, O, U - pointer to long (long *). *
|
||||
* 3. f - pointer to float (float *). *
|
||||
* 4. F - pointer to double (double *). *
|
||||
* 5. s - pointer to char (char *). NO allocation is needed! *
|
||||
* 6. *? - TWO variables are passed for each wild request. the first *
|
||||
* one is (address of) integer, and it will return number of *
|
||||
* parameters actually matched this sequence, and the second *
|
||||
* one is a pointer to pointer to ? (? **), and will return an *
|
||||
* address to a block of pointers to ? kind, terminated with *
|
||||
* NULL pointer. NO pre-allocation is needed. *
|
||||
* note that these two variables are pretty like the argv/argc *
|
||||
* pair... *
|
||||
* *
|
||||
* Examples: *
|
||||
* *
|
||||
* "Example1 i%-OneInteger!d s%-Strings!*s j%- k!-Float!f Files" *
|
||||
* Will match: Example1 -i 77 -s String1 String2 String3 -k 88.2 File1 File2*
|
||||
* or match: Example1 -s String1 -k 88.3 -i 999 -j *
|
||||
* but not: Example1 -i 77 78 (option i expects one integer, k must be). *
|
||||
* Note the option k must exists, and that the order of the options is not *
|
||||
* not important. In the first examples File1 & File2 will match the Files *
|
||||
* in the command line. *
|
||||
* A call to GAPrintHowTo with this CtrlStr will print to stderr: *
|
||||
* Example1 [-i OneIngeter] [-s Strings...] [-j] -k Float Files... *
|
||||
* *
|
||||
* Notes: *
|
||||
* *
|
||||
* 1. This module assumes that all the pointers to all kind of data types *
|
||||
* have the same length and format, i.e. sizeof(int *) == sizeof(char *).*
|
||||
* *
|
||||
* Gershon Elber Ver 0.2 Mar 88 *
|
||||
****************************************************************************
|
||||
* History: *
|
||||
* 11 Mar 88 - Version 1.0 by Gershon Elber. *
|
||||
***************************************************************************/
|
||||
|
||||
#ifdef __MSDOS__
|
||||
#include <stdlib.h>
|
||||
#include <alloc.h>
|
||||
#endif /* __MSDOS__ */
|
||||
|
||||
#ifdef USE_VARARGS
|
||||
#include <varargs.h>
|
||||
#endif /* USE_VARARGS */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "getarg.h"
|
||||
|
||||
#define MYMALLOC /* If no "MyAlloc" routine elsewhere define this. */
|
||||
|
||||
#define MAX_PARAM 100 /* maximum number of parameters allowed. */
|
||||
#define CTRL_STR_MAX_LEN 1024
|
||||
|
||||
#define SPACE_CHAR '|' /* The character not to print using HowTo. */
|
||||
|
||||
#ifndef TRUE
|
||||
#define TRUE -1
|
||||
#define FALSE 0
|
||||
#endif /* TRUE */
|
||||
|
||||
#define ARG_OK 0
|
||||
|
||||
#define ISSPACE(x) ((x) <= ' ') /* Not conventional - but works fine! */
|
||||
/* The two characters '%' and '!' are used in the control string: */
|
||||
#define ISCTRLCHAR(x) (((x) == '%') || ((x) == '!'))
|
||||
|
||||
static char *GAErrorToken;/* On error code, ErrorToken is set to point on it.*/
|
||||
|
||||
static int GATestAllSatis(char *CtrlStrCopy, char *CtrlStr, int *argc,
|
||||
char ***argv, int *Parameters[MAX_PARAM], int *ParamCount);
|
||||
static int GAUpdateParameters(int *Parameters[], int *ParamCount,
|
||||
char *Option, char *CtrlStrCopy, char *CtrlStr, int *argc,
|
||||
char ***argv);
|
||||
static int GAGetParmeters(int *Parameters[], int *ParamCount,
|
||||
char *CtrlStrCopy , char *Option, int *argc, char ***argv);
|
||||
static int GAGetMultiParmeters(int *Parameters[], int *ParamCount,
|
||||
char *CtrlStrCopy, int *argc, char ***argv);
|
||||
static void GASetParamCount(char *CtrlStr, int Max, int *ParamCount);
|
||||
static void GAByteCopy(char *Dst, char *Src, unsigned n);
|
||||
static int GAOptionExists(int argc, char **argv);
|
||||
#ifdef MYMALLOC
|
||||
static char *MyMalloc(unsigned size);
|
||||
#endif /* MYMALLOC */
|
||||
|
||||
/***************************************************************************
|
||||
* Routine to access the command line argument and interpret them: *
|
||||
* Return ARG_OK (0) is case of succesfull parsing, error code else... *
|
||||
***************************************************************************/
|
||||
#ifdef USE_VARARGS
|
||||
int GAGetArgs(int va_alist, ...)
|
||||
{
|
||||
va_list ap;
|
||||
int argc, i, Error = FALSE, ParamCount = 0,
|
||||
*Parameters[MAX_PARAM]; /* Save here parameter addresses. */
|
||||
char **argv, *CtrlStr, *Option, CtrlStrCopy[CTRL_STR_MAX_LEN];
|
||||
|
||||
va_start(ap);
|
||||
|
||||
argc = va_arg(ap, int);
|
||||
argv = va_arg(ap, char **);
|
||||
CtrlStr = va_arg(ap, char *);
|
||||
|
||||
va_end(ap);
|
||||
|
||||
strcpy(CtrlStrCopy, CtrlStr);
|
||||
|
||||
/* Using base address of parameters we access other parameters addr: */
|
||||
/* Note that me (for sure!) samples data beyond the current function */
|
||||
/* frame, but we accesson these set address only by demand. */
|
||||
for (i = 1; i <= MAX_PARAM; i++) Parameters[i-1] = va_arg(ap, int *);
|
||||
#else
|
||||
int GAGetArgs(int argc, char **argv, char *CtrlStr, ...)
|
||||
{
|
||||
int i, Error = FALSE, ParamCount = 0,
|
||||
*Parameters[MAX_PARAM]; /* Save here parameter addresses. */
|
||||
char *Option, CtrlStrCopy[CTRL_STR_MAX_LEN];
|
||||
|
||||
strcpy(CtrlStrCopy, CtrlStr);
|
||||
|
||||
/* Using base address of parameters we access other parameters addr: */
|
||||
/* Note that me (for sure!) samples data beyond the current function */
|
||||
/* frame, but we accesson these set address only by demand. */
|
||||
for (i = 1; i <= MAX_PARAM; i++) Parameters[i-1] = (int *) *(i + &CtrlStr);
|
||||
#endif /* USE_VARARG */
|
||||
|
||||
--argc; argv++; /* Skip the program name (first in argv/c list). */
|
||||
while (argc >= 0) {
|
||||
if (!GAOptionExists(argc, argv)) break; /* The loop. */
|
||||
argc--;
|
||||
Option = *argv++;
|
||||
if ((Error = GAUpdateParameters(Parameters, &ParamCount, Option,
|
||||
CtrlStrCopy, CtrlStr, &argc, &argv)) != FALSE) return Error;
|
||||
}
|
||||
/* Check for results and update trail of command line: */
|
||||
return GATestAllSatis(CtrlStrCopy, CtrlStr, &argc, &argv, Parameters,
|
||||
&ParamCount);
|
||||
}
|
||||
|
||||
/***************************************************************************
|
||||
* Routine to search for unsatisfied flags - simply scan the list for !- *
|
||||
* sequence. Before this scan, this routine updates the rest of the command *
|
||||
* line into the last two parameters if it is requested by the CtrlStr *
|
||||
* (last item in CtrlStr is NOT an option). *
|
||||
* Return ARG_OK if all satisfied, CMD_ERR_AllSatis error else. *
|
||||
***************************************************************************/
|
||||
static int GATestAllSatis(char *CtrlStrCopy, char *CtrlStr, int *argc,
|
||||
char ***argv, int *Parameters[MAX_PARAM], int *ParamCount)
|
||||
{
|
||||
int i;
|
||||
static char *LocalToken = NULL;
|
||||
|
||||
/* If LocalToken is not initialized - do it now. Note that this string */
|
||||
/* should be writable as well so we can not assign it directly. */
|
||||
if (LocalToken == NULL) {
|
||||
LocalToken = (char *) malloc(3);
|
||||
strcpy(LocalToken, "-?");
|
||||
}
|
||||
|
||||
/* Check is last item is an option. If not then copy rest of command */
|
||||
/* line into it as 1. NumOfprm, 2. pointer to block of pointers. */
|
||||
for (i = strlen(CtrlStr) - 1; i > 0 && !ISSPACE(CtrlStr[i]); i--);
|
||||
if (!ISCTRLCHAR(CtrlStr[i + 2])) {
|
||||
GASetParamCount(CtrlStr, i, ParamCount); /* Point in correct prm.. */
|
||||
*Parameters[(*ParamCount)++] = *argc;
|
||||
GAByteCopy((char *) Parameters[(*ParamCount)++], (char *) argv,
|
||||
sizeof(char *));
|
||||
}
|
||||
|
||||
i = 0;
|
||||
while (++i < strlen(CtrlStrCopy))
|
||||
if ((CtrlStrCopy[i] == '-') && (CtrlStrCopy[i-1] == '!')) {
|
||||
GAErrorToken = LocalToken;
|
||||
LocalToken[1] = CtrlStrCopy[i-2]; /* Set the corrent flag. */
|
||||
return CMD_ERR_AllSatis;
|
||||
}
|
||||
|
||||
return ARG_OK;
|
||||
}
|
||||
|
||||
/***************************************************************************
|
||||
* Routine to update the parameters according to the given Option: *
|
||||
***************************************************************************/
|
||||
static int GAUpdateParameters(int *Parameters[], int *ParamCount,
|
||||
char *Option, char *CtrlStrCopy, char *CtrlStr, int *argc, char ***argv)
|
||||
{
|
||||
int i, BooleanTrue = Option[2] != '-';
|
||||
|
||||
if (Option[0] != '-') {
|
||||
GAErrorToken = Option;
|
||||
return CMD_ERR_NotAnOpt;
|
||||
}
|
||||
i = 0; /* Scan the CtrlStrCopy for that option: */
|
||||
while (i + 2 < strlen(CtrlStrCopy)) {
|
||||
if ((CtrlStrCopy[i] == Option[1]) && (ISCTRLCHAR(CtrlStrCopy[i + 1]))
|
||||
&& (CtrlStrCopy[i+2] == '-')) {
|
||||
/* We found that option! */
|
||||
break;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
if (i + 2 >= strlen(CtrlStrCopy)) {
|
||||
GAErrorToken = Option;
|
||||
return CMD_ERR_NoSuchOpt;
|
||||
}
|
||||
|
||||
/* If we are here, then we found that option in CtrlStr - Strip it off: */
|
||||
CtrlStrCopy[i] = CtrlStrCopy[i + 1] = CtrlStrCopy[i + 2] = (char) ' ';
|
||||
GASetParamCount(CtrlStr, i, ParamCount);/*Set it to point in correct prm.*/
|
||||
i += 3;
|
||||
/* Set boolean flag for that option. */
|
||||
*Parameters[(*ParamCount)++] = BooleanTrue;
|
||||
if (ISSPACE(CtrlStrCopy[i]))
|
||||
return ARG_OK; /* Only a boolean flag is needed. */
|
||||
|
||||
/* Skip the text between the boolean option and data follows: */
|
||||
while (!ISCTRLCHAR(CtrlStrCopy[i])) i++;
|
||||
/* Get the parameters and return the appropriete return code: */
|
||||
return GAGetParmeters(Parameters, ParamCount, &CtrlStrCopy[i],
|
||||
Option, argc, argv);
|
||||
}
|
||||
|
||||
/***************************************************************************
|
||||
* Routine to get parameters according to the CtrlStr given from argv/c : *
|
||||
***************************************************************************/
|
||||
static int GAGetParmeters(int *Parameters[], int *ParamCount,
|
||||
char *CtrlStrCopy , char *Option, int *argc, char ***argv)
|
||||
{
|
||||
int i = 0, ScanRes;
|
||||
|
||||
while (!(ISSPACE(CtrlStrCopy[i]))) {
|
||||
switch (CtrlStrCopy[i+1]) {
|
||||
case 'd': /* Get signed integers. */
|
||||
ScanRes = sscanf(*((*argv)++), "%d",
|
||||
(int *) Parameters[(*ParamCount)++]);
|
||||
break;
|
||||
case 'u': /* Get unsigned integers. */
|
||||
ScanRes = sscanf(*((*argv)++), "%u",
|
||||
(unsigned *) Parameters[(*ParamCount)++]);
|
||||
break;
|
||||
case 'x': /* Get hex integers. */
|
||||
ScanRes = sscanf(*((*argv)++), "%x",
|
||||
(int *) Parameters[(*ParamCount)++]);
|
||||
break;
|
||||
case 'o': /* Get octal integers. */
|
||||
ScanRes = sscanf(*((*argv)++), "%o",
|
||||
(int *) Parameters[(*ParamCount)++]);
|
||||
break;
|
||||
case 'D': /* Get signed long integers. */
|
||||
ScanRes = sscanf(*((*argv)++), "%ld",
|
||||
(long *) Parameters[(*ParamCount)++]);
|
||||
break;
|
||||
case 'U': /* Get unsigned long integers. */
|
||||
ScanRes = sscanf(*((*argv)++), "%lu",
|
||||
(unsigned long *) Parameters[(*ParamCount)++]);
|
||||
break;
|
||||
case 'X': /* Get hex long integers. */
|
||||
ScanRes = sscanf(*((*argv)++), "%lx",
|
||||
(long *) Parameters[(*ParamCount)++]);
|
||||
break;
|
||||
case 'O': /* Get octal long integers. */
|
||||
ScanRes = sscanf(*((*argv)++), "%lo",
|
||||
(long *) Parameters[(*ParamCount)++]);
|
||||
break;
|
||||
case 'f': /* Get float number. */
|
||||
ScanRes = sscanf(*((*argv)++), "%f",
|
||||
(float *) Parameters[(*ParamCount)++]);
|
||||
case 'F': /* Get double float number. */
|
||||
ScanRes = sscanf(*((*argv)++), "%lf",
|
||||
(double *) Parameters[(*ParamCount)++]);
|
||||
break;
|
||||
case 's': /* It as a string. */
|
||||
ScanRes = 1; /* Allways O.K. */
|
||||
GAByteCopy((char *) Parameters[(*ParamCount)++],
|
||||
(char *) ((*argv)++), sizeof(char *));
|
||||
break;
|
||||
case '*': /* Get few parameters into one: */
|
||||
ScanRes = GAGetMultiParmeters(Parameters, ParamCount,
|
||||
&CtrlStrCopy[i], argc, argv);
|
||||
if ((ScanRes == 0) && (CtrlStrCopy[i] == '!')) {
|
||||
GAErrorToken = Option;
|
||||
return CMD_ERR_WildEmpty;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
ScanRes = 0; /* Make optimizer warning silent. */
|
||||
}
|
||||
/* If reading fails and this number is a must (!) then error: */
|
||||
if ((ScanRes == 0) && (CtrlStrCopy[i] == '!')) {
|
||||
GAErrorToken = Option;
|
||||
return CMD_ERR_NumRead;
|
||||
}
|
||||
if (CtrlStrCopy[i+1] != '*') {
|
||||
(*argc)--; /* Everything is OK - update to next parameter: */
|
||||
i += 2; /* Skip to next parameter (if any). */
|
||||
}
|
||||
else
|
||||
i += 3; /* Skip the '*' also! */
|
||||
}
|
||||
|
||||
return ARG_OK;
|
||||
}
|
||||
|
||||
/***************************************************************************
|
||||
* Routine to get few parameters into one pointer such that the returned *
|
||||
* pointer actually points on a block of pointers to the parameters... *
|
||||
* For example *F means a pointer to pointers on floats. *
|
||||
* Returns number of parameters actually read. *
|
||||
* This routine assumes that all pointers (on any kind of scalar) has the *
|
||||
* same size (and the union below is totally ovelapped bteween dif. arrays) *
|
||||
***************************************************************************/
|
||||
static int GAGetMultiParmeters(int *Parameters[], int *ParamCount,
|
||||
char *CtrlStrCopy, int *argc, char ***argv)
|
||||
{
|
||||
int i = 0, ScanRes, NumOfPrm = 0, **Pmain, **Ptemp;
|
||||
union TmpArray { /* Save here the temporary data before copying it to */
|
||||
int *IntArray[MAX_PARAM]; /* the returned pointer block. */
|
||||
long *LngArray[MAX_PARAM];
|
||||
float *FltArray[MAX_PARAM];
|
||||
double *DblArray[MAX_PARAM];
|
||||
char *ChrArray[MAX_PARAM];
|
||||
} TmpArray;
|
||||
|
||||
do {
|
||||
switch(CtrlStrCopy[2]) { /* CtrlStr == '!*?' or '%*?' where ? is. */
|
||||
case 'd': /* Format to read the parameters: */
|
||||
TmpArray.IntArray[NumOfPrm] = (int *) MyMalloc(sizeof(int));
|
||||
ScanRes = sscanf(*((*argv)++), "%d",
|
||||
(int *) TmpArray.IntArray[NumOfPrm++]);
|
||||
break;
|
||||
case 'u':
|
||||
TmpArray.IntArray[NumOfPrm] = (int *) MyMalloc(sizeof(int));
|
||||
ScanRes = sscanf(*((*argv)++), "%u",
|
||||
(unsigned int *) TmpArray.IntArray[NumOfPrm++]);
|
||||
break;
|
||||
case 'o':
|
||||
TmpArray.IntArray[NumOfPrm] = (int *) MyMalloc(sizeof(int));
|
||||
ScanRes = sscanf(*((*argv)++), "%o",
|
||||
(int *) TmpArray.IntArray[NumOfPrm++]);
|
||||
break;
|
||||
case 'x':
|
||||
TmpArray.IntArray[NumOfPrm] = (int *) MyMalloc(sizeof(int));
|
||||
ScanRes = sscanf(*((*argv)++), "%x",
|
||||
(int *) TmpArray.IntArray[NumOfPrm++]);
|
||||
break;
|
||||
case 'D':
|
||||
TmpArray.LngArray[NumOfPrm] = (long *) MyMalloc(sizeof(long));
|
||||
ScanRes = sscanf(*((*argv)++), "%ld",
|
||||
(long *) TmpArray.IntArray[NumOfPrm++]);
|
||||
break;
|
||||
case 'U':
|
||||
TmpArray.LngArray[NumOfPrm] = (long *) MyMalloc(sizeof(long));
|
||||
ScanRes = sscanf(*((*argv)++), "%lu",
|
||||
(unsigned long *) TmpArray.IntArray[NumOfPrm++]);
|
||||
break;
|
||||
case 'O':
|
||||
TmpArray.LngArray[NumOfPrm] = (long *) MyMalloc(sizeof(long));
|
||||
ScanRes = sscanf(*((*argv)++), "%lo",
|
||||
(long *) TmpArray.IntArray[NumOfPrm++]);
|
||||
break;
|
||||
case 'X':
|
||||
TmpArray.LngArray[NumOfPrm] = (long *) MyMalloc(sizeof(long));
|
||||
ScanRes = sscanf(*((*argv)++), "%lx",
|
||||
(long *) TmpArray.IntArray[NumOfPrm++]);
|
||||
break;
|
||||
case 'f':
|
||||
TmpArray.FltArray[NumOfPrm] = (float *) MyMalloc(sizeof(float));
|
||||
ScanRes = sscanf(*((*argv)++), "%f",
|
||||
(float *) TmpArray.LngArray[NumOfPrm++]);
|
||||
break;
|
||||
case 'F':
|
||||
TmpArray.DblArray[NumOfPrm] =
|
||||
(double *) MyMalloc(sizeof(double));
|
||||
ScanRes = sscanf(*((*argv)++), "%lf",
|
||||
(double *) TmpArray.LngArray[NumOfPrm++]);
|
||||
break;
|
||||
case 's':
|
||||
while ((*argc) && ((**argv)[0] != '-')) {
|
||||
TmpArray.ChrArray[NumOfPrm++] = *((*argv)++);
|
||||
(*argc)--;
|
||||
}
|
||||
ScanRes = 0; /* Force quit from do - loop. */
|
||||
NumOfPrm++; /* Updated again immediately after loop! */
|
||||
(*argv)++; /* "" */
|
||||
break;
|
||||
default:
|
||||
ScanRes = 0; /* Make optimizer warning silent. */
|
||||
}
|
||||
(*argc)--;
|
||||
}
|
||||
while (ScanRes == 1); /* Exactly one parameter was read. */
|
||||
(*argv)--; NumOfPrm--; (*argc)++;
|
||||
|
||||
/* Now allocate the block with the exact size, and set it: */
|
||||
Ptemp = Pmain = (int **) MyMalloc((unsigned) (NumOfPrm+1) * sizeof(int *));
|
||||
/* And here we use the assumption that all pointers are the same: */
|
||||
for (i = 0; i < NumOfPrm; i++)
|
||||
*Ptemp++ = TmpArray.IntArray[i];
|
||||
*Ptemp = NULL; /* Close the block with NULL pointer. */
|
||||
|
||||
/* That it save the number of parameters read as first parameter to */
|
||||
/* return and the pointer to the block as second, and return: */
|
||||
*Parameters[(*ParamCount)++] = NumOfPrm;
|
||||
GAByteCopy((char *) Parameters[(*ParamCount)++], (char *) &Pmain,
|
||||
sizeof(char *));
|
||||
return NumOfPrm;
|
||||
}
|
||||
|
||||
/***************************************************************************
|
||||
* Routine to scan the CtrlStr, upto Max and count the number of parameters *
|
||||
* to that point: *
|
||||
* 1. Each option is counted as one parameter - boolean variable (int) *
|
||||
* 2. Within an option, each %? or !? is counted once - pointer to something*
|
||||
* 3. Within an option, %*? or !*? is counted twice - one for item count *
|
||||
* and one for pointer to block pointers. *
|
||||
* Note ALL variables are passed by address and so of fixed size (address). *
|
||||
***************************************************************************/
|
||||
static void GASetParamCount(char *CtrlStr, int Max, int *ParamCount)
|
||||
{
|
||||
int i;
|
||||
|
||||
*ParamCount = 0;
|
||||
for (i = 0; i < Max; i++) if (ISCTRLCHAR(CtrlStr[i])) {
|
||||
if (CtrlStr[i+1] == '*')
|
||||
*ParamCount += 2;
|
||||
else
|
||||
(*ParamCount)++;
|
||||
}
|
||||
}
|
||||
|
||||
/***************************************************************************
|
||||
* Routine to copy exactly n bytes from Src to Dst. Note system library *
|
||||
* routine strncpy should do the same, but it stops on NULL char ! *
|
||||
***************************************************************************/
|
||||
static void GAByteCopy(char *Dst, char *Src, unsigned n)
|
||||
{
|
||||
while (n--) *(Dst++) = *(Src++);
|
||||
}
|
||||
|
||||
/***************************************************************************
|
||||
* Routine to check if more option (i.e. first char == '-') exists in the *
|
||||
* given list argc, argv: *
|
||||
***************************************************************************/
|
||||
static int GAOptionExists(int argc, char **argv)
|
||||
{
|
||||
while (argc--)
|
||||
if ((*argv++)[0] == '-') return TRUE;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/***************************************************************************
|
||||
* Routine to print some error messages, for this module: *
|
||||
***************************************************************************/
|
||||
void GAPrintErrMsg(int Error)
|
||||
{
|
||||
fprintf(stderr, "Error in command line parsing - ");
|
||||
switch (Error) {
|
||||
case 0:;
|
||||
fprintf(stderr, "Undefined error");
|
||||
break;
|
||||
case CMD_ERR_NotAnOpt:
|
||||
fprintf(stderr, "None option Found");
|
||||
break;
|
||||
case CMD_ERR_NoSuchOpt:
|
||||
fprintf(stderr, "Undefined option Found");
|
||||
break;
|
||||
case CMD_ERR_WildEmpty:
|
||||
fprintf(stderr, "Empty input for '!*?' seq.");
|
||||
break;
|
||||
case CMD_ERR_NumRead:
|
||||
fprintf(stderr, "Failed on reading number");
|
||||
break;
|
||||
case CMD_ERR_AllSatis:
|
||||
fprintf(stderr, "Fail to satisfy");
|
||||
break;
|
||||
}
|
||||
fprintf(stderr, " - '%s'.\n", GAErrorToken);
|
||||
}
|
||||
|
||||
/***************************************************************************
|
||||
* Routine to print correct format of command line allowed: *
|
||||
***************************************************************************/
|
||||
void GAPrintHowTo(char *CtrlStr)
|
||||
{
|
||||
int i = 0, SpaceFlag;
|
||||
|
||||
fprintf(stderr, "Usage: ");
|
||||
/* Print program name - first word in ctrl. str. (optional): */
|
||||
while (!(ISSPACE(CtrlStr[i])) && (!ISCTRLCHAR(CtrlStr[i+1])))
|
||||
fprintf(stderr, "%c", CtrlStr[i++]);
|
||||
|
||||
while (i < strlen(CtrlStr)) {
|
||||
while ((ISSPACE(CtrlStr[i])) && (i < strlen(CtrlStr))) i++;
|
||||
switch (CtrlStr[i+1]) {
|
||||
case '%':
|
||||
fprintf(stderr, " [-%c", CtrlStr[i++]);
|
||||
i += 2; /* Skip the '%-' or '!- after the char! */
|
||||
SpaceFlag = TRUE;
|
||||
while (!ISCTRLCHAR(CtrlStr[i]) && (i < strlen(CtrlStr)) &&
|
||||
(!ISSPACE(CtrlStr[i])))
|
||||
if (SpaceFlag) {
|
||||
if (CtrlStr[i++] == SPACE_CHAR)
|
||||
fprintf(stderr, " ");
|
||||
else
|
||||
fprintf(stderr, " %c", CtrlStr[i-1]);
|
||||
SpaceFlag = FALSE;
|
||||
}
|
||||
else if (CtrlStr[i++] == SPACE_CHAR)
|
||||
fprintf(stderr, " ");
|
||||
else
|
||||
fprintf(stderr, "%c", CtrlStr[i-1]);
|
||||
while (!ISSPACE(CtrlStr[i]) && (i < strlen(CtrlStr))) {
|
||||
if (CtrlStr[i] == '*') fprintf(stderr, "...");
|
||||
i++; /* Skip the rest of it. */
|
||||
}
|
||||
fprintf(stderr, "]");
|
||||
break;
|
||||
case '!':
|
||||
fprintf(stderr, " -%c", CtrlStr[i++]);
|
||||
i += 2; /* Skip the '%-' or '!- after the char! */
|
||||
SpaceFlag = TRUE;
|
||||
while (!ISCTRLCHAR(CtrlStr[i]) && (i < strlen(CtrlStr)) &&
|
||||
(!ISSPACE(CtrlStr[i])))
|
||||
if (SpaceFlag) {
|
||||
if (CtrlStr[i++] == SPACE_CHAR)
|
||||
fprintf(stderr, " ");
|
||||
else
|
||||
fprintf(stderr, " %c", CtrlStr[i-1]);
|
||||
SpaceFlag = FALSE;
|
||||
}
|
||||
else if (CtrlStr[i++] == SPACE_CHAR)
|
||||
fprintf(stderr, " ");
|
||||
else
|
||||
fprintf(stderr, "%c", CtrlStr[i-1]);
|
||||
while (!ISSPACE(CtrlStr[i]) && (i < strlen(CtrlStr))) {
|
||||
if (CtrlStr[i] == '*') fprintf(stderr, "...");
|
||||
i++; /* Skip the rest of it. */
|
||||
}
|
||||
break;
|
||||
default: /* Not checked, but must be last one! */
|
||||
fprintf(stderr, " ");
|
||||
while (!ISSPACE(CtrlStr[i]) && (i < strlen(CtrlStr)) &&
|
||||
!ISCTRLCHAR(CtrlStr[i]))
|
||||
fprintf(stderr, "%c", CtrlStr[i++]);
|
||||
fprintf(stderr, "\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
fprintf(stderr, "\n");
|
||||
}
|
||||
|
||||
#ifdef MYMALLOC
|
||||
|
||||
/***************************************************************************
|
||||
* My Routine to allocate dynamic memory. All program requests must call *
|
||||
* this routine (no direct call to malloc). Dies if no memory. *
|
||||
***************************************************************************/
|
||||
static char *MyMalloc(unsigned size)
|
||||
{
|
||||
char *p;
|
||||
|
||||
if ((p = (char *) malloc(size)) != NULL) return p;
|
||||
|
||||
fprintf(stderr, "Not enough memory, exit.\n");
|
||||
exit(2);
|
||||
|
||||
return NULL; /* Makes warning silent. */
|
||||
}
|
||||
|
||||
#endif /* MYMALLOC */
|
28
G/LIB/GETARG.H
Normal file
28
G/LIB/GETARG.H
Normal file
@ -0,0 +1,28 @@
|
||||
/***************************************************************************
|
||||
* Error numbers as returned by GAGetArg routine: *
|
||||
* *
|
||||
* Gershon Elber Mar 88 *
|
||||
****************************************************************************
|
||||
* History: *
|
||||
* 11 Mar 88 - Version 1.0 by Gershon Elber. *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef GET_ARG_H
|
||||
#define GET_ARG_H
|
||||
|
||||
#define CMD_ERR_NotAnOpt 1 /* None Option found. */
|
||||
#define CMD_ERR_NoSuchOpt 2 /* Undefined Option Found. */
|
||||
#define CMD_ERR_WildEmpty 3 /* Empty input for !*? seq. */
|
||||
#define CMD_ERR_NumRead 4 /* Failed on reading number. */
|
||||
#define CMD_ERR_AllSatis 5 /* Fail to satisfy (must-'!') option. */
|
||||
|
||||
#ifdef USE_VARARGS
|
||||
int GAGetArgs(int va_alist, ...);
|
||||
#else
|
||||
int GAGetArgs(int argc, char **argv, char *CtrlStr, ...);
|
||||
#endif /* USE_VARARGS */
|
||||
|
||||
void GAPrintErrMsg(int Error);
|
||||
void GAPrintHowTo(char *CtrlStr);
|
||||
|
||||
#endif /* GET_ARG_H */
|
130
G/LIB/GIF_ERR.C
Normal file
130
G/LIB/GIF_ERR.C
Normal file
@ -0,0 +1,130 @@
|
||||
/*****************************************************************************
|
||||
* "Gif-Lib" - Yet another gif library. *
|
||||
* *
|
||||
* Written by: Gershon Elber IBM PC Ver 0.1, Jun. 1989 *
|
||||
******************************************************************************
|
||||
* Handle error reporting for the GIF library. *
|
||||
******************************************************************************
|
||||
* History: *
|
||||
* 17 Jun 89 - Version 1.0 by Gershon Elber. *
|
||||
*****************************************************************************/
|
||||
|
||||
#include <stdio.h>
|
||||
#include "gif_lib.h"
|
||||
|
||||
#define PROGRAM_NAME "GIF_LIBRARY"
|
||||
|
||||
int _GifError = 0;
|
||||
|
||||
#ifdef SYSV
|
||||
static char *VersionStr =
|
||||
"Gif library module,\t\tGershon Elber\n\
|
||||
(C) Copyright 1989 Gershon Elber, Non commercial use only.\n";
|
||||
#else
|
||||
static char *VersionStr =
|
||||
PROGRAM_NAME
|
||||
" IBMPC "
|
||||
GIF_LIB_VERSION
|
||||
" Gershon Elber, "
|
||||
__DATE__ ", " __TIME__ "\n"
|
||||
"(C) Copyright 1989 Gershon Elber, Non commercial use only.\n";
|
||||
#endif /* SYSV */
|
||||
|
||||
/*****************************************************************************
|
||||
* Return the last GIF error (0 if none) and reset the error. *
|
||||
*****************************************************************************/
|
||||
int GifLastError(void)
|
||||
{
|
||||
int i = _GifError;
|
||||
|
||||
_GifError = 0;
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* Print the last GIF error to stderr. *
|
||||
*****************************************************************************/
|
||||
void PrintGifError(void)
|
||||
{
|
||||
char *Err;
|
||||
|
||||
switch(_GifError) {
|
||||
case E_GIF_ERR_OPEN_FAILED:
|
||||
Err = "Failed to open given file";
|
||||
break;
|
||||
case E_GIF_ERR_WRITE_FAILED:
|
||||
Err = "Failed to Write to given file";
|
||||
break;
|
||||
case E_GIF_ERR_HAS_SCRN_DSCR:
|
||||
Err = "Screen Descriptor already been set";
|
||||
break;
|
||||
case E_GIF_ERR_HAS_IMAG_DSCR:
|
||||
Err = "Image Descriptor is still active";
|
||||
break;
|
||||
case E_GIF_ERR_NO_COLOR_MAP:
|
||||
Err = "Neither Global Nor Local color map";
|
||||
break;
|
||||
case E_GIF_ERR_DATA_TOO_BIG:
|
||||
Err = "#Pixels bigger than Width * Height";
|
||||
break;
|
||||
case E_GIF_ERR_NOT_ENOUGH_MEM:
|
||||
Err = "Fail to allocate required memory";
|
||||
break;
|
||||
case E_GIF_ERR_DISK_IS_FULL:
|
||||
Err = "Write failed (disk full?)";
|
||||
break;
|
||||
case E_GIF_ERR_CLOSE_FAILED:
|
||||
Err = "Failed to close given file";
|
||||
break;
|
||||
case E_GIF_ERR_NOT_WRITEABLE:
|
||||
Err = "Given file was not opened for write";
|
||||
break;
|
||||
case D_GIF_ERR_OPEN_FAILED:
|
||||
Err = "Failed to open given file";
|
||||
break;
|
||||
case D_GIF_ERR_READ_FAILED:
|
||||
Err = "Failed to Read from given file";
|
||||
break;
|
||||
case D_GIF_ERR_NOT_GIF_FILE:
|
||||
Err = "Given file is NOT GIF file";
|
||||
break;
|
||||
case D_GIF_ERR_NO_SCRN_DSCR:
|
||||
Err = "No Screen Descriptor detected";
|
||||
break;
|
||||
case D_GIF_ERR_NO_IMAG_DSCR:
|
||||
Err = "No Image Descriptor detected";
|
||||
break;
|
||||
case D_GIF_ERR_NO_COLOR_MAP:
|
||||
Err = "Neither Global Nor Local color map";
|
||||
break;
|
||||
case D_GIF_ERR_WRONG_RECORD:
|
||||
Err = "Wrong record type detected";
|
||||
break;
|
||||
case D_GIF_ERR_DATA_TOO_BIG:
|
||||
Err = "#Pixels bigger than Width * Height";
|
||||
break;
|
||||
case D_GIF_ERR_NOT_ENOUGH_MEM:
|
||||
Err = "Fail to allocate required memory";
|
||||
break;
|
||||
case D_GIF_ERR_CLOSE_FAILED:
|
||||
Err = "Failed to close given file";
|
||||
break;
|
||||
case D_GIF_ERR_NOT_READABLE:
|
||||
Err = "Given file was not opened for read";
|
||||
break;
|
||||
case D_GIF_ERR_IMAGE_DEFECT:
|
||||
Err = "Image is defective, decoding aborted";
|
||||
break;
|
||||
case D_GIF_ERR_EOF_TOO_SOON:
|
||||
Err = "Image EOF detected, before image complete";
|
||||
break;
|
||||
default:
|
||||
Err = NULL;
|
||||
break;
|
||||
}
|
||||
if (Err != NULL)
|
||||
fprintf(stderr, "\nGIF-LIB error: %s.\n", Err);
|
||||
else
|
||||
fprintf(stderr, "\nGIF-LIB undefined error %d.\n", _GifError);
|
||||
}
|
155
G/LIB/GIF_HASH.C
Normal file
155
G/LIB/GIF_HASH.C
Normal file
@ -0,0 +1,155 @@
|
||||
/*****************************************************************************
|
||||
* "Gif-Lib" - Yet another gif library. *
|
||||
* *
|
||||
* Written by: Gershon Elber IBM PC Ver 0.1, Jun. 1989 *
|
||||
******************************************************************************
|
||||
* Module to support the following operations: *
|
||||
* *
|
||||
* 1. InitHashTable - initialize hash table. *
|
||||
* 2. ClearHashTable - clear the hash table to an empty state. *
|
||||
* 2. InsertHashTable - insert one item into data structure. *
|
||||
* 3. ExistsHashTable - test if item exists in data structure. *
|
||||
* *
|
||||
* This module is used to hash the GIF codes during encoding. *
|
||||
******************************************************************************
|
||||
* History: *
|
||||
* 14 Jun 89 - Version 1.0 by Gershon Elber. *
|
||||
*****************************************************************************/
|
||||
|
||||
#ifdef __MSDOS__
|
||||
#include <io.h>
|
||||
#include <alloc.h>
|
||||
#include <sys\stat.h>
|
||||
#else
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#endif /* __MSDOS__ */
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "gif_lib.h"
|
||||
#include "gif_hash.h"
|
||||
|
||||
#define PROGRAM_NAME "GIF_LIBRARY"
|
||||
|
||||
/* #define DEBUG_HIT_RATE Debug number of misses per hash Insert/Exists. */
|
||||
|
||||
#ifdef DEBUG_HIT_RATE
|
||||
static long NumberOfTests = 0,
|
||||
NumberOfMisses = 0;
|
||||
#endif /* DEBUG_HIT_RATE */
|
||||
|
||||
#ifdef SYSV
|
||||
static char *VersionStr =
|
||||
"Gif library module,\t\tGershon Elber\n\
|
||||
(C) Copyright 1989 Gershon Elber, Non commercial use only.\n";
|
||||
#else
|
||||
static char *VersionStr =
|
||||
PROGRAM_NAME
|
||||
" IBMPC "
|
||||
GIF_LIB_VERSION
|
||||
" Gershon Elber, "
|
||||
__DATE__ ", " __TIME__ "\n"
|
||||
"(C) Copyright 1989 Gershon Elber, Non commercial use only.\n";
|
||||
#endif /* SYSV */
|
||||
|
||||
static int KeyItem(unsigned long Item);
|
||||
|
||||
/******************************************************************************
|
||||
* Initialize HashTable - allocate the memory needed and clear it. *
|
||||
******************************************************************************/
|
||||
GifHashTableType *_InitHashTable(void)
|
||||
{
|
||||
GifHashTableType *HashTable;
|
||||
|
||||
if ((HashTable = (GifHashTableType *) malloc(sizeof(GifHashTableType)))
|
||||
== NULL)
|
||||
return NULL;
|
||||
|
||||
_ClearHashTable(HashTable);
|
||||
|
||||
return HashTable;
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* Routine to clear the HashTable to an empty state. *
|
||||
* This part is a little machine depended. Use the commented part otherwise. *
|
||||
******************************************************************************/
|
||||
void _ClearHashTable(GifHashTableType *HashTable)
|
||||
{
|
||||
memset(HashTable -> HTable, 0xFF, HT_SIZE * sizeof(long));
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* Routine to insert a new Item into the HashTable. The data is assumed to be *
|
||||
* new one. *
|
||||
******************************************************************************/
|
||||
void _InsertHashTable(GifHashTableType *HashTable, unsigned long Key, int Code)
|
||||
{
|
||||
int HKey = KeyItem(Key);
|
||||
unsigned long *HTable = HashTable -> HTable;
|
||||
|
||||
#ifdef DEBUG_HIT_RATE
|
||||
NumberOfTests++;
|
||||
NumberOfMisses++;
|
||||
#endif /* DEBUG_HIT_RATE */
|
||||
|
||||
while (HT_GET_KEY(HTable[HKey]) != 0xFFFFFL) {
|
||||
#ifdef DEBUG_HIT_RATE
|
||||
NumberOfMisses++;
|
||||
#endif /* DEBUG_HIT_RATE */
|
||||
HKey = (HKey + 1) & HT_KEY_MASK;
|
||||
}
|
||||
HTable[HKey] = HT_PUT_KEY(Key) | HT_PUT_CODE(Code);
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* Routine to test if given Key exists in HashTable and if so returns its code *
|
||||
* Returns the Code if key was found, -1 if not. *
|
||||
******************************************************************************/
|
||||
int _ExistsHashTable(GifHashTableType *HashTable, unsigned long Key)
|
||||
{
|
||||
int HKey = KeyItem(Key);
|
||||
unsigned long *HTable = HashTable -> HTable, HTKey;
|
||||
|
||||
#ifdef DEBUG_HIT_RATE
|
||||
NumberOfTests++;
|
||||
NumberOfMisses++;
|
||||
#endif /* DEBUG_HIT_RATE */
|
||||
|
||||
while ((HTKey = HT_GET_KEY(HTable[HKey])) != 0xFFFFFL) {
|
||||
#ifdef DEBUG_HIT_RATE
|
||||
NumberOfMisses++;
|
||||
#endif /* DEBUG_HIT_RATE */
|
||||
if (Key == HTKey) return HT_GET_CODE(HTable[HKey]);
|
||||
HKey = (HKey + 1) & HT_KEY_MASK;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* Routine to generate an HKey for the hashtable out of the given unique key. *
|
||||
* The given Key is assumed to be 20 bits as follows: lower 8 bits are the *
|
||||
* new postfix character, while the upper 12 bits are the prefix code. *
|
||||
* Because the average hit ratio is only 2 (2 hash references per entry), *
|
||||
* evaluating more complex keys (such as twin prime keys) does not worth it! *
|
||||
******************************************************************************/
|
||||
static int KeyItem(unsigned long Item)
|
||||
{
|
||||
return ((Item >> 12) ^ Item) & HT_KEY_MASK;
|
||||
}
|
||||
|
||||
#ifdef DEBUG_HIT_RATE
|
||||
/******************************************************************************
|
||||
* Debugging routine to print the hit ratio - number of times the hash table *
|
||||
* was tested per operation. This routine was used to test the KeyItem routine *
|
||||
******************************************************************************/
|
||||
void HashTablePrintHitRatio(void)
|
||||
{
|
||||
printf("Hash Table Hit Ratio is %ld/%ld = %ld%%.\n",
|
||||
NumberOfMisses, NumberOfTests,
|
||||
NumberOfMisses * 100 / NumberOfTests);
|
||||
}
|
||||
#endif /* DEBUG_HIT_RATE */
|
31
G/LIB/GIF_HASH.H
Normal file
31
G/LIB/GIF_HASH.H
Normal file
@ -0,0 +1,31 @@
|
||||
/******************************************************************************
|
||||
* Declarations, global to other of the GIF-HASH.C module. *
|
||||
* *
|
||||
* Written by Gershon Elber, Jun 1989 *
|
||||
*******************************************************************************
|
||||
* History: *
|
||||
* 14 Jun 89 - Version 1.0 by Gershon Elber. *
|
||||
******************************************************************************/
|
||||
|
||||
#define HT_SIZE 8192 /* 12bits = 4096 or twice as big! */
|
||||
#define HT_KEY_MASK 0x1FFF /* 13bits keys */
|
||||
#define HT_KEY_NUM_BITS 13 /* 13bits keys */
|
||||
#define HT_MAX_KEY 8191 /* 13bits - 1, maximal code possible */
|
||||
#define HT_MAX_CODE 4095 /* Biggest code possible in 12 bits. */
|
||||
|
||||
/* The 32 bits of the long are divided into two parts for the key & code: */
|
||||
/* 1. The code is 12 bits as our compression algorithm is limited to 12bits */
|
||||
/* 2. The key is 12 bits Prefix code + 8 bit new char or 20 bits. */
|
||||
#define HT_GET_KEY(l) (l >> 12)
|
||||
#define HT_GET_CODE(l) (l & 0x0FFF)
|
||||
#define HT_PUT_KEY(l) (l << 12)
|
||||
#define HT_PUT_CODE(l) (l & 0x0FFF)
|
||||
|
||||
typedef struct GifHashTableType {
|
||||
unsigned long HTable[HT_SIZE];
|
||||
} GifHashTableType;
|
||||
|
||||
GifHashTableType *_InitHashTable(void);
|
||||
void _ClearHashTable(GifHashTableType *HashTable);
|
||||
void _InsertHashTable(GifHashTableType *HashTable, unsigned long Key, int Code);
|
||||
int _ExistsHashTable(GifHashTableType *HashTable, unsigned long Key);
|
178
G/LIB/GIF_LIB.H
Normal file
178
G/LIB/GIF_LIB.H
Normal file
@ -0,0 +1,178 @@
|
||||
/******************************************************************************
|
||||
* In order to make life a little bit easier when using the GIF file format, *
|
||||
* this library was written, and which does all the dirty work... *
|
||||
* *
|
||||
* Written by Gershon Elber, Jun. 1989 *
|
||||
*******************************************************************************
|
||||
* History: *
|
||||
* 14 Jun 89 - Version 1.0 by Gershon Elber. *
|
||||
* 3 Sep 90 - Version 1.1 by Gershon Elber (Support for Gif89, Unique names). *
|
||||
******************************************************************************/
|
||||
|
||||
#ifndef GIF_LIB_H
|
||||
#define GIF_LIB_H
|
||||
|
||||
#define GIF_LIB_VERSION " Version 1.2, "
|
||||
|
||||
#define GIF_ERROR 0
|
||||
#define GIF_OK 1
|
||||
|
||||
#ifndef TRUE
|
||||
#define TRUE 1
|
||||
#define FALSE 0
|
||||
#endif
|
||||
|
||||
#define GIF_FILE_BUFFER_SIZE 16384 /* Files uses bigger buffers than usual. */
|
||||
|
||||
typedef int GifBooleanType;
|
||||
typedef unsigned char GifPixelType;
|
||||
typedef unsigned char * GifRowType;
|
||||
typedef unsigned char GifByteType;
|
||||
|
||||
#define GIF_MESSAGE(Msg) fprintf(stderr, "\n%s: %s\n", PROGRAM_NAME, Msg)
|
||||
#define GIF_EXIT(Msg) { GIF_MESSAGE(Msg); exit(-3); }
|
||||
|
||||
#ifdef SYSV
|
||||
#define VoidPtr char *
|
||||
#else
|
||||
#define VoidPtr void *
|
||||
#endif /* SYSV */
|
||||
|
||||
typedef struct GifColorType {
|
||||
GifByteType Red, Green, Blue;
|
||||
} GifColorType;
|
||||
|
||||
/* Note entries prefixed with S are of Screen information, while entries */
|
||||
/* prefixed with I are of the current defined Image. */
|
||||
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. */
|
||||
VoidPtr Private; /* The regular user should not mess with this one! */
|
||||
} GifFileType;
|
||||
|
||||
typedef enum {
|
||||
UNDEFINED_RECORD_TYPE,
|
||||
SCREEN_DESC_RECORD_TYPE,
|
||||
IMAGE_DESC_RECORD_TYPE, /* Begin with ',' */
|
||||
EXTENSION_RECORD_TYPE, /* Begin with '!' */
|
||||
TERMINATE_RECORD_TYPE /* Begin with ';' */
|
||||
} GifRecordType;
|
||||
|
||||
/* DumpScreen2Gif routine constants identify type of window/screen to dump. */
|
||||
/* Note all values below 1000 are reserved for the IBMPC different display */
|
||||
/* devices (it has many!) and are compatible with the numbering TC2.0 */
|
||||
/* (Turbo C 2.0 compiler for IBM PC) gives to these devices. */
|
||||
typedef enum {
|
||||
GIF_DUMP_SGI_WINDOW = 1000,
|
||||
GIF_DUMP_X_WINDOW = 1001
|
||||
} GifScreenDumpType;
|
||||
|
||||
/******************************************************************************
|
||||
* O.k. here are the routines one can access in order to encode GIF file: *
|
||||
* (GIF_LIB file EGIF_LIB.C). *
|
||||
******************************************************************************/
|
||||
|
||||
GifFileType *EGifOpenFileName(char *GifFileName, int GifTestExistance);
|
||||
GifFileType *EGifOpenFileHandle(int GifFileHandle);
|
||||
void EGifSetGifVersion(char *Version);
|
||||
int EGifPutScreenDesc(GifFileType *GifFile,
|
||||
int GifWidth, int GifHeight, int GifColorRes, int GifBackGround,
|
||||
int GifBitsPerPixel, GifColorType *GifColorMap);
|
||||
int EGifPutImageDesc(GifFileType *GifFile,
|
||||
int GifLeft, int GifTop, int Width, int GifHeight, int GifInterlace,
|
||||
int GifBitsPerPixel, GifColorType *GifColorMap);
|
||||
int EGifPutLine(GifFileType *GifFile, GifPixelType *GifLine, int GifLineLen);
|
||||
int EGifPutPixel(GifFileType *GifFile, GifPixelType GifPixel);
|
||||
int EGifPutComment(GifFileType *GifFile, char *GifComment);
|
||||
int EGifPutExtension(GifFileType *GifFile, int GifExtCode, int GifExtLen,
|
||||
VoidPtr GifExtension);
|
||||
int EGifPutCode(GifFileType *GifFile, int GifCodeSize,
|
||||
GifByteType *GifCodeBlock);
|
||||
int EGifPutCodeNext(GifFileType *GifFile, GifByteType *GifCodeBlock);
|
||||
int EGifCloseFile(GifFileType *GifFile);
|
||||
|
||||
#define E_GIF_ERR_OPEN_FAILED 1 /* And EGif possible errors. */
|
||||
#define E_GIF_ERR_WRITE_FAILED 2
|
||||
#define E_GIF_ERR_HAS_SCRN_DSCR 3
|
||||
#define E_GIF_ERR_HAS_IMAG_DSCR 4
|
||||
#define E_GIF_ERR_NO_COLOR_MAP 5
|
||||
#define E_GIF_ERR_DATA_TOO_BIG 6
|
||||
#define E_GIF_ERR_NOT_ENOUGH_MEM 7
|
||||
#define E_GIF_ERR_DISK_IS_FULL 8
|
||||
#define E_GIF_ERR_CLOSE_FAILED 9
|
||||
#define E_GIF_ERR_NOT_WRITEABLE 10
|
||||
|
||||
/******************************************************************************
|
||||
* O.k. here are the routines one can access in order to decode GIF file: *
|
||||
* (GIF_LIB file DGIF_LIB.C). *
|
||||
******************************************************************************/
|
||||
|
||||
GifFileType *DGifOpenFileName(char *GifFileName);
|
||||
GifFileType *DGifOpenFileHandle(int GifFileHandle);
|
||||
int DGifGetScreenDesc(GifFileType *GifFile);
|
||||
int DGifGetRecordType(GifFileType *GifFile, GifRecordType *GifType);
|
||||
int DGifGetImageDesc(GifFileType *GifFile);
|
||||
int DGifGetLine(GifFileType *GifFile, GifPixelType *GifLine, int GifLineLen);
|
||||
int DGifGetPixel(GifFileType *GifFile, GifPixelType GifPixel);
|
||||
int DGifGetComment(GifFileType *GifFile, char *GifComment);
|
||||
int DGifGetExtension(GifFileType *GifFile, int *GifExtCode,
|
||||
GifByteType **GifExtension);
|
||||
int DGifGetExtensionNext(GifFileType *GifFile, GifByteType **GifExtension);
|
||||
int DGifGetCode(GifFileType *GifFile, int *GifCodeSize,
|
||||
GifByteType **GifCodeBlock);
|
||||
int DGifGetCodeNext(GifFileType *GifFile, GifByteType **GifCodeBlock);
|
||||
int DGifGetLZCodes(GifFileType *GifFile, int *GifCode);
|
||||
int DGifCloseFile(GifFileType *GifFile);
|
||||
|
||||
#define D_GIF_ERR_OPEN_FAILED 101 /* And DGif possible errors. */
|
||||
#define D_GIF_ERR_READ_FAILED 102
|
||||
#define D_GIF_ERR_NOT_GIF_FILE 103
|
||||
#define D_GIF_ERR_NO_SCRN_DSCR 104
|
||||
#define D_GIF_ERR_NO_IMAG_DSCR 105
|
||||
#define D_GIF_ERR_NO_COLOR_MAP 106
|
||||
#define D_GIF_ERR_WRONG_RECORD 107
|
||||
#define D_GIF_ERR_DATA_TOO_BIG 108
|
||||
#define D_GIF_ERR_NOT_ENOUGH_MEM 109
|
||||
#define D_GIF_ERR_CLOSE_FAILED 110
|
||||
#define D_GIF_ERR_NOT_READABLE 111
|
||||
#define D_GIF_ERR_IMAGE_DEFECT 112
|
||||
#define D_GIF_ERR_EOF_TOO_SOON 113
|
||||
|
||||
/******************************************************************************
|
||||
* O.k. here are the routines from GIF_LIB file QUANTIZE.C. *
|
||||
******************************************************************************/
|
||||
int QuantizeBuffer(unsigned int Width, unsigned int Height, int *ColorMapSize,
|
||||
GifByteType *RedInput, GifByteType *GreenInput, GifByteType *BlueInput,
|
||||
GifByteType *OutputBuffer, GifColorType *OutputColorMap);
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
* O.k. here are the routines from GIF_LIB file QPRINTF.C. *
|
||||
******************************************************************************/
|
||||
extern int GifQuitePrint;
|
||||
|
||||
#ifdef USE_VARARGS
|
||||
void GifQprintf();
|
||||
#else
|
||||
void GifQprintf(char *Format, ...);
|
||||
#endif /* USE_VARARGS */
|
||||
|
||||
/******************************************************************************
|
||||
* O.k. here are the routines from GIF_LIB file GIF_ERR.C. *
|
||||
******************************************************************************/
|
||||
void PrintGifError(void);
|
||||
int GifLastError(void);
|
||||
|
||||
/******************************************************************************
|
||||
* O.k. here are the routines from GIF_LIB file DEV2GIF.C. *
|
||||
******************************************************************************/
|
||||
int DumpScreen2Gif(char *FileName, int ReqGraphDriver, int ReqGraphMode1,
|
||||
int ReqGraphMode2,
|
||||
int ReqGraphMode3);
|
||||
|
||||
#endif /* GIF_LIB_H */
|
BIN
G/LIB/GIF_LIBC.LIB
Normal file
BIN
G/LIB/GIF_LIBC.LIB
Normal file
Binary file not shown.
39
G/LIB/GIF_LIBC.LST
Normal file
39
G/LIB/GIF_LIBC.LST
Normal file
@ -0,0 +1,39 @@
|
||||
Publics by module
|
||||
|
||||
DEV2GIF size = 1630
|
||||
_DumpScreen2Gif
|
||||
|
||||
DGIF_LIB size = 4640
|
||||
_DGifCloseFile _DGifGetCode
|
||||
_DGifGetCodeNext _DGifGetExtension
|
||||
_DGifGetExtensionNext _DGifGetImageDesc
|
||||
_DGifGetLZCodes _DGifGetLine
|
||||
_DGifGetPixel _DGifGetRecordType
|
||||
_DGifGetScreenDesc _DGifOpenFileHandle
|
||||
_DGifOpenFileName
|
||||
|
||||
EGIF_LIB size = 4246
|
||||
_EGifCloseFile _EGifOpenFileHandle
|
||||
_EGifOpenFileName _EGifPutCode
|
||||
_EGifPutCodeNext _EGifPutComment
|
||||
_EGifPutExtension _EGifPutImageDesc
|
||||
_EGifPutLine _EGifPutPixel
|
||||
_EGifPutScreenDesc _EGifSetGifVersion
|
||||
|
||||
GETARG size = 4707
|
||||
_GAGetArgs _GAPrintErrMsg
|
||||
_GAPrintHowTo
|
||||
|
||||
GIF_ERR size = 1235
|
||||
_GifLastError _PrintGifError
|
||||
__GifError
|
||||
|
||||
GIF_HASH size = 496
|
||||
__ClearHashTable __ExistsHashTable
|
||||
__InitHashTable __InsertHashTable
|
||||
|
||||
QPRINTF size = 70
|
||||
_GifQprintf _GifQuitePrint
|
||||
|
||||
QUANTIZE size = 3217
|
||||
_QuantizeBuffer
|
BIN
G/LIB/GIF_LIBH.LIB
Normal file
BIN
G/LIB/GIF_LIBH.LIB
Normal file
Binary file not shown.
39
G/LIB/GIF_LIBH.LST
Normal file
39
G/LIB/GIF_LIBH.LST
Normal file
@ -0,0 +1,39 @@
|
||||
Publics by module
|
||||
|
||||
DEV2GIF size = 1713
|
||||
_DumpScreen2Gif
|
||||
|
||||
DGIF_LIB size = 5155
|
||||
_DGifCloseFile _DGifGetCode
|
||||
_DGifGetCodeNext _DGifGetExtension
|
||||
_DGifGetExtensionNext _DGifGetImageDesc
|
||||
_DGifGetLZCodes _DGifGetLine
|
||||
_DGifGetPixel _DGifGetRecordType
|
||||
_DGifGetScreenDesc _DGifOpenFileHandle
|
||||
_DGifOpenFileName
|
||||
|
||||
EGIF_LIB size = 4751
|
||||
_EGifCloseFile _EGifOpenFileHandle
|
||||
_EGifOpenFileName _EGifPutCode
|
||||
_EGifPutCodeNext _EGifPutComment
|
||||
_EGifPutExtension _EGifPutImageDesc
|
||||
_EGifPutLine _EGifPutPixel
|
||||
_EGifPutScreenDesc _EGifSetGifVersion
|
||||
|
||||
GETARG size = 5054
|
||||
_GAGetArgs _GAPrintErrMsg
|
||||
_GAPrintHowTo
|
||||
|
||||
GIF_ERR size = 1260
|
||||
_GifLastError _PrintGifError
|
||||
__GifError
|
||||
|
||||
GIF_HASH size = 551
|
||||
__ClearHashTable __ExistsHashTable
|
||||
__InitHashTable __InsertHashTable
|
||||
|
||||
QPRINTF size = 84
|
||||
_GifQprintf _GifQuitePrint
|
||||
|
||||
QUANTIZE size = 3287
|
||||
_QuantizeBuffer
|
BIN
G/LIB/GIF_LIBL.LIB
Normal file
BIN
G/LIB/GIF_LIBL.LIB
Normal file
Binary file not shown.
39
G/LIB/GIF_LIBL.LST
Normal file
39
G/LIB/GIF_LIBL.LST
Normal file
@ -0,0 +1,39 @@
|
||||
Publics by module
|
||||
|
||||
DEV2GIF size = 1680
|
||||
_DumpScreen2Gif
|
||||
|
||||
DGIF_LIB size = 4766
|
||||
_DGifCloseFile _DGifGetCode
|
||||
_DGifGetCodeNext _DGifGetExtension
|
||||
_DGifGetExtensionNext _DGifGetImageDesc
|
||||
_DGifGetLZCodes _DGifGetLine
|
||||
_DGifGetPixel _DGifGetRecordType
|
||||
_DGifGetScreenDesc _DGifOpenFileHandle
|
||||
_DGifOpenFileName
|
||||
|
||||
EGIF_LIB size = 4388
|
||||
_EGifCloseFile _EGifOpenFileHandle
|
||||
_EGifOpenFileName _EGifPutCode
|
||||
_EGifPutCodeNext _EGifPutComment
|
||||
_EGifPutExtension _EGifPutImageDesc
|
||||
_EGifPutLine _EGifPutPixel
|
||||
_EGifPutScreenDesc _EGifSetGifVersion
|
||||
|
||||
GETARG size = 4879
|
||||
_GAGetArgs _GAPrintErrMsg
|
||||
_GAPrintHowTo
|
||||
|
||||
GIF_ERR size = 1239
|
||||
_GifLastError _PrintGifError
|
||||
__GifError
|
||||
|
||||
GIF_HASH size = 514
|
||||
__ClearHashTable __ExistsHashTable
|
||||
__InitHashTable __InsertHashTable
|
||||
|
||||
QPRINTF size = 74
|
||||
_GifQprintf _GifQuitePrint
|
||||
|
||||
QUANTIZE size = 3253
|
||||
_QuantizeBuffer
|
BIN
G/LIB/GIF_LIBM.LIB
Normal file
BIN
G/LIB/GIF_LIBM.LIB
Normal file
Binary file not shown.
39
G/LIB/GIF_LIBM.LST
Normal file
39
G/LIB/GIF_LIBM.LST
Normal file
@ -0,0 +1,39 @@
|
||||
Publics by module
|
||||
|
||||
DEV2GIF size = 1576
|
||||
_DumpScreen2Gif
|
||||
|
||||
DGIF_LIB size = 3718
|
||||
_DGifCloseFile _DGifGetCode
|
||||
_DGifGetCodeNext _DGifGetExtension
|
||||
_DGifGetExtensionNext _DGifGetImageDesc
|
||||
_DGifGetLZCodes _DGifGetLine
|
||||
_DGifGetPixel _DGifGetRecordType
|
||||
_DGifGetScreenDesc _DGifOpenFileHandle
|
||||
_DGifOpenFileName
|
||||
|
||||
EGIF_LIB size = 3357
|
||||
_EGifCloseFile _EGifOpenFileHandle
|
||||
_EGifOpenFileName _EGifPutCode
|
||||
_EGifPutCodeNext _EGifPutComment
|
||||
_EGifPutExtension _EGifPutImageDesc
|
||||
_EGifPutLine _EGifPutPixel
|
||||
_EGifPutScreenDesc _EGifSetGifVersion
|
||||
|
||||
GETARG size = 3871
|
||||
_GAGetArgs _GAPrintErrMsg
|
||||
_GAPrintHowTo
|
||||
|
||||
GIF_ERR size = 1066
|
||||
_GifLastError _PrintGifError
|
||||
__GifError
|
||||
|
||||
GIF_HASH size = 456
|
||||
__ClearHashTable __ExistsHashTable
|
||||
__InitHashTable __InsertHashTable
|
||||
|
||||
QPRINTF size = 62
|
||||
_GifQprintf _GifQuitePrint
|
||||
|
||||
QUANTIZE size = 2876
|
||||
_QuantizeBuffer
|
BIN
G/LIB/GIF_LIBS.LIB
Normal file
BIN
G/LIB/GIF_LIBS.LIB
Normal file
Binary file not shown.
39
G/LIB/GIF_LIBS.LST
Normal file
39
G/LIB/GIF_LIBS.LST
Normal file
@ -0,0 +1,39 @@
|
||||
Publics by module
|
||||
|
||||
DEV2GIF size = 1526
|
||||
_DumpScreen2Gif
|
||||
|
||||
DGIF_LIB size = 3595
|
||||
_DGifCloseFile _DGifGetCode
|
||||
_DGifGetCodeNext _DGifGetExtension
|
||||
_DGifGetExtensionNext _DGifGetImageDesc
|
||||
_DGifGetLZCodes _DGifGetLine
|
||||
_DGifGetPixel _DGifGetRecordType
|
||||
_DGifGetScreenDesc _DGifOpenFileHandle
|
||||
_DGifOpenFileName
|
||||
|
||||
EGIF_LIB size = 3214
|
||||
_EGifCloseFile _EGifOpenFileHandle
|
||||
_EGifOpenFileName _EGifPutCode
|
||||
_EGifPutCodeNext _EGifPutComment
|
||||
_EGifPutExtension _EGifPutImageDesc
|
||||
_EGifPutLine _EGifPutPixel
|
||||
_EGifPutScreenDesc _EGifSetGifVersion
|
||||
|
||||
GETARG size = 3701
|
||||
_GAGetArgs _GAPrintErrMsg
|
||||
_GAPrintHowTo
|
||||
|
||||
GIF_ERR size = 1062
|
||||
_GifLastError _PrintGifError
|
||||
__GifError
|
||||
|
||||
GIF_HASH size = 438
|
||||
__ClearHashTable __ExistsHashTable
|
||||
__InitHashTable __InsertHashTable
|
||||
|
||||
QPRINTF size = 58
|
||||
_GifQprintf _GifQuitePrint
|
||||
|
||||
QUANTIZE size = 2840
|
||||
_QuantizeBuffer
|
63
G/LIB/MAKEFILE.TC
Normal file
63
G/LIB/MAKEFILE.TC
Normal file
@ -0,0 +1,63 @@
|
||||
#
|
||||
# This is the make file for the lib subdirectory of the GIF library
|
||||
# In order to run it tcc is assumed to be available, in addition to
|
||||
# tlib and obviously borland make.
|
||||
#
|
||||
# Usage: "make [-DMDL=model]" where model can be l (large) or c (compact) etc.
|
||||
# Note the MDL is optional with large model as default.
|
||||
#
|
||||
# Gershon Elber, Jun 1989
|
||||
#
|
||||
|
||||
|
||||
# Works only on TC++ 1.0 make and up - swap out make before invoking command.
|
||||
.SWAP
|
||||
|
||||
# Your C compiler
|
||||
CC = d:\program\borlandc\bin\bcc
|
||||
|
||||
# MDL set?
|
||||
!if !$d(MDL)
|
||||
MDL=l
|
||||
!endif
|
||||
|
||||
# Where all the include files are:
|
||||
INC = -I.
|
||||
|
||||
CFLAGS = -m$(MDL) -a- -f- -G -O -r -c -d -w -v- -y- -k- -N-
|
||||
|
||||
DEST = ..\bin
|
||||
|
||||
OBJS = dev2gif.obj egif_lib.obj dgif_lib.obj gif_hash.obj \
|
||||
qprintf.obj gif_err.obj getarg.obj quantize.obj
|
||||
# Show me better way if you know one to prepare this line for TLIB:
|
||||
POBJS = +dev2gif.obj +egif_lib.obj +dgif_lib.obj +gif_hash.obj \
|
||||
+qprintf.obj +gif_err.obj +getarg.obj +quantize.obj
|
||||
|
||||
# The {$< } is also new to TC++ 1.0 make - remove the { } pair if your make
|
||||
# choke on them (the { } signals batch mode that combines few operation at the
|
||||
# same time - very nice feature!).
|
||||
.c.obj:
|
||||
$(CC) $(INC) $(CFLAGS) {$< }
|
||||
|
||||
gif_libl.lib: $(OBJS)
|
||||
del gif_lib$(MDL).lib
|
||||
tlib gif_lib$(MDL).lib @&&!
|
||||
$(POBJS), gif_lib$(MDL).lst
|
||||
!
|
||||
copy gif_lib$(MDL).lib $(DEST)
|
||||
|
||||
dev2gif.obj: gif_lib.h
|
||||
|
||||
egif_lib.obj: gif_lib.h gif_hash.h
|
||||
|
||||
dgif_lib.obj: gif_lib.h gif_hash.h
|
||||
|
||||
gif_hash.obj: gif_lib.h gif_hash.h
|
||||
|
||||
qprintf.obj: gif_lib.h
|
||||
|
||||
gif_err.obj: gif_lib.h
|
||||
|
||||
getarg.obj: getarg.h
|
||||
|
72
G/LIB/MAKEFILE.UNX
Normal file
72
G/LIB/MAKEFILE.UNX
Normal file
@ -0,0 +1,72 @@
|
||||
#
|
||||
# This is the make file for the lib subdirectory of the GIF library
|
||||
# In order to run it gcc is assumed to be available.
|
||||
#
|
||||
# Gershon Elber, Jun 1989
|
||||
#
|
||||
|
||||
#
|
||||
# Where all the include files are:
|
||||
INCS = -I.
|
||||
|
||||
#
|
||||
# What devices we should be able to grab into gif images. Note that if
|
||||
# you enable them the associated library must be available at link time.
|
||||
# Avaiable devices:
|
||||
# 1. EGA, VGA, SVGA (800x600), Hercules - all on IBM PC only.
|
||||
# 2. SGI 4D Irix using gl library (Add -D__SGI_GL__).
|
||||
# 3. X11 using libX.a (Add -D__X11__)
|
||||
DEVS = -D__SGI_GL__
|
||||
|
||||
#
|
||||
# These are the flags for gcc, in BSD4.3 or Sun O.S. 4.0.3
|
||||
#
|
||||
# If your system has all function prototypes for gcc, replace all
|
||||
# the -Wxxx with -Wall. I can not add -Wimplicit as my system uses old cc
|
||||
# h files.
|
||||
#
|
||||
# CC = gcc
|
||||
#
|
||||
# CFLAGS = -O -c -W -Wreturn-type -Wcomment
|
||||
# CFLAGS = -g -pg -c -W -Wreturn-type -Wcomment
|
||||
#
|
||||
# for sun 4 (gunnars@ifi.uib.no). Tested using gcc 1.39.
|
||||
#
|
||||
# CFLAGS = -O -c -sun4 -W -Wreturn-type -Wcomment -DUSE_VARARGS
|
||||
# CFLAGS = -g -c -sun4 -W -Wreturn-type -Wcomment -DUSE_VARARGS
|
||||
|
||||
#
|
||||
# These are the flags for cc on SGI iris4d. O.S. IRIX 3.2
|
||||
#
|
||||
CC = cc
|
||||
#
|
||||
CFLAGS = -O -c -DSYSV -DNO_VOID_PTR -DUSE_VARARGS -Olimit 1000 -Wf,-XNh5000 -Wf,-XNd5000 -G 4
|
||||
# CFLAGS = -g -p -c -DSYSV -DNO_VOID_PTR -DUSE_VARARGS -Olimit 1000 -Wf,-XNh5000 -Wf,-XNd5000 -G 4
|
||||
|
||||
#
|
||||
# These are the flags for xlc, ansi compiler for IBM R6000
|
||||
#
|
||||
# CC = xlc
|
||||
#
|
||||
# CFLAGS = -O -c -qnoro -D_POSIX_SOURCE -D_ALL_SOURCE -DR6000
|
||||
# CFLAGS = -g -pg -c -qnoro -D_POSIX_SOURCE -D_ALL_SOURCE -DR6000
|
||||
|
||||
OBJS = dev2gif.o egif_lib.o dgif_lib.o gif_hash.o gif_err.o \
|
||||
quantize.o qprintf.o getarg.o
|
||||
|
||||
.c.o:
|
||||
$(CC) $(INCS) $(DEVS) $(CFLAGS) $<
|
||||
|
||||
libgif.a: $(OBJS)
|
||||
rm -f libgif.a
|
||||
ar rcv libgif.a *.o
|
||||
-ranlib libgif.a
|
||||
|
||||
dev2gif.o: gif_lib.h
|
||||
egif_lib.o: gif_lib.h gif_hash.h
|
||||
dgif_lib.o: gif_lib.h gif_hash.h
|
||||
gif_hash.o: gif_lib.h gif_hash.h
|
||||
gif_err.o: gif_lib.h
|
||||
quantize.o: gif_lib.h
|
||||
qprintf.o: gif_lib.h
|
||||
getarg.o: getarg.h
|
55
G/LIB/QPRINTF.C
Normal file
55
G/LIB/QPRINTF.C
Normal file
@ -0,0 +1,55 @@
|
||||
/*****************************************************************************
|
||||
* "Gif-Lib" - Yet another gif library. *
|
||||
* *
|
||||
* Written by: Gershon Elber IBM PC Ver 0.1, Jun. 1989 *
|
||||
******************************************************************************
|
||||
* Module to emulate a printf with a possible quite (disable mode.) *
|
||||
* A global variable GifQuitePrint controls the printing of this routine *
|
||||
******************************************************************************
|
||||
* History: *
|
||||
* 12 May 91 - Version 1.0 by Gershon Elber. *
|
||||
*****************************************************************************/
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#ifdef USE_VARARGS
|
||||
#include <varargs.h>
|
||||
#else
|
||||
#include <stdarg.h>
|
||||
#endif /* USE_VARARGS */
|
||||
|
||||
#include "gif_lib.h"
|
||||
|
||||
#ifdef __MSDOS__
|
||||
int GifQuitePrint = FALSE;
|
||||
#else
|
||||
int GifQuitePrint = TRUE;
|
||||
#endif /* __MSDOS__ */
|
||||
|
||||
/*****************************************************************************
|
||||
* Same as fprintf to stderr but with optional print. *
|
||||
*****************************************************************************/
|
||||
#ifdef USE_VARARGS
|
||||
void GifQprintf(int va_alist)
|
||||
{
|
||||
char *Format, Line[128];
|
||||
va_list ArgPtr;
|
||||
|
||||
va_start(ArgPtr);
|
||||
Format = va_arg(ArgPtr, char *);
|
||||
#else
|
||||
void GifQprintf(char *Format, ...)
|
||||
{
|
||||
char Line[128];
|
||||
va_list ArgPtr;
|
||||
|
||||
va_start(ArgPtr, Format);
|
||||
#endif /* USE_VARARGS */
|
||||
|
||||
if (GifQuitePrint) return;
|
||||
|
||||
vsprintf(Line, Format, ArgPtr);
|
||||
va_end(ArgPtr);
|
||||
|
||||
fputs(Line, stderr);
|
||||
}
|
335
G/LIB/QUANTIZE.C
Normal file
335
G/LIB/QUANTIZE.C
Normal file
@ -0,0 +1,335 @@
|
||||
/*****************************************************************************
|
||||
* "Gif-Lib" - Yet another gif library. *
|
||||
* *
|
||||
* Written by: Gershon Elber IBM PC Ver 0.1, Jun. 1989 *
|
||||
******************************************************************************
|
||||
* Module to quatize high resolution image into lower one. You may want to *
|
||||
* peek into the following article this code is based on: *
|
||||
* "Color Image Quantization for frame buffer Display", by Paul Heckbert *
|
||||
* SIGGRAPH 1982 page 297-307. *
|
||||
******************************************************************************
|
||||
* History: *
|
||||
* 5 Jan 90 - Version 1.0 by Gershon Elber. *
|
||||
*****************************************************************************/
|
||||
|
||||
#ifdef __MSDOS__
|
||||
#include <dos.h>
|
||||
#include <alloc.h>
|
||||
#include <stdlib.h>
|
||||
#include <graphics.h>
|
||||
#endif /* __MSDOS__ */
|
||||
|
||||
#include <stdio.h>
|
||||
#include "gif_lib.h"
|
||||
|
||||
#define PROGRAM_NAME "GIF_LIBRARY"
|
||||
|
||||
#define ABS(x) ((x) > 0 ? (x) : (-(x)))
|
||||
|
||||
/* The colors are stripped to 5 bits per primary color if non MSDOS system */
|
||||
/* or to 4 (not enough memory...) if MSDOS as first step. */
|
||||
#ifdef __MSDOS__
|
||||
#define COLOR_ARRAY_SIZE 4096
|
||||
#define BITS_PER_PRIM_COLOR 4
|
||||
#define MAX_PRIM_COLOR 0x0f
|
||||
#else
|
||||
#define COLOR_ARRAY_SIZE 32768
|
||||
#define BITS_PER_PRIM_COLOR 5
|
||||
#define MAX_PRIM_COLOR 0x1f
|
||||
#endif /* __MSDOS__ */
|
||||
|
||||
extern int _GifError;
|
||||
|
||||
#ifdef SYSV
|
||||
static char *VersionStr =
|
||||
"Gif library module,\t\tGershon Elber\n\
|
||||
(C) Copyright 1989 Gershon Elber, Non commercial use only.\n";
|
||||
#else
|
||||
static char *VersionStr =
|
||||
PROGRAM_NAME
|
||||
" IBMPC "
|
||||
GIF_LIB_VERSION
|
||||
" Gershon Elber, "
|
||||
__DATE__ ", " __TIME__ "\n"
|
||||
"(C) Copyright 1989 Gershon Elber, Non commercial use only.\n";
|
||||
#endif /* SYSV */
|
||||
|
||||
static int SortRGBAxis;
|
||||
|
||||
typedef struct QuantizedColorType {
|
||||
GifByteType RGB[3];
|
||||
GifByteType NewColorIndex;
|
||||
long Count;
|
||||
struct QuantizedColorType *Pnext;
|
||||
} QuantizedColorType;
|
||||
|
||||
typedef struct NewColorMapType {
|
||||
GifByteType RGBMin[3], RGBWidth[3];
|
||||
unsigned int NumEntries;/* # of QuantizedColorType in linked list below. */
|
||||
long Count; /* Total number of pixels in all the entries. */
|
||||
QuantizedColorType *QuantizedColors;
|
||||
} NewColorMapType;
|
||||
|
||||
static int SubdivColorMap(NewColorMapType *NewColorSubdiv,
|
||||
unsigned int ColorMapSize,
|
||||
unsigned int *NewColorMapSize);
|
||||
#ifdef __MSDOS__
|
||||
static int SortCmpRtn(const VoidPtr Entry1, const VoidPtr Entry2);
|
||||
#else
|
||||
static int SortCmpRtn(VoidPtr Entry1, VoidPtr Entry2);
|
||||
#endif /* __MSDOS__ */
|
||||
|
||||
/******************************************************************************
|
||||
* Quantize high resolution image into lower one. Input image consists of a *
|
||||
* 2D array for each of the RGB colors with size Width by Height. There is no *
|
||||
* Color map for the input. Output is a quantized image with 2D array of *
|
||||
* indexes into the output color map. *
|
||||
* Note input image can be 24 bits at the most (8 for red/green/blue) and *
|
||||
* the output has 256 colors at the most (256 entries in the color map.). *
|
||||
* ColorMapSize specifies size of color map up to 256 and will be updated to *
|
||||
* real size before returning. *
|
||||
* Also non of the parameter are allocated by this routine. *
|
||||
* This function returns GIF_OK if succesfull, GIF_ERROR otherwise. *
|
||||
******************************************************************************/
|
||||
int QuantizeBuffer(unsigned int Width, unsigned int Height, int *ColorMapSize,
|
||||
GifByteType *RedInput, GifByteType *GreenInput, GifByteType *BlueInput,
|
||||
GifByteType *OutputBuffer, GifColorType *OutputColorMap)
|
||||
{
|
||||
unsigned int i, j, Index, NewColorMapSize, NumOfEntries, MaxRGBError[3];
|
||||
long Red, Green, Blue;
|
||||
NewColorMapType NewColorSubdiv[256];
|
||||
QuantizedColorType *ColorArrayEntries, *QuantizedColor;
|
||||
|
||||
if ((ColorArrayEntries = (QuantizedColorType *)
|
||||
malloc(sizeof(QuantizedColorType) * COLOR_ARRAY_SIZE)) == NULL) {
|
||||
_GifError = E_GIF_ERR_NOT_ENOUGH_MEM;
|
||||
return GIF_ERROR;
|
||||
}
|
||||
|
||||
for (i = 0; i < COLOR_ARRAY_SIZE; i++) {
|
||||
ColorArrayEntries[i].RGB[0]= i >> (2 * BITS_PER_PRIM_COLOR);
|
||||
ColorArrayEntries[i].RGB[1] = (i >> BITS_PER_PRIM_COLOR) &
|
||||
MAX_PRIM_COLOR;
|
||||
ColorArrayEntries[i].RGB[2] = i & MAX_PRIM_COLOR;
|
||||
ColorArrayEntries[i].Count = 0;
|
||||
}
|
||||
|
||||
/* Sample the colors and their distribution: */
|
||||
for (i = 0; i < Width * Height; i++) {
|
||||
Index = ((RedInput[i] >> (8 - BITS_PER_PRIM_COLOR))
|
||||
<< (2 * BITS_PER_PRIM_COLOR)) +
|
||||
((GreenInput[i] >> (8 - BITS_PER_PRIM_COLOR))
|
||||
<< BITS_PER_PRIM_COLOR) +
|
||||
(BlueInput[i] >> (8 - BITS_PER_PRIM_COLOR));
|
||||
ColorArrayEntries[Index].Count++;
|
||||
}
|
||||
|
||||
/* Put all the colors in the first entry of the color map, and call the */
|
||||
/* recursive subdivision process. */
|
||||
for (i = 0; i < 256; i++) {
|
||||
NewColorSubdiv[i].QuantizedColors = NULL;
|
||||
NewColorSubdiv[i].Count = NewColorSubdiv[i].NumEntries = 0;
|
||||
for (j = 0; j < 3; j++) {
|
||||
NewColorSubdiv[i].RGBMin[j] = 0;
|
||||
NewColorSubdiv[i].RGBWidth[j] = 255;
|
||||
}
|
||||
}
|
||||
|
||||
/* Find the non empty entries in the color table and chain them: */
|
||||
for (i = 0; i < COLOR_ARRAY_SIZE; i++)
|
||||
if (ColorArrayEntries[i].Count > 0) break;
|
||||
QuantizedColor = NewColorSubdiv[0].QuantizedColors = &ColorArrayEntries[i];
|
||||
NumOfEntries = 1;
|
||||
while (++i < COLOR_ARRAY_SIZE)
|
||||
if (ColorArrayEntries[i].Count > 0) {
|
||||
QuantizedColor -> Pnext = &ColorArrayEntries[i];
|
||||
QuantizedColor = &ColorArrayEntries[i];
|
||||
NumOfEntries++;
|
||||
}
|
||||
QuantizedColor -> Pnext = NULL;
|
||||
|
||||
NewColorSubdiv[0].NumEntries = NumOfEntries;/* Different sampled colors. */
|
||||
NewColorSubdiv[0].Count = ((long) Width) * Height; /* Pixels. */
|
||||
NewColorMapSize = 1;
|
||||
if (SubdivColorMap(NewColorSubdiv, *ColorMapSize, &NewColorMapSize) !=
|
||||
GIF_OK) {
|
||||
free((char *) ColorArrayEntries);
|
||||
return GIF_ERROR;
|
||||
}
|
||||
if (NewColorMapSize < *ColorMapSize) {
|
||||
/* And clear rest of color map: */
|
||||
for (i = NewColorMapSize; i < *ColorMapSize; i++)
|
||||
OutputColorMap[i].Red =
|
||||
OutputColorMap[i].Green =
|
||||
OutputColorMap[i].Blue = 0;
|
||||
}
|
||||
|
||||
/* Average the colors in each entry to be the color to be used in the */
|
||||
/* output color map, and plug it into the output color map itself. */
|
||||
for (i = 0; i < NewColorMapSize; i++) {
|
||||
if ((j = NewColorSubdiv[i].NumEntries) > 0) {
|
||||
QuantizedColor = NewColorSubdiv[i].QuantizedColors;
|
||||
Red = Green = Blue = 0;
|
||||
while (QuantizedColor) {
|
||||
QuantizedColor -> NewColorIndex = i;
|
||||
Red += QuantizedColor -> RGB[0];
|
||||
Green += QuantizedColor -> RGB[1];
|
||||
Blue += QuantizedColor -> RGB[2];
|
||||
QuantizedColor = QuantizedColor -> Pnext;
|
||||
}
|
||||
OutputColorMap[i].Red = (Red << (8 - BITS_PER_PRIM_COLOR)) / j;
|
||||
OutputColorMap[i].Green = (Green << (8 - BITS_PER_PRIM_COLOR)) / j;
|
||||
OutputColorMap[i].Blue= (Blue << (8 - BITS_PER_PRIM_COLOR)) / j;
|
||||
}
|
||||
else
|
||||
GIF_MESSAGE("Null entry in quantized color map - thats weird.");
|
||||
}
|
||||
|
||||
/* Finally scan the input buffer again and put the mapped index in the */
|
||||
/* output buffer. */
|
||||
MaxRGBError[0] = MaxRGBError[1] = MaxRGBError[2] = 0;
|
||||
for (i = 0; i < Width * Height; i++) {
|
||||
Index = ((RedInput[i] >> (8 - BITS_PER_PRIM_COLOR))
|
||||
<< (2 * BITS_PER_PRIM_COLOR)) +
|
||||
((GreenInput[i] >> (8 - BITS_PER_PRIM_COLOR))
|
||||
<< BITS_PER_PRIM_COLOR) +
|
||||
(BlueInput[i] >> (8 - BITS_PER_PRIM_COLOR));
|
||||
Index = ColorArrayEntries[Index].NewColorIndex;
|
||||
OutputBuffer[i] = Index;
|
||||
if (MaxRGBError[0] < ABS(OutputColorMap[Index].Red - RedInput[i]))
|
||||
MaxRGBError[0] = ABS(OutputColorMap[Index].Red - RedInput[i]);
|
||||
if (MaxRGBError[1] < ABS(OutputColorMap[Index].Green - GreenInput[i]))
|
||||
MaxRGBError[1] = ABS(OutputColorMap[Index].Green - GreenInput[i]);
|
||||
if (MaxRGBError[2] < ABS(OutputColorMap[Index].Blue - BlueInput[i]))
|
||||
MaxRGBError[2] = ABS(OutputColorMap[Index].Blue - BlueInput[i]);
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr,
|
||||
"Quantization L(0) errors: Red = %d, Green = %d, Blue = %d.\n",
|
||||
MaxRGBError[0], MaxRGBError[1], MaxRGBError[2]);
|
||||
#endif /* DEBUG */
|
||||
|
||||
free((char *) ColorArrayEntries);
|
||||
|
||||
*ColorMapSize = NewColorMapSize;
|
||||
|
||||
return GIF_OK;
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* Routine to subdivide the RGB space recursively using median cut in each *
|
||||
* axes alternatingly until ColorMapSize different cubes exists. *
|
||||
* The biggest cube in one dimension is subdivide unless it has only one entry.*
|
||||
* Returns GIF_ERROR if failed, otherwise GIF_OK. *
|
||||
******************************************************************************/
|
||||
static int SubdivColorMap(NewColorMapType *NewColorSubdiv,
|
||||
unsigned int ColorMapSize,
|
||||
unsigned int *NewColorMapSize)
|
||||
{
|
||||
int MaxSize;
|
||||
unsigned int i, j, Index = 0, NumEntries, MinColor, MaxColor;
|
||||
long Sum, Count;
|
||||
QuantizedColorType *QuantizedColor, **SortArray;
|
||||
|
||||
while (ColorMapSize > *NewColorMapSize) {
|
||||
/* Find candidate for subdivision: */
|
||||
MaxSize = -1;
|
||||
for (i = 0; i < *NewColorMapSize; i++) {
|
||||
for (j = 0; j < 3; j++) {
|
||||
if (((int) NewColorSubdiv[i].RGBWidth[j]) > MaxSize &&
|
||||
NewColorSubdiv[i].NumEntries > 1) {
|
||||
MaxSize = NewColorSubdiv[i].RGBWidth[j];
|
||||
Index = i;
|
||||
SortRGBAxis = j;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (MaxSize == -1)
|
||||
return GIF_OK;
|
||||
|
||||
/* Split the entry Index into two along the axis SortRGBAxis: */
|
||||
|
||||
/* Sort all elements in that entry along the given axis and split at */
|
||||
/* the median. */
|
||||
if ((SortArray = (QuantizedColorType **)
|
||||
malloc(sizeof(QuantizedColorType *) *
|
||||
NewColorSubdiv[Index].NumEntries)) == NULL)
|
||||
return GIF_ERROR;
|
||||
for (j = 0, QuantizedColor = NewColorSubdiv[Index].QuantizedColors;
|
||||
j < NewColorSubdiv[Index].NumEntries && QuantizedColor != NULL;
|
||||
j++, QuantizedColor = QuantizedColor -> Pnext)
|
||||
SortArray[j] = QuantizedColor;
|
||||
qsort(SortArray, NewColorSubdiv[Index].NumEntries,
|
||||
sizeof(QuantizedColorType *), SortCmpRtn);
|
||||
|
||||
/* Relink the sorted list into one: */
|
||||
for (j = 0; j < NewColorSubdiv[Index].NumEntries - 1; j++)
|
||||
SortArray[j] -> Pnext = SortArray[j + 1];
|
||||
SortArray[NewColorSubdiv[Index].NumEntries - 1] -> Pnext = NULL;
|
||||
NewColorSubdiv[Index].QuantizedColors = QuantizedColor = SortArray[0];
|
||||
free((char *) SortArray);
|
||||
|
||||
/* Now simply add the Counts until we have half of the Count: */
|
||||
Sum = NewColorSubdiv[Index].Count / 2 - QuantizedColor -> Count;
|
||||
NumEntries = 1;
|
||||
Count = QuantizedColor -> Count;
|
||||
while ((Sum -= QuantizedColor -> Pnext -> Count) >= 0 &&
|
||||
QuantizedColor -> Pnext != NULL &&
|
||||
QuantizedColor -> Pnext -> Pnext != NULL) {
|
||||
QuantizedColor = QuantizedColor -> Pnext;
|
||||
NumEntries++;
|
||||
Count += QuantizedColor -> Count;
|
||||
}
|
||||
/* Save the values of the last color of the first half, and first */
|
||||
/* of the second half so we can update the Bounding Boxes later. */
|
||||
/* Also as the colors are quantized and the BBoxes are full 0..255, */
|
||||
/* they need to be rescaled. */
|
||||
MaxColor = QuantizedColor -> RGB[SortRGBAxis];/* Max. of first half. */
|
||||
MinColor = QuantizedColor -> Pnext -> RGB[SortRGBAxis];/* of second. */
|
||||
MaxColor <<= (8 - BITS_PER_PRIM_COLOR);
|
||||
MinColor <<= (8 - BITS_PER_PRIM_COLOR);
|
||||
|
||||
/* Partition right here: */
|
||||
NewColorSubdiv[*NewColorMapSize].QuantizedColors =
|
||||
QuantizedColor -> Pnext;
|
||||
QuantizedColor -> Pnext = NULL;
|
||||
NewColorSubdiv[*NewColorMapSize].Count = Count;
|
||||
NewColorSubdiv[Index].Count -= Count;
|
||||
NewColorSubdiv[*NewColorMapSize].NumEntries =
|
||||
NewColorSubdiv[Index].NumEntries - NumEntries;
|
||||
NewColorSubdiv[Index].NumEntries = NumEntries;
|
||||
for (j = 0; j < 3; j++) {
|
||||
NewColorSubdiv[*NewColorMapSize].RGBMin[j] =
|
||||
NewColorSubdiv[Index].RGBMin[j];
|
||||
NewColorSubdiv[*NewColorMapSize].RGBWidth[j] =
|
||||
NewColorSubdiv[Index].RGBWidth[j];
|
||||
}
|
||||
NewColorSubdiv[*NewColorMapSize].RGBWidth[SortRGBAxis] =
|
||||
NewColorSubdiv[*NewColorMapSize].RGBMin[SortRGBAxis] +
|
||||
NewColorSubdiv[*NewColorMapSize].RGBWidth[SortRGBAxis] -
|
||||
MinColor;
|
||||
NewColorSubdiv[*NewColorMapSize].RGBMin[SortRGBAxis] = MinColor;
|
||||
|
||||
NewColorSubdiv[Index].RGBWidth[SortRGBAxis] =
|
||||
MaxColor - NewColorSubdiv[Index].RGBMin[SortRGBAxis];
|
||||
|
||||
(*NewColorMapSize)++;
|
||||
}
|
||||
|
||||
return GIF_OK;
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* Routine called by qsort to compare to entries. *
|
||||
******************************************************************************/
|
||||
#ifdef __MSDOS__
|
||||
static int SortCmpRtn(const VoidPtr Entry1, const VoidPtr Entry2)
|
||||
#else
|
||||
static int SortCmpRtn(VoidPtr Entry1, VoidPtr Entry2)
|
||||
#endif /* __MSDOS__ */
|
||||
{
|
||||
return (* ((QuantizedColorType **) Entry1)) -> RGB[SortRGBAxis] -
|
||||
(* ((QuantizedColorType **) Entry2)) -> RGB[SortRGBAxis];
|
||||
}
|
Reference in New Issue
Block a user