📄 giffile.cpp
字号:
if (sp > stack)
return *--sp;
}
return code;
}
static BOOL ReadImage( FILE *fd,
BYTE * bigMemBuf,
int width, int height,
UCHAR cmap[3][MAXCOLORMAPSIZE],
int interlace)
{
UCHAR c;
int color;
int xpos=0, ypos=0, pass=0;
long curidx;
if (!ReadOK(fd,& c,1))
{
return FALSE;
}
if (LZWReadByte(fd,TRUE,c)<0)
{
return FALSE;
}
while ((color = LZWReadByte(fd, FALSE, c)) >= 0 )
{
curidx=(long)xpos + (long)ypos * (long)width;
curidx*=3;
*(bigMemBuf+curidx) = cmap[0][color];
*(bigMemBuf+curidx+1) = cmap[1][color];
*(bigMemBuf+curidx+2) = cmap[2][color];
++xpos;
if (xpos==width)
{
xpos=0;
if (interlace)
{
switch (pass)
{
case 0:
case 1:
ypos += 8; break;
case 2:
ypos += 4; break;
case 3:
ypos += 2; break;
}
if (ypos>=height)
{
++pass;
switch (pass)
{
case 1: ypos = 4; break;
case 2: ypos = 2; break;
case 3: ypos = 1; break;
default : goto fini;
}
}
}
else
{
++ypos;
}
}
if (ypos >=height)
break;
}
fini :
if (LZWReadByte(fd,FALSE,c)>=0)
{
}
return TRUE;
}
// gets image dimensions
// returns -1,-1 on bad read
void GIFFile::GIFGetDimensions(CString path, UINT *width, UINT *height)
{
UCHAR buf[16];
UCHAR c;
char version[4];
FILE *fd;
int w=0;
int h=0;
if (_access(path,0)!=0)
{
*width=(UINT)-1;*height=(UINT)-1;
return;
}
fd=fopen(path,"rb");
if (fd==NULL)
{
*width=(UINT)-1;*height=(UINT)-1;
return;
}
// read GIF file header
if (!ReadOK(fd,buf,6))
goto bail;
// need the string "GIF" in the header
if (strncmp((char *)buf,"GIF",3)!=0)
goto bail;
strncpy(version,(char *)(buf+3),3);
version[3]='\0';
// only handle v 87a and 89a
if ((strcmp(version,"87a")!=0)&&(strcmp(version,"89a")!=0))
goto bail;
// screen description
if (!ReadOK(fd,buf,7))
goto bail;
GifScreen.Width = LM_to_uint((UCHAR)buf[0],(UCHAR)buf[1]);
GifScreen.Height = LM_to_uint((UCHAR)buf[2],(UCHAR)buf[3]);
GifScreen.BitPixel = 2<<((UCHAR)buf[4]&0x07);
GifScreen.ColorResolution=((((UCHAR)buf[4]&0x70)>>3)+1);
GifScreen.BackGround= (UCHAR)buf[5]; // background color...
GifScreen.AspectRatio= (UCHAR)buf[6];
*width = GifScreen.Width;
*height = GifScreen.Height;
// read colormaps
if (BitSet((UCHAR)buf[4],LOCALCOLORMAP))
if (!ReadColorMap(fd,GifScreen.BitPixel,GifScreen.ColorMap))
goto bail;
if (!ReadOK(fd,&c,1))
goto bail;
if (c!=',')
goto bail;
// read image header
if (!ReadOK(fd,buf,9))
goto bail;
//*width=LM_to_uint((UCHAR)buf[4],(UCHAR)buf[5]);
//*height=LM_to_uint((UCHAR)buf[6],(UCHAR)buf[7]);
if ((*width<0) || (*height<0))
goto bail;
// good
fclose(fd);
return;
bail:
// bad
fclose(fd);
//*width=(UINT)-1;*height=(UINT)-1;
return;
}
////////////////////////////////////////////////////////////////////////
//
// This is the writing portion of the GIFFile class.
// It is based on code from Programming for Graphics Files by John Levine
//
// This is free to use and modify provided proper credit is given
//
// This writes 256 color GIFs version GIF87a.
//
// see GIFFile.h for example
////////////////////////////////////////////////////////////////////////
////////////
//
// GIF writing section
//
////////////
// a code_int must be able to hold 2**BITS values of type int, and also -1
static int Width, Height;
static int curx, cury;
static long CountDown;
static unsigned long cur_accum = 0;
static int cur_bits = 0;
static unsigned char *buffer;
/*
* Bump the 'curx' and 'cury' to point to the next pixel
*/
void GIFFile::BumpPixel()
{
/*
* Bump the current X position
*/
++curx;
if( curx == Width )
{
curx = 0;
++cury;
}
}
/*******************************************************************************
* Return the next pixel from the image
*******************************************************************************/
int GIFFile::GIFNextPixel( )
{
unsigned long index;
int r;
if( CountDown == 0 )
return EOF;
--CountDown;
index= (unsigned long)curx + (unsigned long)cury * (unsigned long)Width;
r = *(buffer+index);
BumpPixel();
return r;
}
/*******************************************************************************
* here's the entry point.
* file ptr, screen width, height, background color, bits per pixel and
* arrays of color values (0-255)
*******************************************************************************/
BOOL GIFFile::GIFWriteFileFrom256Color(unsigned char * buf,
CString name,
int GWidth,
int GHeight,
int BackGround,
int Red[], int Green[], int Blue[])
{
FILE *fp;
int B;
int RWidth, RHeight;
int LeftOfs, TopOfs;
int Resolution;
int ColorMapSize;
int InitCodeSize;
int i;
int BitsPerPixel = 8;
fp=fopen(name,"wb");
if (fp==NULL)
{
m_GIFErrorText="Can't open GIF for writing";
return FALSE;
}
ColorMapSize = 1 << BitsPerPixel;
buffer=buf;
RWidth = Width = GWidth;
RHeight = Height = GHeight;
LeftOfs = TopOfs = 0;
cur_accum = 0;
cur_bits = 0;
Resolution = BitsPerPixel;
CountDown = (long)Width * (long) Height;
if (BitsPerPixel <=1)
InitCodeSize=2;
else
InitCodeSize = BitsPerPixel;
curx = cury =0;
fwrite("GIF87a",1,6,fp);
Putword(RWidth,fp);
Putword(RHeight,fp);
B=0x80;
B |=(Resolution -1) << 5;
B |=(BitsPerPixel - 1);
fputc(B,fp);
fputc(BackGround,fp);
fputc(0,fp);
for(i=0; i<ColorMapSize; ++i)
{
fputc(Red[i],fp);
fputc(Green[i],fp);
fputc(Blue[i],fp);
}
fputc(',',fp);
Putword(LeftOfs,fp);
Putword(TopOfs,fp);
Putword(Width,fp);
Putword(Height,fp);
fputc(0x00,fp);
/*
* Write out the initial code size
*/
fputc( InitCodeSize, fp );
/*
* Go and actually compress the data
*/
compress( InitCodeSize+1, fp);
/*
* Write out a Zero-length packet (to end the series)
*/
fputc( 0, fp );
/*
* Write the GIF file terminator
*/
fputc( ';', fp );
/*
* And close the file
*/
fclose( fp );
return TRUE;
}
/*******************************************************************************
* Write out a word to the GIF file
*******************************************************************************/
void GIFFile::Putword(int w, FILE *fp )
{
fputc( w & 0xff, fp );
fputc( (w / 256) & 0xff, fp );
}
/***************************************************************************
*
* GIFCOMPR.C - GIF Image compression routines
*
* Lempel-Ziv compression based on 'compress'. GIF modifications by
* David Rowley (mgardi@watdcsu.waterloo.edu)
*
***************************************************************************/
/*
* General DEFINEs
*/
#define BITS 12
#define HSIZE 5003 /* 80% occupancy */
typedef unsigned char char_type;
/*
*
* GIF Image compression - modified 'compress'
*
* Based on: compress.c - File compression ala IEEE Computer, June 1984.
*
* By Authors: Spencer W. Thomas (decvax!harpo!utah-cs!utah-gr!thomas)
* Jim McKie (decvax!mcvax!jim)
* Steve Davies (decvax!vax135!petsd!peora!srd)
* Ken Turkowski (decvax!decwrl!turtlevax!ken)
* James A. Woods (decvax!ihnp4!ames!jaw)
* Joe Orost (decvax!vax135!petsd!joe)
*
*/
static int n_bits; /* number of bits/code */
static int maxbits = BITS; /* user settable max # bits/code */
static code_int maxcode; /* maximum code, given n_bits */
static code_int maxmaxcode = (code_int)1 << BITS; /* should NEVER generate this
code */
#define MAXCODE(n_bits) (((code_int) 1 << (n_bits)) - 1)
static count_int htab [HSIZE];
static unsigned short codetab [HSIZE];
#define HashTabOf(i) htab[i]
#define CodeTabOf(i) codetab[i]
static code_int free_ent = 0; /* first unused entry */
/*
* block compression parameters -- after all codes are used up,
* and compression rate changes, start over.
*/
static int clear_flg = 0;
/*
* compress pixels to GIF packets
*
* Algorithm: use open addressing double hashing (no chaining) on the
* prefix code / next character combination. We do a variant of Knuth's
* algorithm D (vol. 3, sec. 6.4) along with G. Knott's relatively-prime
* secondary probe. Here, the modular division first probe is gives way
* to a faster exclusive-or manipulation. Also do block compression with
* an adaptive reset, whereby the code table is cleared when the compression
* ratio decreases, but after the table fills. The variable-length output
* codes are re-sized at this point, and a special CLEAR code is generated
* for the decompressor. Late addition: construct the table according to
* file size for noticeable speed improvement on small files. Please direct
* questions about this implementation to ames!jaw.
*/
static int g_init_bits;
static FILE* g_outfile;
static int ClearCode;
static int EOFCode;
/*******************************************************************************
*
*******************************************************************************/
void GIFFile::compress( int init_bits, FILE* outfile)
{
register long fcode;
register code_int i /* = 0 */;
register int c;
register code_int ent;
register code_int disp;
register int hshift;
/*
* Set up the globals: g_init_bits - initial number of bits
* g_outfile - pointer to output file
*/
g_init_bits = init_bits;
g_outfile = outfile;
/*
* Set up the necessary values
*/
clear_flg = 0;
maxcode = MAXCODE(n_bits = g_init_bits);
ClearCode = (1 << (init_bits - 1));
EOFCode = ClearCode + 1;
free_ent = ClearCode + 2;
char_init();
ent = GIFNextPixel( );
hshift = 0;
for ( fcode = (long) HSIZE; fcode < 65536L; fcode *= 2L )
++hshift;
hshift = 8 - hshift; /* set hash code range bound */
cl_hash( (count_int) HSIZE); /* clear hash table */
output( (code_int)ClearCode );
while ( (c = GIFNextPixel( )) != EOF )
{ /* } */
fcode = (long) (((long) c << maxbits) + ent);
i = (((code_int)c << hshift) ^ ent); /* xor hashing */
if ( HashTabOf (i) == fcode )
{
ent = CodeTabOf (i);
continue;
} else if ( (long)HashTabOf (i) < 0 ) /* empty slot */
goto nomatch;
disp = HSIZE - i; /* secondary hash (after G. Knott) */
if ( i == 0 )
disp = 1;
probe:
if ( (i -= disp) < 0 )
i += HSIZE;
if ( HashTabOf (i) == fcode )
{
ent = CodeTabOf (i);
continue;
}
if ( (long)HashTabOf (i) > 0 )
goto probe;
nomatch:
output ( (code_int) ent );
ent = c;
if ( free_ent < maxmaxcode )
{ /* } */
CodeTabOf (i) = free_ent++; /* code -> hashtable */
HashTabOf (i) = fcode;
} else
cl_block();
}
/*
* Put out the final code.
*/
output( (code_int)ent );
output( (code_int) EOFCode );
}
/*****************************************************************
* TAG( output )
*
* Output the given code.
* Inputs:
* code: A n_bits-bit integer. If == -1, then EOF. This assumes
* that n_bits =< (long)wordsize - 1.
* Outputs:
* Outputs code to the file.
* Assumptions:
* Chars are 8 bits long.
* Algorithm:
* Maintain a BITS character long buffer (so that 8 codes will
* fit in it exactly). Use the VAX insv instruction to insert each
* code in turn. When the buffer fills up empty it and start over.
*/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -