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

📄 gifdeclib.c

📁 GIF动画解码算法
💻 C
📖 第 1 页 / 共 4 页
字号:
#include "GIFDecLib.h"
#include "Key_drv.h"
#include "Stn_drv.h"
#include "nucleus.h"
#include "RsBmpInt.h"

//解码器函数原型为
//BOOL GIFDec(U8 *inFileBuf,
//				U32 nFileSize,
// 				U32 nLeftX,
//				U32 nTopY,
//				U32 nWidth,
// 				U32 nHeight,
// 				U32 nTimes)
//参数说明:
//inFileBuf		待解压GIF文件的缓冲区
//nFileSize		GIF文件的大小
//nLeftX		动画显示区的左上角横坐标(屏幕的物理坐标)。
//nTopY		动画显示区的左上角竖坐标(屏幕的物理坐标)。
//nWidth		动画显示区的宽,注意:nWidth <= 屏幕宽度。
//nHeight		动画显示区的高,注意:nHeight <= 屏幕的高度。
//nTimes		动画播放次数。
//
//返回:
//返回一个标识解码是否成功的BOOL类型的变量。

//底层依赖函数
//
//PutPixel (	U32 curX,
//			U32 curY,
//			U8	R,
//			U8	G,
//			U8	B)
//参数说明:
//curX		当前显示点的横坐标。
//CurY	当前显示点的竖坐标。
//R		当前象素的R值。
//G		当前象素的G值。
//B		当前象素的B值。

BOOL GIFDec(U8 *inFileBuf,
			U32 nFileSize,
			U32 nLeftX,
			U32 nTopY,
			U32 nWidth,
			U32 nHeight,
			U32 nTimes)
{
	TImage stImage;
	int nCurFrame;
	int i;
	U32 pass=0;
	BOOL isResized;
	BOOL isLarge=FALSE;
	
	stImage.m_pGIFLSDescriptor 	= NULL;
	stImage.m_pGIFHeader	   	= NULL;
	stImage.m_pPicture		   	= NULL;
	stImage.m_pRawData		   	= NULL;
	stImage.m_bIsInitialized   	= TRUE;
	stImage.m_bExitThread	   	= FALSE;
	stImage.m_bIsPlaying	   	= FALSE;
	stImage.m_bIsGIF		   	= FALSE;
	stImage.m_nGlobalCTSize    = 0;
	stImage.m_nCurrOffset	   	= 0;
	stImage.m_nCurrFrame	   	= 0;
	stImage.m_nDataSize 	   	= 0;
	stImage.m_PictureSize.cx 	= 0;
	stImage.m_PictureSize.cy 	= 0;	
	stImage.m_pRawData = (unsigned char*)inFileBuf;
	stImage.m_nDataSize = nFileSize;
	stImage.m_pGIFHeader = (TGIFHeader *)(stImage.m_pRawData);

	if ((memcmp(&stImage.m_pGIFHeader->m_cSignature,"GIF",3) != 0) &&
		((memcmp(&stImage.m_pGIFHeader->m_cVersion,"87a",3) != 0) ||
		 (memcmp(&stImage.m_pGIFHeader->m_cVersion,"89a",3) != 0))){
		// it's neither GIF87a nor GIF89a, do the default processing, release and clear image
		return FALSE;
	}
	

	
/*	if(!Load(&stImage,inFileBuf,fileSize,LeftX,TopY,nWidth,nHeight))
		isLarge = TRUE;
	if(!isLarge){
		InitImage(&stImage);
		if(!Play(&stImage,nLeftX,nTopY,nWidth,nHeight)){
			DestroyImage(&stImage);
			isLarge = TRUE;
		}
	}
	if(isLarge){ */
		isResized = FALSE;
		StnClearAll();
		WriteRect(nLeftX,nTopY,nWidth,nHeight,0x0F,0x0F,0x0F);
//		FillRect(0x0F,nLeftX,nTopY,nWidth,nHeight); 
//		while (KEY_OK != GetKey()){
		while(pass < nTimes){
			InitImage(&stImage);
			nCurFrame = 0;
			isResized = TRUE;		
			ResetDataPointer(&stImage); 		
			while(nCurFrame<stImage.m_nFrameCount){ 		
				if(!Large_GetNextGraphicBlock(&stImage,nWidth,nHeight)){
					NU_Deallocate_Memory(stImage.m_Frame.m_pRGB);
					return FALSE;
				}
				if(!Large_GIFFrameAdjust(&stImage,nCurFrame,nWidth,nHeight,&isResized)){
					NU_Deallocate_Memory(stImage.m_Frame.m_pRGB);
					return FALSE;
				}
//				if(!Large_GIFFrameCompress(&stImage,nCurFrame,nLeftX,nTopY,nWidth,nHeight,&isResized)){
//					NU_Deallocate_Memory(stImage.m_Frame.m_pRGB);
//					return FALSE;
//				}
				if(!Large_PlayFrame(&stImage,nCurFrame,nLeftX,nTopY,nWidth,nHeight)){
					NU_Deallocate_Memory(stImage.m_Frame.m_pRGB);
					return FALSE;
				}
				NU_Deallocate_Memory(stImage.m_Frame.m_pRGB);
				nCurFrame ++;
			}
			if(nCurFrame == 1)
				break;
			pass ++;
		}
		NU_Deallocate_Memory(stImage.m_Frame.m_pRGB);
		return TRUE;
//	}
}
BOOL InitImage(TImage *pImage)
{
	unsigned char	*pBkClr;
	UINT			nCurFrame = 0;
	int 			i;

	pImage->m_bIsGIF = TRUE;
	pImage->m_pGIFLSDescriptor = (TGIFLSDescriptor *)(pImage->m_pRawData + sizeof(TGIFHeader));

	if (GetPackedValueLSD(pImage->m_pGIFLSDescriptor,LSD_PACKED_GLOBALCT) == 1)
	{
		// calculate the globat color table size
		pImage->m_nGlobalCTSize = (int)(3* (1 << (GetPackedValueLSD(pImage->m_pGIFLSDescriptor,LSD_PACKED_GLOBALCTSIZE)+1)));
		pImage->m_nGlobalCTPos = 13;  // by yajun
		// get the background color if GCT is present
		pBkClr = pImage->m_pRawData + sizeof(TGIFHeader) + 
			sizeof(TGIFLSDescriptor) + 3*pImage->m_pGIFLSDescriptor->m_cBkIndex;
		pImage->m_clrBackground = RGB(pBkClr[0],pBkClr[1],pBkClr[2]);
		pImage->m_clrBackInex = pImage->m_pRawData[11] ;
	}

	// store the picture's size
	pImage->m_PictureSize.cx = pImage->m_pGIFLSDescriptor->m_wWidth;
	pImage->m_PictureSize.cy = pImage->m_pGIFLSDescriptor->m_wHeight;

	// determine frame count for this picture
	pImage->m_nFrameCount = 0;
	ResetDataPointer(pImage);
	while (SkipNextGraphicBlock(pImage))
		pImage->m_nFrameCount++;

	if (pImage->m_nFrameCount == 0) // it's an empty GIF!
	{
		pImage->m_pRawData = NULL; 
		return FALSE;
	}	
	return TRUE;
}

BOOL Large_PlayFrame(TImage *pImage,
			int nCurFrame,
			int LeftX,
			int TopY,
			int nWidth,
			int nHeight)
{
	long hmWidth;
	long hmHeight;
	int i,n;
	BYTE byBrush;
	int finish = 0;
		
	if (IsAnimatedGIF(pImage))
	{
		pImage->m_bIsPlaying = TRUE;	
		Large_DrawFrameRGB( pImage,nCurFrame,LeftX,TopY, nWidth,nHeight);
		NU_Sleep(pImage->m_Frame.m_controlExt.m_wDelayTime/10);
	} 
	else
	{		
		Large_SubDrawFrameRGB(pImage,nCurFrame, 0, 0,0,LeftX, TopY,nWidth,nHeight);
	}
	return TRUE;
}

int GetPackedValueCon(TGIFControlExt *pCon,
						  enum ControlExtValues Value)
{
	int nRet = (int)pCon->m_cPacked;
	switch (Value)
	{
	case GCX_PACKED_DISPOSAL:
		nRet = (nRet & 28) >> 2;
		break;

	case GCX_PACKED_USERINPUT:
		nRet = (nRet & 2) >> 1;
		break;

	case GCX_PACKED_TRANSPCOLOR:
		nRet &= 1;
		break;
	};

	return nRet;
}
int GetPackedValueLSD(TGIFLSDescriptor   *pLSD,
						  enum LSDPackedValues Value)
{
	int nRet = (int)pLSD->m_cPacked;

	switch (Value)
	{
	case LSD_PACKED_GLOBALCT:
		nRet = nRet >> 7;
		break;

	case LSD_PACKED_CRESOLUTION:
		nRet = ((nRet & 0x70) >> 4) + 1;
		break;

	case LSD_PACKED_SORT:
		nRet = (nRet & 8) >> 3;
		break;

	case LSD_PACKED_GLOBALCTSIZE:
		nRet &= 7;
		break;
	};

	return nRet;
}

int GetPackedValueImD(TGIFImageDescriptor *pImd,
	                      enum IDPackedValues Value)
{
	int nRet = (int)pImd->m_cPacked;

	switch (Value)
	{
	case ID_PACKED_LOCALCT:
		nRet >>= 7;
		break;

	case ID_PACKED_INTERLACE:
		nRet = ((nRet & 0x40) >> 6);
		break;

	case ID_PACKED_SORT:
		nRet = (nRet & 0x20) >> 5;
		break;

	case ID_PACKED_LOCALCTSIZE:
		nRet &= 7;
		break;
	};

	return nRet;
}

void ResetDataPointer(TImage *pImage)
{
	// skip header and logical screen descriptor
	pImage->m_nCurrOffset = sizeof(TGIFHeader)+sizeof(TGIFLSDescriptor)+pImage->m_nGlobalCTSize;
}
BOOL SkipNextGraphicBlock(TImage *pImage)
{
	enum GIFBlockTypes nBlock;
	
	if (!pImage->m_pRawData)
		return FALSE;

	// GIF header + LSDescriptor [+ GCT] [+ Control block] + Data
	nBlock = GetNextBlock(pImage);

	while ((nBlock != BLOCK_CONTROLEXT) &&(nBlock != BLOCK_IMAGE) &&(nBlock != BLOCK_PLAINTEXT) &&(nBlock != BLOCK_UNKNOWN) &&(nBlock != BLOCK_TRAILER) )
	{
		if (!SkipNextBlock(pImage)) 
			return NULL;
		nBlock = GetNextBlock(pImage);
	};

	if ((nBlock == BLOCK_UNKNOWN) ||(nBlock == BLOCK_TRAILER))
		return FALSE;

	// it's either a control ext.block, an image or a plain text

	if (GetNextBlockLen(pImage) <= 0) 
		return FALSE;

	if (nBlock == BLOCK_CONTROLEXT)
	{
		if (!SkipNextBlock(pImage)) 
			return FALSE;
		nBlock = GetNextBlock(pImage);

		// skip everything until we meet an image block or a plain-text block
		while ((nBlock != BLOCK_IMAGE) &&(nBlock != BLOCK_PLAINTEXT) &&(nBlock != BLOCK_UNKNOWN) && (nBlock != BLOCK_TRAILER) )
		{
			if (!SkipNextBlock(pImage)) 
				return NULL;
			nBlock = GetNextBlock(pImage);
		};

		if ((nBlock == BLOCK_UNKNOWN) ||(nBlock == BLOCK_TRAILER))
			return FALSE;
	}
	// skip the found data block (image or plain-text)
	if (!SkipNextBlock(pImage)) 
		return FALSE;
	return TRUE;
}
BOOL Large_GetNextGraphicBlock(TImage *pImage,
							 int nWidth,
							 int nHeight)
{
	enum GIFBlockTypes nBlock;
	int nStart ;	
	int nBlockLen; 
	TGIFControlExt *pControl;
	TGIFImageDescriptor *pImgDscpt ;
	HGLOBAL hGlobal;
	int nOffset = 0; 
	unsigned char *pGlobal;

	TFrame *pFrame;
	pFrame = (TFrame *)(&(pImage->m_Frame));
	
	if (!pImage->m_pRawData) 
		return NULL;
	// GIF header + LSDescriptor [+ GCT] [+ Control block] + Data
	pFrame->m_nDisposal = 0;
	nBlock = GetNextBlock(pImage);

	while ((nBlock != BLOCK_CONTROLEXT) &&(nBlock != BLOCK_IMAGE) &&(nBlock != BLOCK_PLAINTEXT) &&(nBlock != BLOCK_UNKNOWN) &&(nBlock != BLOCK_TRAILER))
	{
		if (!SkipNextBlock(pImage)) 
			return NULL;
		nBlock = GetNextBlock(pImage);
	};
	if ((nBlock == BLOCK_UNKNOWN) ||(nBlock == BLOCK_TRAILER))
		return NULL;

	// it's either a controlext, an image or a plain text block
	nStart = pImage->m_nCurrOffset;
	nBlockLen = GetNextBlockLen(pImage);

	if (nBlockLen <= 0) 
		return NULL;

	if (nBlock == BLOCK_CONTROLEXT)
	{
		// get the following data
		pControl = (TGIFControlExt *)(&pImage->m_pRawData[pImage->m_nCurrOffset]);
		// store delay time
		pFrame->m_nDelay = pControl->m_wDelayTime;
		// store disposal method
		pFrame->m_nDisposal = GetPackedValueCon(pControl,GCX_PACKED_DISPOSAL);

		if (!SkipNextBlock(pImage)) 
			return NULL;
		nBlock = GetNextBlock(pImage);
		
		// skip everything until we find data to display 
		// (image block or plain-text block)
		
		while ((nBlock != BLOCK_IMAGE) &&(nBlock != BLOCK_PLAINTEXT) &&(nBlock != BLOCK_UNKNOWN) &&(nBlock != BLOCK_TRAILER))
		{
			if (!SkipNextBlock(pImage)) 
				return NULL;
			nBlock = GetNextBlock(pImage);
			nBlockLen += GetNextBlockLen(pImage);
		};

		if ((nBlock == BLOCK_UNKNOWN) || (nBlock == BLOCK_TRAILER))
			return NULL;
		nBlockLen += GetNextBlockLen(pImage);
	}
	else
		pFrame->m_nDelay = -1; // to indicate that there was no delay value

	if (nBlock == BLOCK_IMAGE)
	{
		// store size and offsets
		pImgDscpt = (TGIFImageDescriptor *) (&pImage->m_pRawData[pImage->m_nCurrOffset]);
		pFrame->m_frameSize.cx= pImgDscpt->m_wWidth;
		pFrame->m_frameSize.cy = pImgDscpt->m_wHeight;
		pFrame->m_frameOffset.cx = pImgDscpt->m_wLeftPos;
		pFrame->m_frameOffset.cy = pImgDscpt->m_wTopPos;
	}

	if (!SkipNextBlock(pImage)) 
		return NULL;
	if(!FrameDec(pImage,&((pImage->m_pRawData)[nStart]),nStart,nBlockLen,pFrame,nWidth,nHeight))
		return FALSE;
	return TRUE;
}

UINT GetSubBlocksLen(TImage *pImage,
	                     UINT nStartingOffset) 
{
	UINT nRet = 0;
	UINT nCurOffset = nStartingOffset;
	
	while (pImage->m_pRawData[nCurOffset] != 0)
	{
		nRet += pImage->m_pRawData[nCurOffset]+1;
		nCurOffset += pImage->m_pRawData[nCurOffset]+1;
	}
	return nRet+1;
}
enum GIFBlockTypes GetNextBlock(TImage *pImage) 
{
	switch(pImage->m_pRawData[pImage->m_nCurrOffset])
	{
	case 0x21:
	// extension block
		switch(pImage->m_pRawData[pImage->m_nCurrOffset+1])
		{
		case 0x01:
		// plain text extension

⌨️ 快捷键说明

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