📄 gifdeclib.c
字号:
#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 + -