⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 gif.cpp

📁 < 精通Visual C++图象处理编程>>(第3版)第八章配套源码,希望对学过此书的同学或开发人员有帮助
💻 CPP
📖 第 1 页 / 共 2 页
字号:
// Gif.cpp: implementation of the CGif class.
//
//////////////////////////////////////////////////////////////////////

#include "stdafx.h"

#include <io.h>
#include <fcntl.h>
#include <string.h>
#include <stdio.h>
#include <conio.h>
#include <stdlib.h>

#include "Gif.h"

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif

//////////////////////////////////////////////////////////////////////
// Global variables
//
GIF89 Gif89 = {-1,-1,-1,0};
GIFSCREEN GifScreen;
static unsigned long masks[] = { 0x0000, 0x0001, 0x0003, 0x0007, 0x000F,
                                  0x001F, 0x003F, 0x007F, 0x00FF,
                                  0x01FF, 0x03FF, 0x07FF, 0x0FFF,
                                  0x1FFF, 0x3FFF, 0x7FFF, 0xFFFF };

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

CGif::CGif()
{
	ZeroDataBlock = FALSE;
	m_strGIFError = "No Error"; // yet
	m_pDib = NULL;
	cur_accum = 0;
	cur_bits = 0;
	maxbits = BITS;
	maxmaxcode = (code_int)1 << BITS;
	free_ent = 0;
	clear_flg = 0;

	m_pDib = NULL;
}

CGif::CGif(CDib *pDib)
{
	ZeroDataBlock = FALSE;
	m_strGIFError = "No Error"; // yet
	m_pDib = NULL;
	cur_accum = 0;
	cur_bits = 0;
	maxbits = BITS;
	maxmaxcode = (code_int)1 << BITS;
	free_ent = 0;
	clear_flg = 0;

	m_pDib = NULL;

	SetDib(pDib);
}

CGif::~CGif()
{
	if (m_pDib != NULL)
		delete m_pDib;
}

// free allocate memory
void CGif::FreeBuffer(BYTE *Buffer)
{
	delete[] Buffer;
}

// get error string
CString CGif::GetErrorString()
{
	return m_strGIFError;
}

// load gif file
BOOL CGif::Load(LPCTSTR lpstrFileName)
{
	UINT uWidth, uHeight, uWidthDW;

	// read the GIF to a packed buffer of RGB bytes
	BYTE *lpTmpBuffer = ReadGIFFile(lpstrFileName, &uWidth, &uHeight);
	if (lpTmpBuffer == NULL)
		return FALSE;

	// do this before DWORD-alignment!!!
	// swap red and blue for display
	BGRFromRGB(lpTmpBuffer, uWidth, uHeight);

	// now DWORD-align for display
	BYTE *lpBuffer = MakeDwordAlign(lpTmpBuffer, uWidth, uHeight, &uWidthDW);
	FreeBuffer(lpTmpBuffer);

	// flip for display
	VertFlipBuf(lpBuffer, uWidthDW, uHeight);

	BITMAPINFOHEADER bmiHeader;
	bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
	bmiHeader.biWidth = uWidth;
	bmiHeader.biHeight = uHeight;
	bmiHeader.biPlanes = 1;
	bmiHeader.biBitCount = 24;
	bmiHeader.biCompression = BI_RGB;
	bmiHeader.biSizeImage = 0;
	bmiHeader.biXPelsPerMeter = 0;
	bmiHeader.biYPelsPerMeter = 0;
	bmiHeader.biClrUsed = 0;
	bmiHeader.biClrImportant = 0;

    // Allocate enough memory for the new CF_DIB, and copy bits 
	DWORD dwHeaderSize = sizeof(BITMAPINFOHEADER);
	DWORD dwBitsSize = WIDTHBYTES(uWidth*24) * uHeight;
    HDIB hDIB = GlobalAlloc(GHND, dwHeaderSize + dwBitsSize); 
	if (hDIB == NULL)
		return FALSE;

    LPBYTE lpDIB = (LPBYTE)GlobalLock(hDIB); 
    memcpy(lpDIB, (LPBYTE)&bmiHeader, dwHeaderSize); 
    memcpy(FindDIBBits((LPBYTE)lpDIB), lpBuffer, dwBitsSize); 
	FreeBuffer(lpBuffer);

	if (m_pDib != NULL)
		delete m_pDib;

	m_pDib = new CDib();
	m_pDib->Attach(hDIB);

	return TRUE;
}

// save gif file
BOOL CGif::Save(LPCTSTR lpstrFileName, CDib* pDib)
{
	if (pDib == NULL)
		pDib = m_pDib;
	if (pDib == NULL)
		return FALSE;

	HDIB hDib = CopyHandle(pDib->GetHandle());
	if (hDib == NULL)
		return FALSE;

	CDib* pDibTmp = new CDib;
	pDibTmp->Attach(hDib);

	//if (pDibTmp->GetBitCount() != 24)
	//	pDibTmp->ConvertFormat(24);

	UINT uWidth  = pDibTmp->GetWidth();
	UINT uHeight = pDibTmp->GetHeight();

	// convert to 8-bit image
	if (pDibTmp->GetBitCount() != 8)
		pDibTmp->ColorQuantize(8);

	// get 256 color r, g, b
	PALETTEENTRY PaletteColors[256];
	pDibTmp->GetPalette()->GetPaletteEntries(0, 256, PaletteColors);
	int red[256], blue[256], green[256];
	for (int i=0;i<256;i++) 
	{
		red[i]   = PaletteColors[i].peRed;
		green[i] = PaletteColors[i].peGreen;
		blue[i]  = PaletteColors[i].peBlue;
	}

	// convert from DIB format (DWORD aligned, vertically flipped, red and blue swapped)
	BYTE *tmp = ClearDwordAlign(pDibTmp->GetBitsPtr(), uWidth, uHeight, 8);
	if (tmp == NULL)
		return FALSE;

	// convert from DIB
	VertFlipBuf(tmp, uWidth, uHeight);

	BOOL bSuccess = WriteGIFFile(lpstrFileName,
							tmp, uWidth, uHeight,
							0,		// background color
							red, green, blue);

	delete pDibTmp;
	FreeBuffer(tmp);

	return bSuccess;
}

LPBYTE CGif::ReadGIFFile(LPCTSTR lpstrFileName, UINT *uWidth, UINT *uHeight)
{
	BYTE			buf[16];
	BYTE			c;
	BYTE			localColorMap[3][MAXCOLORMAPSIZE];
	int				useGlobalColormap;
	int				bitPixel;
	int				imageCount	=0;
	char			version[4];
	FILE 			*fd;          
	int 			w=0;
	int				h=0;	

	CString strFileName = lpstrFileName;
	if (strFileName.IsEmpty()) 
	{
		m_strGIFError="No Name Given";
		return NULL;
	}

	BYTE *bigBuf;

	fd=fopen(lpstrFileName,"rb");
	if (fd==NULL) 
	{                       
		m_strGIFError="Cant open GIF :\n" + strFileName;
		return NULL;
	}

	// read GIF file header
	if (!ReadOK(fd,buf,6)) 
	{
		m_strGIFError="Error reading GIF Magic #\n"+strFileName;
		fclose(fd);
		return NULL;
	}
	
	// need the string "GIF" in the header
	if (strncmp((char *)buf,"GIF",3)!=0) 
	{
		m_strGIFError="Error, "+strFileName+" is not a valid .GIF file";
		fclose(fd);
		return NULL;
	}	

	strncpy(version,(char *)(buf+3),3);
	version[3]='\0';

	// only handle v 87a and 89a
	if ((strcmp(version,"87a")!=0)&&(strcmp(version,"89a")!=0)) 
	{
		m_strGIFError="Error, Bad GIF Version number";
		fclose(fd);
		return NULL;
	}	

	// screen description
	if (!ReadOK(fd,buf,7)) 
	{
		m_strGIFError="Error, failed to GIF read screen descriptor.\nGiving up";
		fclose(fd);
		return NULL;
	}

	GifScreen.Width		=	LM_to_uint((BYTE)buf[0],(BYTE)buf[1]);
	GifScreen.Height	=	LM_to_uint((BYTE)buf[2],(BYTE)buf[3]);
	GifScreen.BitPixel	=	2 << ((BYTE)buf[4] & 0x07);
	GifScreen.ColorResolution = ((((BYTE)buf[4] & 0x70) >> 3) + 1);
	GifScreen.BackGround=	(BYTE)buf[5];									// background color...
	GifScreen.AspectRatio=	(BYTE)buf[6];
            

	// read colormaps
	if (BitSet((BYTE)buf[4],LOCALCOLORMAP)) 
	{
		if (!ReadColorMap(fd,GifScreen.BitPixel,GifScreen.ColorMap)) 
		{
			m_strGIFError="Error reading GIF colormap";
			fclose(fd);
			return NULL;                                             
		}
	}

	// non-square pixels, so what?	
	if ((GifScreen.AspectRatio!=0 ) && (GifScreen.AspectRatio!=49)) 
	{
		m_strGIFError="Non-square pixels in GIF image.\nIgnoring that fact...";
	}

	// there can be multiple images in a GIF file... uh?
	// what the hell do we do with multiple images?
	// so, we'll be interested in just the first image, cause we're lazy

	for(;;) 
	{	
		// read a byte;
		if (!ReadOK(fd,&c,1)) 
		{
			m_strGIFError="Unexpected EOF in GIF.\nGiving up";
			fclose(fd);
			return NULL; 
		}
	
		// image terminator
		if (c==';') 
		{
		}
	
		if (c=='!') 
		{
			if (!ReadOK(fd,&c,1)) 
			{
				m_strGIFError="Error on extension read.\nGiving up";
				fclose(fd);
				return NULL;       
			}
			DoExtension(fd,c);
			continue;
		}
	
		if (c!=',') 
		{
			// Ignoring c
			continue;
		}
	
		// read image header
		if (!ReadOK(fd,buf,9)) 
		{
			m_strGIFError="Error on dimension read\nGiving up";
			fclose(fd);
			return NULL;                     
		}
	
		useGlobalColormap=!BitSet((BYTE)buf[8],LOCALCOLORMAP);
	
		bitPixel=1<<(((BYTE)buf[8]&0x07)+1);
	
	    // let's see if we have enough mem to continue?

		long bufsize;

		if ((int)buf[5]>4) 
		{
			//AfxMessageBox("This GIF file claims to be > 2000 bytes wide!",MB_OK | MB_ICONINFORMATION);
		}
		if ((int)buf[7]>4) 
		{
			//AfxMessageBox("This GIF file claims to be > 2000 bytes high!",MB_OK | MB_ICONINFORMATION);
		}		                                                       
		
		w=LM_to_uint((BYTE)buf[4],(BYTE)buf[5]);		
		h=LM_to_uint((BYTE)buf[6],(BYTE)buf[7]);
		
		if ((w<0) || (h<0)) 
		{
			m_strGIFError="Negative image dimensions!\nGiving up";
			fclose(fd);
			return NULL;
		}
				
		bufsize=(long)w*(long)h;
		bufsize*=3;
		bigBuf= (BYTE *) new char [bufsize];
		
		if (bigBuf==NULL) 
		{
			m_strGIFError="Out of Memory in GIFRead";
			fclose(fd);
			return NULL;
		}
			
		if (!useGlobalColormap) 
		{
			if (!ReadColorMap(fd,bitPixel,localColorMap)) 
			{
				m_strGIFError="Error reading GIF colormap\nGiving up";
				delete [] bigBuf;
				fclose(fd);
				return NULL;                     
			}
	
		 	//read image
			if (!ReadImage(fd, bigBuf, w, h, localColorMap, BitSet((BYTE)buf[8],INTERLACE))) 
			{
				m_strGIFError="Error reading GIF file\nLocalColorMap\nGiving up";
				delete [] bigBuf;
				fclose(fd);
				return NULL; 				
			}
		} 
		else 
		{
			if (!ReadImage(fd, bigBuf, w, h, GifScreen.ColorMap, BitSet((BYTE)buf[8],INTERLACE))) 
			{
				m_strGIFError="Error reading GIF file\nGIFScreen Colormap\nGiving up";
				delete [] bigBuf;
				fclose(fd);
				return NULL; 			
			}
		}
		break;
	}

	*uWidth=w;
	*uHeight=h;
		
	fclose(fd);
	return bigBuf;
}

int CGif::ReadColorMap(FILE *fd, int number, BYTE buffer[3][MAXCOLORMAPSIZE])
{
	int 	i;
	BYTE rgb[3];
	
	for (i=0;i < number; ++i) 
	{
		if (!ReadOK(fd,rgb,sizeof(rgb))) 
		{
			return FALSE;
		}
		
		buffer[CM_RED][i]=rgb[0];
		buffer[CM_GREEN][i]=rgb[1];
		buffer[CM_BLUE][i]=rgb[2];
	}	
	return TRUE;
}

int CGif::DoExtension(FILE *fd, int label)
{
	static char buf[256];
	char	*str;

	switch(label) 
	{
	case 0x01  :
		str="Plain Text Ext";
		break;
	case 0xff :
		str= "Appl ext";
		break;
	case 0xfe :
		str="Comment Ext";
		while (GetDataBlock(fd,(BYTE *)buf)!=0);
		return FALSE;
	case 0XF9 :
		str="Graphic Ctrl Ext";
		(void)GetDataBlock(fd,(BYTE *)buf);
		Gif89.disposal	=(buf[0]>>2)		&0x7;
		Gif89.inputFlag	=(buf[0]>>1)		&0x1;
		Gif89.delayTime	=LM_to_uint(buf[1],buf[2]);
		if ((buf[0]&0x1)!=0)
			Gif89.transparent=buf[3];
	
		while (GetDataBlock(fd,(BYTE *)buf)!=0);
		return FALSE;
	default :
		str=buf;
		sprintf(buf,"UNKNOWN (0x%02x)",label);
		break;
	}
	
	while (GetDataBlock(fd,(BYTE *)buf)!=0);

	return FALSE;
}

int CGif::GetDataBlock(FILE *fd, BYTE *buf)
{
	BYTE count;

	if (!ReadOK(fd,&count,1)) 
	{
		//m_strGIFError="Error in GIF DataBlock Size";
		return -1;
	}

	ZeroDataBlock=count==0;

	if ((count!=0) && (!ReadOK(fd,buf,count))) 
	{
		//m_strGIFError="Error reading GIF datablock";
		return -1;
	}
	return count;
}

int CGif::GetCode(FILE *fd, int code_size, int flag)
{
	static BYTE buf[280];
	static int curbit, lastbit, done, last_byte;
	int i,j,ret;
	BYTE count;

	if (flag) 
	{
		curbit=0;
		lastbit=0;
		done=FALSE;
		return 0;
	}

	if ((curbit+code_size) >=lastbit) 
	{
		if (done) 
		{
			if (curbit >=lastbit) 
			{
				//m_strGIFError="Ran off the end of my bits";
				return 0;
			}
			return -1;
		}
		buf[0]=buf[last_byte-2];	
		buf[1]=buf[last_byte-1];

		if ((count=GetDataBlock(fd,&buf[2]))==0)
			done=TRUE;

		last_byte=2+count;

		curbit=(curbit - lastbit) + 16;

		lastbit = (2+count)*8;
	}
	ret=0;
	for (i=curbit,j=0; j<code_size;++i,++j)
		ret|=((buf[i/8]&(1<<(i% 8)))!=0)<<j;

	curbit+=code_size;

	return ret;
}

int CGif::LZWReadByte(FILE *fd, int flag, int input_code_size)
{
	static int fresh=FALSE;
	int code, incode;
	static int code_size, set_code_size;
	static int max_code, max_code_size;
	static int firstcode, oldcode;
	static int clear_code, end_code;

	static unsigned short  next[1<<MAX_LZW_BITS];
	static BYTE  vals[1<<MAX_LZW_BITS];
	static BYTE  stack [1<<(MAX_LZW_BITS+1)];
	static BYTE  *sp;
	
	register int i;

	if (flag) 
	{
		set_code_size=input_code_size;
		code_size=set_code_size+1;
		clear_code=1<<set_code_size;
		end_code = clear_code+1;
		max_code = clear_code+2;
		max_code_size=2*clear_code;

		GetCode(fd,0,TRUE);

		fresh=TRUE;
	
		for(i=0;i<clear_code;++i) 
		{
			next[i]=0;
			vals[i]=i;
		}

		for (;i<(1<<MAX_LZW_BITS);++i)
			next[i]=vals[0]=0;
	
		sp=stack;

		return 0;
	} 
	else if (fresh) 
	{
			fresh=FALSE;
			do 
			{
				firstcode=oldcode=GetCode(fd,code_size,FALSE);
			} while (firstcode==clear_code);
			return firstcode;
		}

		if (sp > stack)
			return *--sp;

		while ((code= GetCode(fd,code_size,FALSE)) >=0) 
		{
			if (code==clear_code) 
			{
				for (i=0;i<clear_code;++i) 
				{
					next[i]=0;
					vals[i]=i;
				}
				for (;i<(1<<MAX_LZW_BITS);++i)	
					next[i]=vals[i]=0;
				code_size=set_code_size+1;
				max_code_size=2*clear_code;
				max_code=clear_code+2;
				sp=stack;
				firstcode=oldcode=GetCode(fd,code_size,FALSE);
				return firstcode;
			} 
			else if (code==end_code) 
			{
				int count;
				BYTE buf[260];
		
				if (ZeroDataBlock)
					return -2;

				while ((count=GetDataBlock(fd,buf)) >0);

				if (count!=0)
					//AfxMessageBox("Missing EOD in GIF data stream (common occurrence)",MB_OK);
				return -2;	
			}

			incode = code;

			if (code >= max_code) 
			{
				*sp++=firstcode;
				code=oldcode;
			}

			while (code >=clear_code) 
			{
				*sp++=vals[code];
				if (code==(int)next[code]) 
				{
					//m_strGIFError="Circular table entry, big GIF Error!";
					return -1;
				}
				code=next[code];
			}

			*sp++ = firstcode=vals[code];

			if ((code=max_code) <(1<<MAX_LZW_BITS)) 
			{
				next[code]=oldcode;
				vals[code]=firstcode;
				++max_code;
				if ((max_code >=max_code_size) &&
					(max_code_size < (1<<MAX_LZW_BITS))) 
				{
					 max_code_size*=2;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -