📄 ximagif.cpp
字号:
{
fp->PutC(pPal[i].rgbRed);
fp->PutC(pPal[i].rgbGreen);
fp->PutC(pPal[i].rgbBlue);
}
}
int InitCodeSize = head.biBitCount <=1 ? 2 : head.biBitCount;
// Write out the initial code size
fp->PutC((BYTE)InitCodeSize);
// Go and actually compress the data
switch (info.dwCodecOption)
{
case 1: //uncompressed
compressNONE(InitCodeSize+1, fp);
break;
case 2: //LZW
compressLZW(InitCodeSize+1, fp);
break;
default: //RLE
compressRLE(InitCodeSize+1, fp);
}
// Write out a Zero-length packet (to end the series)
fp->PutC(0);
}
////////////////////////////////////////////////////////////////////////////////
void CxImageGIF::EncodeComment(CxFile *fp)
{
long n=strlen(m_comment);
if (n>255) n=255;
if (n) {
fp->PutC('!'); //extension code:
fp->PutC(254); //comment extension
fp->PutC((BYTE)n); //size of comment
fp->Write(m_comment,n,1);
fp->PutC(0); //block terminator
}
}
////////////////////////////////////////////////////////////////////////////////
bool CxImageGIF::EncodeRGB(CxFile *fp)
{
EncodeHeader(fp);
// EncodeLoopExtension(fp);
EncodeComment(fp);
unsigned long w,h;
w=h=0;
const long cellw = 17;
const long cellh = 15;
CxImageGIF tmp;
for (long y=0;y<head.biHeight;y+=cellh){
for (long x=0;x<head.biWidth;x+=cellw){
if ((head.biWidth -x)<cellw) w=head.biWidth -x; else w=cellw;
if ((head.biHeight-y)<cellh) h=head.biHeight-y; else h=cellh;
if (w!=tmp.GetWidth() || h!=tmp.GetHeight()) tmp.Create(w,h,8);
if (IsTransparent()){
tmp.SetTransIndex(0);
tmp.SetPaletteColor(0,GetTransColor());
}
BYTE i;
for (unsigned long j=0;j<h;j++){
for (unsigned long k=0;k<w;k++){
i=(BYTE)(1+k+cellw*j);
tmp.SetPaletteColor(i,GetPixelColor(x+k,head.biHeight-y-h+j));
tmp.SetPixelIndex(k,j,tmp.GetNearestIndex(tmp.GetPaletteColor(i)));
}
}
tmp.SetOffset(x,y);
tmp.EncodeExtension(fp);
tmp.EncodeBody(fp,true);
}
}
fp->PutC(';'); // Write the GIF file terminator
return true; // done!
}
////////////////////////////////////////////////////////////////////////////////
#endif // CXIMAGE_SUPPORT_ENCODE
////////////////////////////////////////////////////////////////////////////////
// Return the next pixel from the image
// <DP> fix for 1 & 4 bpp images
int CxImageGIF::GifNextPixel( )
{
if( CountDown == 0 ) return EOF;
--CountDown;
int r = GetPixelIndex(curx,cury);
// Bump the current X position
++curx;
if( curx == head.biWidth ){
curx = 0;
cury--; //bottom to top
}
return r;
}
////////////////////////////////////////////////////////////////////////////////
void CxImageGIF::Putword(int w, CxFile *fp )
{
fp->PutC((BYTE)(w & 0xff));
fp->PutC((BYTE)((w / 256) & 0xff));
}
////////////////////////////////////////////////////////////////////////////////
void CxImageGIF::compressNONE( int init_bits, CxFile* outfile)
{
register long c;
register long ent;
// 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
cur_accum = cur_bits = clear_flg = 0;
maxcode = (short)MAXCODE(n_bits = g_init_bits);
code_int maxmaxcode = (code_int)1 << MAXBITSCODES;
ClearCode = (1 << (init_bits - 1));
EOFCode = ClearCode + 1;
free_ent = (short)(ClearCode + 2);
a_count=0;
ent = GifNextPixel( );
output( (code_int)ClearCode );
while ( ent != EOF ) {
c = GifNextPixel();
output ( (code_int) ent );
ent = c;
if ( free_ent < maxmaxcode ) {
free_ent++;
} else {
free_ent=(short)(ClearCode+2);
clear_flg=1;
output((code_int)ClearCode);
}
}
// Put out the final code.
output( (code_int) EOFCode );
}
////////////////////////////////////////////////////////////////////////////////
/***************************************************************************
*
* GIFCOMPR.C - LZW GIF Image compression routines
*
***************************************************************************/
void CxImageGIF::compressLZW( int init_bits, CxFile* outfile)
{
register long fcode;
register long c;
register long ent;
register long hshift;
register long disp;
register long i;
// 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
cur_accum = cur_bits = clear_flg = 0;
maxcode = (short)MAXCODE(n_bits = g_init_bits);
code_int maxmaxcode = (code_int)1 << MAXBITSCODES;
ClearCode = (1 << (init_bits - 1));
EOFCode = ClearCode + 1;
free_ent = (short)(ClearCode + 2);
a_count=0;
ent = GifNextPixel( );
hshift = 0;
for ( fcode = (long) HSIZE; fcode < 65536L; fcode *= 2L ) ++hshift;
hshift = 8 - hshift; /* set hash code range bound */
cl_hash((long)HSIZE); /* clear hash table */
output( (code_int)ClearCode );
while ( (c = GifNextPixel( )) != EOF ) {
fcode = (long) (((long) c << MAXBITSCODES) + 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_hash((long)HSIZE);
free_ent=(short)(ClearCode+2);
clear_flg=1;
output((code_int)ClearCode);
}
}
// Put out the final code.
output( (code_int)ent );
output( (code_int) EOFCode );
}
////////////////////////////////////////////////////////////////////////////////
static const unsigned long code_mask[] = { 0x0000, 0x0001, 0x0003, 0x0007, 0x000F,
0x001F, 0x003F, 0x007F, 0x00FF,
0x01FF, 0x03FF, 0x07FF, 0x0FFF,
0x1FFF, 0x3FFF, 0x7FFF, 0xFFFF };
////////////////////////////////////////////////////////////////////////////////
void CxImageGIF::output( code_int code)
{
cur_accum &= code_mask[ cur_bits ];
if( cur_bits > 0 )
cur_accum |= ((long)code << cur_bits);
else
cur_accum = code;
cur_bits += n_bits;
while( cur_bits >= 8 ) {
char_out( (unsigned int)(cur_accum & 0xff) );
cur_accum >>= 8;
cur_bits -= 8;
}
/*
* If the next entry is going to be too big for the code size,
* then increase it, if possible.
*/
if ( free_ent > maxcode || clear_flg ) {
if( clear_flg ) {
maxcode = (short)MAXCODE(n_bits = g_init_bits);
clear_flg = 0;
} else {
++n_bits;
if ( n_bits == MAXBITSCODES )
maxcode = (code_int)1 << MAXBITSCODES; /* should NEVER generate this code */
else
maxcode = (short)MAXCODE(n_bits);
}
}
if( code == EOFCode ) {
// At EOF, write the rest of the buffer.
while( cur_bits > 0 ) {
char_out( (unsigned int)(cur_accum & 0xff) );
cur_accum >>= 8;
cur_bits -= 8;
}
flush_char();
g_outfile->Flush();
if(g_outfile->Error()) strcpy(info.szLastError,"Write Error in GIF file");
}
}
////////////////////////////////////////////////////////////////////////////////
void CxImageGIF::cl_hash(register long hsize)
{
register long *htab_p = htab+hsize;
register long i;
register long m1 = -1L;
i = hsize - 16;
do {
*(htab_p-16)=m1;
*(htab_p-15)=m1;
*(htab_p-14)=m1;
*(htab_p-13)=m1;
*(htab_p-12)=m1;
*(htab_p-11)=m1;
*(htab_p-10)=m1;
*(htab_p-9)=m1;
*(htab_p-8)=m1;
*(htab_p-7)=m1;
*(htab_p-6)=m1;
*(htab_p-5)=m1;
*(htab_p-4)=m1;
*(htab_p-3)=m1;
*(htab_p-2)=m1;
*(htab_p-1)=m1;
htab_p-=16;
} while ((i-=16) >=0);
for (i+=16;i>0;--i)
*--htab_p=m1;
}
/*******************************************************************************
* GIF specific
*******************************************************************************/
void CxImageGIF::char_out(int c)
{
accum[a_count++]=(char)c;
if (a_count >=254)
flush_char();
}
void CxImageGIF::flush_char()
{
if (a_count > 0) {
g_outfile->PutC((BYTE)a_count);
g_outfile->Write(accum,1,a_count);
a_count=0;
}
}
/*******************************************************************************
* GIF decoder
*******************************************************************************/
/* DECODE.C - An LZW decoder for GIF
* Copyright (C) 1987, by Steven A. Bennett
* Copyright (C) 1994, C++ version by Alejandro Aguilar Sierra
*
* Permission is given by the author to freely redistribute and include
* this code in any program as long as this credit is given where due.
*
* In accordance with the above, I want to credit Steve Wilhite who wrote
* the code which this is heavily inspired by...
*
* GIF and 'Graphics Interchange Format' are trademarks (tm) of
* Compuserve, Incorporated, an H&R Block Company.
*
* Release Notes: This file contains a decoder routine for GIF images
* which is similar, structurally, to the original routine by Steve Wilhite.
* It is, however, somewhat noticably faster in most cases.
*
*/
////////////////////////////////////////////////////////////////////////////////
short CxImageGIF::init_exp(short size)
{
curr_size = (short)(size + 1);
top_slot = (short)(1 << curr_size);
clear = (short)(1 << size);
ending = (short)(clear + 1);
slot = newcodes = (short)(ending + 1);
navail_bytes = nbits_left = 0;
memset(stack,0,MAX_CODES + 1);
memset(prefix,0,MAX_CODES + 1);
memset(suffix,0,MAX_CODES + 1);
return(0);
}
////////////////////////////////////////////////////////////////////////////////
/* get_next_code()
* - gets the next code from the GIF file. Returns the code, or else
* a negative number in case of file errors...
*/
short CxImageGIF::get_next_code(CxFile* file)
{
short i, x;
DWORD ret;
if (nbits_left == 0) {
if (navail_bytes <= 0) {
/* Out of bytes in current block, so read next block */
pbytes = byte_buff;
if ((navail_bytes = (short)get_byte(file)) < 0)
return(navail_bytes);
else if (navail_bytes) {
for (i = 0; i < navail_bytes; ++i) {
if ((x = (short)get_byte(file)) < 0) return(x);
byte_buff[i] = (BYTE)x;
}
}
}
b1 = *pbytes++;
nbits_left = 8;
--navail_bytes;
}
if (navail_bytes<0) return ending; // prevent deadlocks (thanks to Mike Melnikov)
ret = b1 >> (8 - nbits_left);
while (curr_size > nbits_left){
if (navail_bytes <= 0){
/* Out of bytes in current block, so read next block*/
pbytes = byte_buff;
if ((navail_bytes = (short)get_byte(file)) < 0)
return(navail_bytes);
else if (navail_bytes){
for (i = 0; i < navail_bytes; ++i){
if ((x = (short)get_byte(file)) < 0) return(x);
byte_buff[i] = (BYTE)x;
}
}
}
b1 = *pbytes++;
ret |= b1 << nbits_left;
nbits_left += 8;
--navail_bytes;
}
nbits_left = (short)(nbits_left-curr_size);
ret &= code_mask[curr_size];
return((short)(ret));
}
////////////////////////////////////////////////////////////////////////////////
/* short decoder(linewidth)
* short linewidth; * Pixels per line of image *
*
* - This function decodes an LZW image, according to the method used
* in the GIF spec. Every *linewidth* "characters" (ie. pixels) decoded
* will generate a call to out_line(), which is a user specific function
* to display a line of pixels. The function gets it's codes from
* get_next_code() which is responsible for reading blocks of data and
* seperating them into the proper size codes. Finally, get_byte() is
* the global routine to read the next BYTE from the GIF file.
*
* It is generally a good idea to have linewidth correspond to the actual
* width of a line (as specified in the Image header) to make your own
* code a bit simpler, but it isn't absolutely necessary.
*
* Returns: 0 if successful, else negative. (See ERRS.H)
*
*/
/* bad_code_count is incremented each time an out of range code is read.
* When this value is non-zero after a decode, your GIF file is probably
* corrupt in some way...
*/
short CxImageGIF::decoder(CxFile* file, CImageIterator* iter, short linewidth, int &bad_code_count)
{
register BYTE *sp, *bufptr;
BYTE *buf;
register short code, fc, oc, bufcnt;
short c, size, ret;
/* Initialize for decoding a new image... */
bad_code_count = 0;
if ((size = (short)get_byte(file)) < 0) return(size);
if (size < 2 || 9 < size) return(BAD_CODE_SIZE);
// out_line = outline;
init_exp(size);
//printf("L %d %x\n",linewidth,size);
/* Initialize in case they forgot to put in a clear code.
* (This shouldn't happen, but we'll try and decode it anyway...)
*/
oc = fc = 0;
/* Allocate space for the decode buffer */
if ((buf = new BYTE[linewidth + 1]) == NULL) return(OUT_OF_MEMORY);
/* Set up the stack pointer and decode buffer pointer */
sp = stack;
bufptr = buf;
bufcnt = linewidth;
/* This is the main loop. For each code we get we pass through the
* linked list of prefix codes, pushing the corresponding "character" for
* each code onto the stack. When the list reaches a single "character"
* we push that on the stack too, and then start unstacking each
* character for output in the correct order. Special handling is
* included for the clear code, and the whole thing ends when we get
* an ending code.
*/
while ((c = get_next_code(file)) != ending) {
/* If we had a file error, return without completing the decode*/
if (c < 0){
delete[] buf;
return(0);
}
/* If the code is a clear code, reinitialize all necessary items.*/
if (c == clear){
curr_size = (short)(size + 1);
slot = newcodes;
top_slot = (short)(1 << curr_size);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -