jzimagegif.cpp
来自「君正早期ucos系统(只有早期的才不没有打包成库),MPLAYER,文件系统,图」· C++ 代码 · 共 947 行 · 第 1/2 页
CPP
947 行
/*******************************************************************************
* 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 CJzImageGIF::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);
}
////////////////////////////////////////////////////////////////////////////////
static const unsigned long code_mask[] = { 0x0000, 0x0001, 0x0003, 0x0007, 0x000F,
0x001F, 0x003F, 0x007F, 0x00FF,
0x01FF, 0x03FF, 0x07FF, 0x0FFF,
0x1FFF, 0x3FFF, 0x7FFF, 0xFFFF };
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
/* 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 CJzImageGIF::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 CJzImageGIF::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);
/* Continue reading codes until we get a non-clear code
* (Another unlikely, but possible case...)
*/
while ((c = get_next_code(file)) == clear);
/* If we get an ending code immediately after a clear code
* (Yet another unlikely case), then break out of the loop.
*/
if (c == ending) break;
/* Finally, if the code is beyond the range of already set codes,
* (This one had better NOT happen... I have no idea what will
* result from this, but I doubt it will look good...) then set it
* to color zero.
*/
if (c >= slot) c = 0;
oc = fc = c;
/* And let us not forget to put the char into the buffer... And
* if, on the off chance, we were exactly one pixel from the end
* of the line, we have to send the buffer to the out_line()
* routine...
*/
*bufptr++ = (BYTE)c;
if (--bufcnt == 0) {
if ((ret = (short)out_line(iter, buf, linewidth)) < 0) {
delete[] buf;
return(ret);
}
bufptr = buf;
bufcnt = linewidth;
}
} else {
/* In this case, it's not a clear code or an ending code, so
* it must be a code code... So we can now decode the code into
* a stack of character codes. (Clear as mud, right?)
*/
code = c;
/* Here we go again with one of those off chances... If, on the
* off chance, the code we got is beyond the range of those already
* set up (Another thing which had better NOT happen...) we trick
* the decoder into thinking it actually got the last code read.
* (Hmmn... I'm not sure why this works... But it does...)
*/
if (code >= slot) {
if (code > slot) ++bad_code_count;
code = oc;
*sp++ = (BYTE)fc;
}
/* Here we scan back along the linked list of prefixes, pushing
* helpless characters (ie. suffixes) onto the stack as we do so.
*/
while (code >= newcodes) {
*sp++ = suffix[code];
code = prefix[code];
}
/* Push the last character on the stack, and set up the new
* prefix and suffix, and if the required slot number is greater
* than that allowed by the current bit size, increase the bit
* size. (NOTE - If we are all full, we *don't* save the new
* suffix and prefix... I'm not certain if this is correct...
* it might be more proper to overwrite the last code...
*/
*sp++ = (BYTE)code;
if (slot < top_slot){
suffix[slot] = (BYTE)(fc = (BYTE)code);
prefix[slot++] = oc;
oc = c;
}
if (slot >= top_slot){
if (curr_size < 12) {
top_slot <<= 1;
++curr_size;
}
}
/* Now that we've pushed the decoded string (in reverse order)
* onto the stack, lets pop it off and put it into our decode
* buffer... And when the decode buffer is full, write another
* line...
*/
while (sp > stack) {
*bufptr++ = *(--sp);
if (--bufcnt == 0) {
if ((ret = (short)out_line(iter, buf, linewidth)) < 0) {
delete[] buf;
return(ret);
}
bufptr = buf;
bufcnt = linewidth;
}
}
}
}
ret = 0;
if (bufcnt != linewidth)
ret = (short)out_line(iter, buf, (linewidth - bufcnt));
delete[] buf;
return(ret);
}
////////////////////////////////////////////////////////////////////////////////
int CJzImageGIF::get_num_frames(CxFile *fp,struct_TabCol* TabColSrc,struct_dscgif* dscgif)
{
struct_image image;
//printf(" ====== Extension decoder ========\n");
long pos=fp->Tell();
int nframes=0;
struct_TabCol TempTabCol;
memcpy(&TempTabCol,TabColSrc,sizeof(struct_TabCol));
char ch;
bool bPreviousWasNull = true;
for (BOOL bContinue = TRUE; bContinue; )
{
if (fp->Read(&ch, sizeof(ch), 1) != 1) {break;}
if (bPreviousWasNull || ch==0)
{
switch (ch)
{
case '!': // extension
{
DecodeExtension(fp);
break;
}
case ',': // image
{
//assert(sizeof(image) == 9);
//log << "Image header" << endl;
fp->Read(&image,sizeof(image),1);
//avoid byte order problems with Solaris <candan>
BYTE *byteData = (BYTE *) & image;
image.l = byteData[0]+byteData[1]*256;
image.t = byteData[2]+byteData[3]*256;
image.w = byteData[4]+byteData[5]*256;
image.h = byteData[6]+byteData[7]*256;
if (((image.l + image.w) > dscgif->scrwidth)||((image.t + image.h) > dscgif->scrheight))
break;
nframes++;
// Local colour map?
if (image.pf & 0x80) {
TempTabCol.sogct = (short)(1 << ((image.pf & 0x07) +1));
//assert(3 == sizeof(struct rgb_color));
fp->Read(TempTabCol.paleta,sizeof(struct rgb_color)*TempTabCol.sogct,1);
//log << "Local colour map" << endl;
}
int bpp; //<DP> select the correct bit per pixel value
if (TempTabCol.sogct <= 2) bpp = 1;
else if (TempTabCol.sogct <= 16) bpp = 4;
else bpp = 8;
Create(image.w, image.h, bpp, CXIMAGE_FORMAT_GIF);
CImageIterator* iter = new CImageIterator(this);
iter->Upset();
int badcode=0;
ibf = GIFBUFTAM+1;
interlaced = image.pf & 0x40;
iheight = image.h;
istep = 8;
iypos = 0;
ipass = 0;
long pos_start = fp->Tell();
//if (interlaced) log << "Interlaced" << endl;
decoder(fp, iter, image.w, badcode);
delete iter;
if (badcode){
seek_next_image(fp,pos_start);
} else {
fp->Seek(-(ibfmax - ibf - 1), SEEK_CUR);
}
break;
}
case ';': //terminator
bContinue=false;
break;
default:
bPreviousWasNull = (ch==0);
break;
}
}
}
fp->Seek(pos,SEEK_SET);
return nframes;
}
////////////////////////////////////////////////////////////////////////////////
long CJzImageGIF::seek_next_image(CxFile* fp, long position)
{
fp->Seek(position, SEEK_SET);
char ch1,ch2;
ch1=ch2=0;
while(fp->Read(&ch2,sizeof(char),1)>0){
if (ch1 == 0 && ch2 == ','){
fp->Seek(-1,SEEK_CUR);
return fp->Tell();
} else {
ch1 = ch2;
}
}
return -1;
}
void CJzImageGIF::GifMix(CJzImage & imgsrc2, struct_image & imgdesc)
{
long ymin = max(0,(long)(GetHeight()-imgdesc.t - imgdesc.h));
long ymax = GetHeight()-imgdesc.t;
long xmin = imgdesc.l;
long xmax = min(GetWidth(), (DWORD)(imgdesc.l + imgdesc.w));
long ibg2= imgsrc2.GetTransIndex();
BYTE i2;
for(long y = ymin; y < ymax; y++){
for(long x = xmin; x < xmax; x++){
i2 = imgsrc2.GetPixelIndex(x-xmin,y-ymin);
if(i2!=ibg2) SetPixelIndex(x,y,i2);
}
}
}
////////////////////////////////////////////////////////////////////////////////
void CJzImageGIF::GIFShowFrame( BYTE *pbuffer, struct_image &image, int prevdispmeth)
{
int i, j, index, dx, dy;
RGBQUAD *palette = GetPalette(), color;
unsigned char *ptar;//
long ymin = max(0,(long)(GetHeight()-image.t - image.h));
long ymax = GetHeight()-image.t;
long xmin = image.l;
long xmax = min(GetWidth(), (DWORD)(image.l + image.w));
long jmin = ymin*ivscale/128;
long jmax = ymax*ivscale/128;
if( jmax > info.dwimaHeight ) jmax = info.dwimaHeight;
long imin = xmin*ivscale/128;
long imax = xmax*ivscale/128;
if( imax > info.dwimaWidth ) imax = info.dwimaWidth;
//printf(" ================= GetHeight: %d, ivscale: %d \n", GetHeight(), ivscale );
//printf(" ======= image.l: %d, image.t: %d, image.w: %d, image.h: %d\n",image.l,image.t,image.w,image.h);
//printf(" ================= xmin: %d, xmax: %d, ymin: %d, ymax: %d\n", xmin, xmax, ymin, ymax );
//printf(" ================= imin: %d, imax: %d, jmin: %d, jmax: %d\n", imin, imax, jmin, jmax );
//printf(" ================= rescreen_h: %d\n", rescreen_h );
BYTE *line = pbuffer;
//line = pbuffer + (rescreen_h-1) * info.dwimaWidth * 4;
if( prevdispmeth == 2 )
{
memset( (void *)line, 0, info.dwimaHeight*info.dwimaWidth*4 );
}
dy = ymin;
for( j = jmin+1; j <= jmax; j++ )
{
line = pbuffer + (info.dwimaHeight-j)* info.dwimaWidth * 4;
while( ivscale*dy/128 < j ) dy++;
dx = xmin;
for( i = imin; i < imax; i++ )
{
while( ivscale*dx/128 < i ) dx++;
index = GetPixelIndex(dx,dy);
color = palette[index];
line[i*4+2] = color.rgbRed;
line[i*4+1] = color.rgbGreen;
line[i*4+0] = color.rgbBlue;
}
//line = line - info.dwimaWidth * 4;
}
ivDeflateGifImage();
}
#endif // CXIMAGE_SUPPORT_GIF
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?