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

📄 gif.cpp

📁 一个国人自己实现图像库的程序(有参考价值)
💻 CPP
字号:
#include "stdafx.h"
#include "..\..\Include\Pic\Image.h"

//===================================================================
BOOL  FCImage::AddGifFrame (PCTSTR szFileName, bool bGolPal,
							DWORD dwDelay, DWORD dwTransIndex)
{
	BOOL			bRet = FALSE ;
	BYTE			* pStart = NULL, * pCurr ;
	HANDLE			hMap = NULL ;
	HANDLE			hFile = INVALID_HANDLE_VALUE ;

	__try
	{
		if (pFooDib->hBitmap == NULL)
			__leave ;
		if (this->ColorBits() > 8) // 支持1, 4, 8位色
			__leave ;

		//	获得文件大小
		WIN32_FILE_ATTRIBUTE_DATA	file_data ;
		if (::GetFileAttributesEx (szFileName, GetFileExInfoStandard, &file_data) == 0)
			__leave ;

		pStart = this->__fooGifOpenFileForAddFrame (szFileName, &hFile, &hMap, file_data.nFileSizeLow + this->GetPitch()*Height()*2) ;
		if (pStart == NULL)
			__leave ;
		pCurr = pStart + file_data.nFileSizeLow - 1 ; // 文件结尾 ==> 0x3B
		if (*pCurr != 0x3B)
			__leave ;

		//	加入图形控制扩充块
		BYTE	ExtBlk[13] = {0x21, 0xF9, 4, 0, 0, 0, 0, 0, 
							  0x2C, 0, 0, 0, 0} ;
		* (WORD *) &ExtBlk[4] =  dwDelay / 10 ;
		ExtBlk[3] |= (dwTransIndex == -1) ? 0 : 1 ; // 透明色标志
		ExtBlk[6] = dwTransIndex ;
		CopyMemory (pCurr, ExtBlk, 13) ;
		pCurr += 13 ;
		* (WORD *) pCurr = (WORD) this->Width() ;
		* (WORD *) &pCurr[2] = (WORD) this->Height() ;
		pCurr[4] = 0 ;
		if (!bGolPal)
			pCurr[4] |= 0x80 | (this->ColorBits() - 1) ; // 局部调色板
		pCurr += 5 ;

		if (!bGolPal) // 加入区域调色板
		{
			int			iColorNum = 1 << this->ColorBits() ;
			RGBQUAD		* Palette = new RGBQUAD [iColorNum] ;
			this->GetColorTable (0, iColorNum, Palette) ;
			for (int i = 0 ; i < iColorNum ; i++)
			{
				*pCurr++ = Palette[i].rgbRed ;
				*pCurr++ = Palette[i].rgbGreen ;
				*pCurr++ = Palette[i].rgbBlue ;
			}
			delete[] Palette ;
		}

		//	压缩
		BYTE	* pEncode, * pSrc ;
		pSrc = pEncode = (BYTE *) ::VirtualAlloc (NULL, Width()*Height()*2, MEM_COMMIT, PAGE_READWRITE) ;
		if (pEncode == NULL)
			__leave ;
		DWORD	dwWrite = this->__fooGifEncode (pEncode) ;

		//	压缩数据打包
		int			iPack = dwWrite / 0xFF,		// 生成块数
					iLeft = dwWrite % 0xFF ;	// 剩余字节
		*pCurr++ = (this->ColorBits () == 1) ? 2 : this->ColorBits () ; // 写入最小码长度
		while (iPack-- > 0) // 拷贝整块
		{
			*pCurr++ = 0xFF ;
			CopyMemory (pCurr, pSrc, 0xFF) ;
			pCurr += 0xFF ; pSrc += 0xFF ;
		}
		if (iLeft != 0) // 移动最后一个块
		{
			*pCurr++ = iLeft ;
			CopyMemory (pCurr, pSrc, iLeft) ;
			pCurr += iLeft ; pSrc += iLeft ;
		}
		::VirtualFree (pEncode, 0, MEM_RELEASE) ;
		*pCurr++ = 0 ;
		*pCurr++ = 0x3B ; // 设结尾
		::UnmapViewOfFile (pStart) ;
		::CloseHandle (hMap) ;
		::SetFilePointer (hFile, pCurr - pStart, NULL, FILE_BEGIN) ;
		::SetEndOfFile (hFile) ; // 结束头信息
		::CloseHandle (hFile) ;
		pStart = NULL ; hMap = NULL ;
		hFile = INVALID_HANDLE_VALUE ;
		bRet = TRUE ;
	}
	__finally
	{
		this->__fooImageUnmapFile (pStart, hMap, hFile) ;
	}
	return bRet ;
}
//===================================================================
BOOL  FCImage::SaveGif (PCTSTR szFileName, bool bGolPal)
{
	BOOL			bRet = FALSE ;
	BYTE			* pStart = NULL, * pCurr ;
	HANDLE			hMap = NULL ;
	HANDLE			hFile = INVALID_HANDLE_VALUE ;

	__try
	{
		if (pFooDib->hBitmap == NULL)
			__leave ;
		if (this->ColorBits() > 8) // 支持1, 4, 8位色
			__leave ;

		//	创建文件
		pStart = this->__fooImageSaveFile (szFileName, &hFile, &hMap, 1024 * 4) ;
		if (pStart == NULL)
			__leave ;

		//	写头
		CopyMemory (pStart, "GIF89a", 6) ;
		* (WORD *) &pStart[6] = this->Width() ; // 屏幕宽
		* (WORD *) &pStart[8] = this->Height() ; // 屏幕高
		pCurr = pStart + 13 ;

		//	使用此帧调色板作为全局调色板
		if (bGolPal)
		{
			pStart[10] = 0x80 | (this->ColorBits() - 1) ; // 设置全局调色板标志
		
			//	设置全局调色板条目
			int			iColorNum = 1 << this->ColorBits() ;
			RGBQUAD		* Palette = new RGBQUAD [iColorNum] ;
			this->GetColorTable (0, iColorNum, Palette) ;
			for (int i = 0 ; i < iColorNum ; i++)
			{
				*pCurr++ = Palette[i].rgbRed ;
				*pCurr++ = Palette[i].rgbGreen ;
				*pCurr++ = Palette[i].rgbBlue ;
			}
			delete[] Palette ;
		}

		*pCurr++ = 0x3B ; // 头结束, 设置标志给 AddGifFrame ()
		::UnmapViewOfFile (pStart) ;
		::CloseHandle (hMap) ;
		::SetFilePointer (hFile, pCurr - pStart, NULL, FILE_BEGIN) ;
		::SetEndOfFile (hFile) ; // 结束头信息
		::CloseHandle (hFile) ;
		pStart = NULL ; hMap = NULL ;
		hFile = INVALID_HANDLE_VALUE ;

		//	加入第一帧
		bRet = this->AddGifFrame (szFileName, bGolPal) ;
	}
	__finally
	{
		this->__fooImageUnmapFile ((BYTE *)pStart, hMap, hFile) ;
	}
	return bRet ;
}
//===================================================================
BOOL  FCImage::LoadGif (PCTSTR resName, PCTSTR resType)
{
	HRSRC	res = ::FindResource (NULL, resName, resType) ;
	HGLOBAL	gol = ::LoadResource (NULL, res) ;
	BYTE	* pGifData = (BYTE *) ::LockResource (gol) ;
	this->__fooGifScanFile (pGifData, ::SizeofResource (NULL, res)) ;
	return this->LoadGifNextFrame () ;
}
//===================================================================
BOOL  FCImage::LoadGif (PCTSTR szFileName)
{
	BOOL			bRet = FALSE ;
	BYTE			* pStart = NULL ;
	HANDLE			hMap = NULL ;
	HANDLE			hFile = INVALID_HANDLE_VALUE ;

	__try
	{
		//	映射文件
		pStart = this->__fooImageReadFile (szFileName, &hFile, &hMap) ;
		if (pStart == NULL)
			__leave ;

		this->__fooGifScanFile (pStart, ::GetFileSize(hFile, NULL)) ;
		if (!this->LoadGifNextFrame ()) // 读第一帧
			__leave ;
		bRet = TRUE ;
	}
	__finally
	{
		this->__fooImageUnmapFile ((BYTE *)pStart, hMap, hFile) ;
	}
	return bRet ;
}
//===================================================================
BOOL  FCImage::LoadGifFrame (int iNumber)
{
	m_pGifInfo->wCurrentFrame = max (0, min (iNumber - 1, m_pGifInfo->wTotalFrame)) ;
	return (this->LoadGifNextFrame () == 1) ;
}
//===================================================================
int  FCImage::LoadGifNextFrame ()
{
	if (m_pGifInfo == NULL)	// 未调用__fooGifScanFile 或失败
		return 0 ;
	if (m_pGifInfo->wCurrentFrame >= m_pGifInfo->wTotalFrame)
		return 2 ;	// 当前帧已是最后一帧

	BYTE	  * pStart = NULL, * pFrame = NULL ;
	int			iRet = 0 ;
	__try
	{
		pStart = m_pGifInfo->pStart ;
		if (pStart == NULL)
			__leave ;

		//	定位当前帧的位置, 在0x2C后的第一个字节 + 4
		pFrame = pStart + m_pGifInfo->pFrameIndexArray[m_pGifInfo->wCurrentFrame + 1] + 4 ;

		//	创建DIB, 所有位色GIF一律解码为8位色DIB
		if (!this->Create (* (WORD *) pFrame, * (WORD *) &pFrame[2], 8))
			__leave ;
		pFrame += 4 ;
		m_pGifInfo->byInterlace = *pFrame & 0x40 ; // 交错显示

		//	设置调色板
		int			iPalNum = 1 << ((*pFrame & 0x07) + 1) ;
		RGBQUAD		* Palette = new RGBQUAD [256] ;
		if (*pFrame++ & 0x80) // 区域调色板
			for (int i = 0 ; i < iPalNum ; i++)
			{
				Palette[i].rgbRed = *pFrame++ ;
				Palette[i].rgbGreen = *pFrame++ ;
				Palette[i].rgbBlue = *pFrame++ ;
			}
		else // 为全局调色板
		{
			iPalNum = m_pGifInfo->wGolPalNum ;
			BYTE	* pBak = pStart + 13 ;
			for (int i = 0 ; i < iPalNum ; i++)
			{
				Palette[i].rgbRed = *pBak++ ;
				Palette[i].rgbGreen = *pBak++ ;
				Palette[i].rgbBlue = *pBak++ ;
			}
		}
		this->SetColorTable (0, iPalNum, Palette) ;
		delete[] Palette ;

		//	解包 (因为GIF文件数据打包存放) ---------------------+
		BYTE	* pbyBak = pFrame ;	// 保存指针, 先计算大小
		pbyBak++ ; // Skip min-code length
		while (*pbyBak != 0)	// Skip data sub block
			pbyBak += *pbyBak + 1 ;
		BYTE	* pIndata = new BYTE [pbyBak - pFrame] ;
		pbyBak = pIndata ;
		*pbyBak++ = *pFrame++ ;	// copy min-code length
		while (*pFrame != 0)	// copy data sub block
		{
			CopyMemory (pbyBak, pFrame + 1, *pFrame) ;
			pbyBak += *pFrame ;
			pFrame += *pFrame + 1 ;
		} // 解包完成, 未解压数据==>pIndata --------------------+

		//	开始解压缩
		this->__fooGifDecode (pIndata) ;
		delete[] pIndata ;
		m_pGifInfo->wCurrentFrame++ ;
		iRet = 1 ;
	}
	__finally
	{
	}
	return iRet ;
}
//===================================================================
bool  FCImage::__fooGifScanFile (BYTE * pStart, int iFileSize)
{
	bool				bRet = false ;
	BYTE			  * pCurr, * pEnd ;

	__try
	{
		if (pStart == NULL)
			__leave ;

		this->__fooGifInitInfo (iFileSize) ; // 初始化m_pGifInfo
		CopyMemory (m_pGifInfo->pStart, pStart, iFileSize) ;
		pStart = m_pGifInfo->pStart ;
		CopyMemory (&m_pGifInfo->byVersion, pStart + 3, 3) ; // Version
		pCurr = pStart + 10 ; // ==>屏幕描述信息
		pEnd = pStart + iFileSize ;

		if (*pCurr & 0x80) // 存在全局调色板
		{
			m_pGifInfo->wGolPalNum = 1 << ((*pCurr & 0x07) + 1) ;
			pCurr += m_pGifInfo->wGolPalNum * 3 ;
		}
		pCurr += 3 ;

		while (pCurr < pEnd)
			switch (*pCurr++)
			{
				case 0x21 :	// 4种扩充块
					switch (*pCurr++)
					{
						case 0xf9 : // GIF 图形控制扩充块
							pCurr++ ;
							m_pGifInfo->byTransFlag = *pCurr++ & 0x01 ; // 透明色标志
							m_pGifInfo->wDelayTime = (* (WORD*) pCurr) * 10 ;
							pCurr += 2 ;
							m_pGifInfo->byTransparencyIndex = *pCurr ;
							pCurr += 2 ;
							break ;
						case 0xfe : // GIF 注解说明控制块
						case 0x01 : // GIF 图形文本扩充块
						case 0xff : // GIF 应用程序扩充块
						default :
							while (*pCurr != 0)	// Skip sub block
								pCurr += *pCurr + 1 ;
							pCurr++ ; // Terminator '\0'
					}
					break ;
					
				case 0x2C :	// 图像描述块
					m_pGifInfo->pFrameIndexArray[++m_pGifInfo->wTotalFrame] = pCurr - pStart ;
					pCurr += 8 ;
					m_pGifInfo->byInterlace = *pCurr & 0x40 ; // 交错
					if (*pCurr & 0x80) // 是否有区域调色板
						pCurr += 3 * (1 << ((*pCurr & 0x07) + 1)) ;
					pCurr++ ;
					m_pGifInfo->byBitCount = *pCurr++ ; // Skip min-code length
					while (*pCurr != 0)	// Skip data sub block
						pCurr += *pCurr + 1 ;
					pCurr++ ; // Terminator '\0'
					break ;

				case 0x3B :	// End of file
					bRet = true ;
					__leave ; // 成功退出
				case 0x00 :
					break ;
				default :
					__leave ; // 错误
			}	// End of switch
	}
	__finally
	{
		if (!bRet)
			this->__fooGifFreeInfo () ;
	}
	return bRet ;
}
//===================================================================

⌨️ 快捷键说明

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