630 lines
17 KiB
C
630 lines
17 KiB
C
|
#include "main.h"
|
|||
|
#include "ff.h"
|
|||
|
#include "gif.h"
|
|||
|
//////////////////////////////////////////////////////////////////////////////////
|
|||
|
//本程序只供学习使用,未经作者许可,不得用于其它任何用途
|
|||
|
//ALIENTEK STM32开发板
|
|||
|
//图片解码 驱动代码-gif解码部分
|
|||
|
//正点原子@ALIENTEK
|
|||
|
//技术论坛:www.openedv.com
|
|||
|
//创建日期:2016/1/7
|
|||
|
//版本:V1.0
|
|||
|
//版权所有,盗版必究。
|
|||
|
//Copyright(C) 广州市星翼电子科技有限公司 2014-2024
|
|||
|
//All rights reserved
|
|||
|
//********************************************************************************
|
|||
|
//升级说明
|
|||
|
//无
|
|||
|
//////////////////////////////////////////////////////////////////////////////////
|
|||
|
|
|||
|
|
|||
|
struct _pic_phy
|
|||
|
{
|
|||
|
void (*draw_hline)(int x,int y,int len,u16 color);
|
|||
|
void (*draw_point)(int x,int y,u16 color);
|
|||
|
void (*fill)(int sx,int xy,int ex,int ey,u16 color);
|
|||
|
|
|||
|
};
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
static GIF_DecodeStruct *g_decode=0;
|
|||
|
static void draw_hline (int x,int y,int len,u16 color)
|
|||
|
{
|
|||
|
if (g_decode&&g_decode->frameNumber&&g_decode->frame[g_decode->frameNumber-1])
|
|||
|
{
|
|||
|
if (x>=0&&x<g_decode->x_size)
|
|||
|
{
|
|||
|
if (x+len>g_decode->x_size) len=g_decode->x_size-x;
|
|||
|
int ds=y*g_decode->x_size+x;
|
|||
|
for (int i=0;i<len;i++)
|
|||
|
(g_decode->frame[g_decode->frameNumber-1])[ds+i]=color;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
static void draw_point (int x,int y,u16 color)
|
|||
|
{
|
|||
|
if (g_decode&&g_decode->frameNumber&&g_decode->frame[g_decode->frameNumber-1])
|
|||
|
{
|
|||
|
int ds=y*g_decode->x_size+x;
|
|||
|
(g_decode->frame[g_decode->frameNumber-1])[ds]=color;
|
|||
|
}
|
|||
|
}
|
|||
|
static void fill(int sx,int sy,int ex,int ey,u16 color)
|
|||
|
{
|
|||
|
for (int i=0;i<ey-sy+1;i++)
|
|||
|
{
|
|||
|
draw_hline (sx,sy+i,ex-sx+1,color);
|
|||
|
}
|
|||
|
}
|
|||
|
static struct _pic_phy pic_phy ={
|
|||
|
.draw_hline=draw_hline,
|
|||
|
.draw_point=draw_point,
|
|||
|
.fill=fill,
|
|||
|
};
|
|||
|
|
|||
|
|
|||
|
|
|||
|
const u16 _aMaskTbl[16] =
|
|||
|
{
|
|||
|
0x0000, 0x0001, 0x0003, 0x0007,
|
|||
|
0x000f, 0x001f, 0x003f, 0x007f,
|
|||
|
0x00ff, 0x01ff, 0x03ff, 0x07ff,
|
|||
|
0x0fff, 0x1fff, 0x3fff, 0x7fff,
|
|||
|
};
|
|||
|
const u8 _aInterlaceOffset[]={8,8,4,2};
|
|||
|
const u8 _aInterlaceYPos []={0,4,2,1};
|
|||
|
|
|||
|
u8 gifdecoding=0;//标记GIF正在解码.
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
//检测GIF头
|
|||
|
//返回值:0,是GIF89a/87a;非零,非GIF89a/87a
|
|||
|
u8 gif_check_head(FIL *file)
|
|||
|
{
|
|||
|
u8 gifversion[6];
|
|||
|
u32 readed;
|
|||
|
u8 res;
|
|||
|
res=f_read(file,gifversion,6,(UINT*)&readed);
|
|||
|
if(res)return 1;
|
|||
|
if((gifversion[0]!='G')||(gifversion[1]!='I')||(gifversion[2]!='F')||
|
|||
|
(gifversion[3]!='8')||((gifversion[4]!='7')&&(gifversion[4]!='9'))||
|
|||
|
(gifversion[5]!='a'))return 2;
|
|||
|
else return 0;
|
|||
|
}
|
|||
|
//将RGB888转为RGB565
|
|||
|
//ctb:RGB888颜色数组首地址.
|
|||
|
//返回值:RGB565颜色.
|
|||
|
u16 gif_getrgb565(u8 *ctb)
|
|||
|
{
|
|||
|
u16 r,g,b;
|
|||
|
r=(ctb[0]>>3)&0X1F;
|
|||
|
g=(ctb[1]>>2)&0X3F;
|
|||
|
b=(ctb[2]>>3)&0X1F;
|
|||
|
return b+(g<<5)+(r<<11);
|
|||
|
}
|
|||
|
//读取颜色表
|
|||
|
//file:文件;
|
|||
|
//gif:gif信息;
|
|||
|
//num:tbl大小.
|
|||
|
//返回值:0,OK;其他,失败;
|
|||
|
u8 gif_readcolortbl(FIL *file,gif89a * gif,u16 num)
|
|||
|
{
|
|||
|
u8 rgb[3];
|
|||
|
u16 t;
|
|||
|
u8 res;
|
|||
|
u32 readed;
|
|||
|
for(t=0;t<num;t++)
|
|||
|
{
|
|||
|
res=f_read(file,rgb,3,(UINT*)&readed);
|
|||
|
if(res)return 1;//读错误
|
|||
|
gif->colortbl[t]=gif_getrgb565(rgb);
|
|||
|
}
|
|||
|
return 0;
|
|||
|
}
|
|||
|
//得到逻辑屏幕描述,图像尺寸等
|
|||
|
//file:文件;
|
|||
|
//gif:gif信息;
|
|||
|
//返回值:0,OK;其他,失败;
|
|||
|
u8 gif_getinfo(FIL *file,gif89a * gif)
|
|||
|
{
|
|||
|
u32 readed;
|
|||
|
u8 res;
|
|||
|
res=f_read(file,(u8*)&gif->gifLSD,7,(UINT*)&readed);
|
|||
|
if(res)return 1;
|
|||
|
if(gif->gifLSD.flag&0x80)//存在全局颜色表
|
|||
|
{
|
|||
|
gif->numcolors=2<<(gif->gifLSD.flag&0x07);//得到颜色表大小
|
|||
|
if(gif_readcolortbl(file,gif,gif->numcolors))return 1;//读错误
|
|||
|
}
|
|||
|
return 0;
|
|||
|
}
|
|||
|
//保存全局颜色表
|
|||
|
//gif:gif信息;
|
|||
|
void gif_savegctbl(gif89a* gif)
|
|||
|
{
|
|||
|
u16 i=0;
|
|||
|
for(i=0;i<256;i++)gif->bkpcolortbl[i]=gif->colortbl[i];//保存全局颜色.
|
|||
|
}
|
|||
|
//恢复全局颜色表
|
|||
|
//gif:gif信息;
|
|||
|
void gif_recovergctbl(gif89a* gif)
|
|||
|
{
|
|||
|
u16 i=0;
|
|||
|
for(i=0;i<256;i++)gif->colortbl[i]=gif->bkpcolortbl[i];//恢复全局颜色.
|
|||
|
}
|
|||
|
|
|||
|
//初始化LZW相关参数
|
|||
|
//gif:gif信息;
|
|||
|
//codesize:lzw码长度
|
|||
|
void gif_initlzw(gif89a* gif,u8 codesize)
|
|||
|
{
|
|||
|
mymemset((u8 *)gif->lzw, 0, sizeof(LZW_INFO));
|
|||
|
gif->lzw->SetCodeSize = codesize;
|
|||
|
gif->lzw->CodeSize = codesize + 1;
|
|||
|
gif->lzw->ClearCode = (1 << codesize);
|
|||
|
gif->lzw->EndCode = (1 << codesize) + 1;
|
|||
|
gif->lzw->MaxCode = (1 << codesize) + 2;
|
|||
|
gif->lzw->MaxCodeSize = (1 << codesize) << 1;
|
|||
|
gif->lzw->ReturnClear = 1;
|
|||
|
gif->lzw->LastByte = 2;
|
|||
|
gif->lzw->sp = gif->lzw->aDecompBuffer;
|
|||
|
}
|
|||
|
|
|||
|
//读取一个数据块
|
|||
|
//gfile:gif文件;
|
|||
|
//buf:数据缓存区
|
|||
|
//maxnum:最大读写数据限制
|
|||
|
u16 gif_getdatablock(FIL *gfile,u8 *buf,u16 maxnum)
|
|||
|
{
|
|||
|
u8 cnt;
|
|||
|
u32 readed;
|
|||
|
u32 fpos;
|
|||
|
f_read(gfile,&cnt,1,(UINT*)&readed);//得到LZW长度
|
|||
|
if(cnt)
|
|||
|
{
|
|||
|
if (buf)//需要读取
|
|||
|
{
|
|||
|
if(cnt>maxnum)
|
|||
|
{
|
|||
|
fpos=f_tell(gfile);
|
|||
|
f_lseek(gfile,fpos+cnt);//跳过
|
|||
|
return cnt;//直接不读
|
|||
|
}
|
|||
|
f_read(gfile,buf,cnt,(UINT*)&readed);//得到LZW长度
|
|||
|
}else //直接跳过
|
|||
|
{
|
|||
|
fpos=f_tell(gfile);
|
|||
|
f_lseek(gfile,fpos+cnt);//跳过
|
|||
|
}
|
|||
|
}
|
|||
|
return cnt;
|
|||
|
}
|
|||
|
//ReadExtension
|
|||
|
//Purpose:
|
|||
|
//Reads an extension block. One extension block can consist of several data blocks.
|
|||
|
//If an unknown extension block occures, the routine failes.
|
|||
|
//返回值:0,成功;
|
|||
|
// 其他,失败
|
|||
|
u8 gif_readextension(FIL *gfile,gif89a* gif, int *pTransIndex,u8 *pDisposal)
|
|||
|
{
|
|||
|
u8 temp;
|
|||
|
u32 readed;
|
|||
|
u8 buf[4];
|
|||
|
f_read(gfile,&temp,1,(UINT*)&readed);//得到长度
|
|||
|
switch(temp)
|
|||
|
{
|
|||
|
case GIF_PLAINTEXT:
|
|||
|
case GIF_APPLICATION:
|
|||
|
case GIF_COMMENT:
|
|||
|
while(gif_getdatablock(gfile,0,256)>0); //获取数据块
|
|||
|
return 0;
|
|||
|
case GIF_GRAPHICCTL://图形控制扩展块
|
|||
|
if(gif_getdatablock(gfile,buf,4)!=4)return 1; //图形控制扩展块的长度必须为4
|
|||
|
gif->delay=(buf[2]<<8)|buf[1]; //得到延时
|
|||
|
*pDisposal=(buf[0]>>2)&0x7; //得到处理方法
|
|||
|
if((buf[0]&0x1)!=0)*pTransIndex=buf[3]; //透明色表
|
|||
|
f_read(gfile,&temp,1,(UINT*)&readed); //得到LZW长度
|
|||
|
if(temp!=0)return 1; //读取数据块结束符错误.
|
|||
|
return 0;
|
|||
|
}
|
|||
|
return 1;//错误的数据
|
|||
|
}
|
|||
|
|
|||
|
//从LZW缓存中得到下一个LZW码,每个码包含12位
|
|||
|
//返回值:<0,错误.
|
|||
|
// 其他,正常.
|
|||
|
int gif_getnextcode(FIL *gfile,gif89a* gif)
|
|||
|
{
|
|||
|
int i,j,End;
|
|||
|
long Result;
|
|||
|
if(gif->lzw->ReturnClear)
|
|||
|
{
|
|||
|
//The first code should be a clearcode.
|
|||
|
gif->lzw->ReturnClear=0;
|
|||
|
return gif->lzw->ClearCode;
|
|||
|
}
|
|||
|
End=gif->lzw->CurBit+gif->lzw->CodeSize;
|
|||
|
if(End>=gif->lzw->LastBit)
|
|||
|
{
|
|||
|
int Count;
|
|||
|
if(gif->lzw->GetDone)return-1;//Error
|
|||
|
gif->lzw->aBuffer[0]=gif->lzw->aBuffer[gif->lzw->LastByte-2];
|
|||
|
gif->lzw->aBuffer[1]=gif->lzw->aBuffer[gif->lzw->LastByte-1];
|
|||
|
if((Count=gif_getdatablock(gfile,&gif->lzw->aBuffer[2],300))==0)gif->lzw->GetDone=1;
|
|||
|
if(Count<0)return -1;//Error
|
|||
|
gif->lzw->LastByte=2+Count;
|
|||
|
gif->lzw->CurBit=(gif->lzw->CurBit-gif->lzw->LastBit)+16;
|
|||
|
gif->lzw->LastBit=(2+Count)*8;
|
|||
|
End=gif->lzw->CurBit+gif->lzw->CodeSize;
|
|||
|
}
|
|||
|
j=End>>3;
|
|||
|
i=gif->lzw->CurBit>>3;
|
|||
|
if(i==j)Result=(long)gif->lzw->aBuffer[i];
|
|||
|
else if(i+1==j)Result=(long)gif->lzw->aBuffer[i]|((long)gif->lzw->aBuffer[i+1]<<8);
|
|||
|
else Result=(long)gif->lzw->aBuffer[i]|((long)gif->lzw->aBuffer[i+1]<<8)|((long)gif->lzw->aBuffer[i+2]<<16);
|
|||
|
Result=(Result>>(gif->lzw->CurBit&0x7))&_aMaskTbl[gif->lzw->CodeSize];
|
|||
|
gif->lzw->CurBit+=gif->lzw->CodeSize;
|
|||
|
return(int)Result;
|
|||
|
}
|
|||
|
//得到LZW的下一个码
|
|||
|
//返回值:<0,错误(-1,不成功;-2,读到结束符了)
|
|||
|
// >=0,OK.(LZW的第一个码)
|
|||
|
int gif_getnextbyte(FIL *gfile,gif89a* gif)
|
|||
|
{
|
|||
|
int i,Code,Incode;
|
|||
|
while((Code=gif_getnextcode(gfile,gif))>=0)
|
|||
|
{
|
|||
|
if(Code==gif->lzw->ClearCode)
|
|||
|
{
|
|||
|
//Corrupt GIFs can make this happen
|
|||
|
if(gif->lzw->ClearCode>=(1<<MAX_NUM_LWZ_BITS))return -1;//Error
|
|||
|
//Clear the tables
|
|||
|
mymemset((u8*)gif->lzw->aCode,0,sizeof(gif->lzw->aCode));
|
|||
|
for(i=0;i<gif->lzw->ClearCode;++i)gif->lzw->aPrefix[i]=i;
|
|||
|
//Calculate the'special codes' independence of the initial code size
|
|||
|
//and initialize the stack pointer
|
|||
|
gif->lzw->CodeSize=gif->lzw->SetCodeSize+1;
|
|||
|
gif->lzw->MaxCodeSize=gif->lzw->ClearCode<<1;
|
|||
|
gif->lzw->MaxCode=gif->lzw->ClearCode+2;
|
|||
|
gif->lzw->sp=gif->lzw->aDecompBuffer;
|
|||
|
//Read the first code from the stack after clear ingand initializing*/
|
|||
|
do
|
|||
|
{
|
|||
|
gif->lzw->FirstCode=gif_getnextcode(gfile,gif);
|
|||
|
}while(gif->lzw->FirstCode==gif->lzw->ClearCode);
|
|||
|
gif->lzw->OldCode=gif->lzw->FirstCode;
|
|||
|
return gif->lzw->FirstCode;
|
|||
|
}
|
|||
|
if(Code==gif->lzw->EndCode)return -2;//End code
|
|||
|
Incode=Code;
|
|||
|
if(Code>=gif->lzw->MaxCode)
|
|||
|
{
|
|||
|
*(gif->lzw->sp)++=gif->lzw->FirstCode;
|
|||
|
Code=gif->lzw->OldCode;
|
|||
|
}
|
|||
|
while(Code>=gif->lzw->ClearCode)
|
|||
|
{
|
|||
|
*(gif->lzw->sp)++=gif->lzw->aPrefix[Code];
|
|||
|
if(Code==gif->lzw->aCode[Code])return Code;
|
|||
|
if((gif->lzw->sp-gif->lzw->aDecompBuffer)>=sizeof(gif->lzw->aDecompBuffer))return Code;
|
|||
|
Code=gif->lzw->aCode[Code];
|
|||
|
}
|
|||
|
*(gif->lzw->sp)++=gif->lzw->FirstCode=gif->lzw->aPrefix[Code];
|
|||
|
if((Code=gif->lzw->MaxCode)<(1<<MAX_NUM_LWZ_BITS))
|
|||
|
{
|
|||
|
gif->lzw->aCode[Code]=gif->lzw->OldCode;
|
|||
|
gif->lzw->aPrefix[Code]=gif->lzw->FirstCode;
|
|||
|
++gif->lzw->MaxCode;
|
|||
|
if((gif->lzw->MaxCode>=gif->lzw->MaxCodeSize)&&(gif->lzw->MaxCodeSize<(1<<MAX_NUM_LWZ_BITS)))
|
|||
|
{
|
|||
|
gif->lzw->MaxCodeSize<<=1;
|
|||
|
++gif->lzw->CodeSize;
|
|||
|
}
|
|||
|
}
|
|||
|
gif->lzw->OldCode=Incode;
|
|||
|
if(gif->lzw->sp>gif->lzw->aDecompBuffer)return *--(gif->lzw->sp);
|
|||
|
}
|
|||
|
return Code;
|
|||
|
}
|
|||
|
//DispGIFImage
|
|||
|
//Purpose:
|
|||
|
// This routine draws a GIF image from the current pointer which should point to a
|
|||
|
// valid GIF data block. The size of the desired image is given in the image descriptor.
|
|||
|
//Return value:
|
|||
|
// 0 if succeed
|
|||
|
// 1 if not succeed
|
|||
|
//Parameters:
|
|||
|
// pDescriptor - Points to a IMAGE_DESCRIPTOR structure, which contains infos about size, colors and interlacing.
|
|||
|
// x0, y0 - Obvious.
|
|||
|
// Transparency - Color index which should be treated as transparent.
|
|||
|
// Disposal - Contains the disposal method of the previous image. If Disposal == 2, the transparent pixels
|
|||
|
// of the image are rendered with the background color.
|
|||
|
u8 gif_dispimage(FIL *gfile,gif89a* gif,u16 x0,u16 y0,int Transparency, u8 Disposal)
|
|||
|
{
|
|||
|
u32 readed;
|
|||
|
u8 lzwlen;
|
|||
|
int Index,OldIndex,XPos,YPos,YCnt,Pass,Interlace,XEnd;
|
|||
|
int Width,Height,Cnt,ColorIndex;
|
|||
|
u16 bkcolor;
|
|||
|
u16 *pTrans;
|
|||
|
|
|||
|
Width=gif->gifISD.width;
|
|||
|
Height=gif->gifISD.height;
|
|||
|
XEnd=Width+x0-1;
|
|||
|
bkcolor=gif->colortbl[gif->gifLSD.bkcindex];
|
|||
|
pTrans=(u16*)gif->colortbl;
|
|||
|
f_read(gfile,&lzwlen,1,(UINT*)&readed);//得到LZW长度
|
|||
|
gif_initlzw(gif,lzwlen);//Initialize the LZW stack with the LZW code size
|
|||
|
Interlace=gif->gifISD.flag&0x40;//是否交织编码
|
|||
|
for(YCnt=0,YPos=y0,Pass=0;YCnt<Height;YCnt++)
|
|||
|
{
|
|||
|
Cnt=0;
|
|||
|
OldIndex=-1;
|
|||
|
for(XPos=x0;XPos<=XEnd;XPos++)
|
|||
|
{
|
|||
|
if(gif->lzw->sp>gif->lzw->aDecompBuffer)Index=*--(gif->lzw->sp);
|
|||
|
else Index=gif_getnextbyte(gfile,gif);
|
|||
|
if(Index==-2)return 0;//Endcode
|
|||
|
if((Index<0)||(Index>=gif->numcolors))
|
|||
|
{
|
|||
|
//IfIndex out of legal range stop decompressing
|
|||
|
return 1;//Error
|
|||
|
}
|
|||
|
//If current index equals old index increment counter
|
|||
|
if((Index==OldIndex)&&(XPos<=XEnd))Cnt++;
|
|||
|
else
|
|||
|
{
|
|||
|
if(Cnt)
|
|||
|
{
|
|||
|
if(OldIndex!=Transparency)
|
|||
|
{
|
|||
|
pic_phy.draw_hline(XPos-Cnt-1,YPos,Cnt+1,*(pTrans+OldIndex));
|
|||
|
}else if(Disposal==2)
|
|||
|
{
|
|||
|
pic_phy.draw_hline(XPos-Cnt-1,YPos,Cnt+1,bkcolor);
|
|||
|
}
|
|||
|
Cnt=0;
|
|||
|
}else
|
|||
|
{
|
|||
|
if(OldIndex>=0)
|
|||
|
{
|
|||
|
if(OldIndex!=Transparency)pic_phy.draw_point(XPos-1,YPos,*(pTrans+OldIndex));
|
|||
|
else if(Disposal==2)pic_phy.draw_point(XPos-1,YPos,bkcolor);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
OldIndex=Index;
|
|||
|
}
|
|||
|
if((OldIndex!=Transparency)||(Disposal==2))
|
|||
|
{
|
|||
|
if(OldIndex!=Transparency)ColorIndex=*(pTrans+OldIndex);
|
|||
|
else ColorIndex=bkcolor;
|
|||
|
if(Cnt)
|
|||
|
{
|
|||
|
pic_phy.draw_hline(XPos-Cnt-1,YPos,Cnt+1,ColorIndex);
|
|||
|
}else pic_phy.draw_point(XEnd,YPos,ColorIndex);
|
|||
|
}
|
|||
|
//Adjust YPos if image is interlaced
|
|||
|
if(Interlace)//交织编码
|
|||
|
{
|
|||
|
YPos+=_aInterlaceOffset[Pass];
|
|||
|
if((YPos-y0)>=Height)
|
|||
|
{
|
|||
|
++Pass;
|
|||
|
YPos=_aInterlaceYPos[Pass]+y0;
|
|||
|
}
|
|||
|
}else YPos++;
|
|||
|
}
|
|||
|
return 0;
|
|||
|
}
|
|||
|
//恢复成背景色
|
|||
|
//x,y:坐标
|
|||
|
//gif:gif信息.
|
|||
|
//pimge:图像描述块信息
|
|||
|
void gif_clear2bkcolor(u16 x,u16 y,gif89a* gif,ImageScreenDescriptor pimge)
|
|||
|
{
|
|||
|
u16 x0,y0,x1,y1;
|
|||
|
u16 color=gif->colortbl[gif->gifLSD.bkcindex];
|
|||
|
if(pimge.width==0||pimge.height==0)return;//直接不用清除了,原来没有图像!!
|
|||
|
if(gif->gifISD.yoff>pimge.yoff)
|
|||
|
{
|
|||
|
x0=x+pimge.xoff;
|
|||
|
y0=y+pimge.yoff;
|
|||
|
x1=x+pimge.xoff+pimge.width-1;;
|
|||
|
y1=y+gif->gifISD.yoff-1;
|
|||
|
if(x0<x1&&y0<y1&&x1<320&&y1<320)pic_phy.fill(x0,y0,x1,y1,color); //设定xy,的范围不能太大.
|
|||
|
}
|
|||
|
if(gif->gifISD.xoff>pimge.xoff)
|
|||
|
{
|
|||
|
x0=x+pimge.xoff;
|
|||
|
y0=y+pimge.yoff;
|
|||
|
x1=x+gif->gifISD.xoff-1;;
|
|||
|
y1=y+pimge.yoff+pimge.height-1;
|
|||
|
if(x0<x1&&y0<y1&&x1<320&&y1<320)pic_phy.fill(x0,y0,x1,y1,color);
|
|||
|
}
|
|||
|
if((gif->gifISD.yoff+gif->gifISD.height)<(pimge.yoff+pimge.height))
|
|||
|
{
|
|||
|
x0=x+pimge.xoff;
|
|||
|
y0=y+gif->gifISD.yoff+gif->gifISD.height-1;
|
|||
|
x1=x+pimge.xoff+pimge.width-1;;
|
|||
|
y1=y+pimge.yoff+pimge.height-1;
|
|||
|
if(x0<x1&&y0<y1&&x1<320&&y1<320)pic_phy.fill(x0,y0,x1,y1,color);
|
|||
|
}
|
|||
|
if((gif->gifISD.xoff+gif->gifISD.width)<(pimge.xoff+pimge.width))
|
|||
|
{
|
|||
|
x0=x+gif->gifISD.xoff+gif->gifISD.width-1;
|
|||
|
y0=y+pimge.yoff;
|
|||
|
x1=x+pimge.xoff+pimge.width-1;;
|
|||
|
y1=y+pimge.yoff+pimge.height-1;
|
|||
|
if(x0<x1&&y0<y1&&x1<320&&y1<320)pic_phy.fill(x0,y0,x1,y1,color);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
//画GIF图像的一帧
|
|||
|
//gfile:gif文件.
|
|||
|
//x0,y0:开始显示的坐标
|
|||
|
u8 gif_drawimage(FIL *gfile,gif89a* gif,u16 x0,u16 y0)
|
|||
|
{
|
|||
|
u32 readed;
|
|||
|
u8 res,temp;
|
|||
|
u16 numcolors;
|
|||
|
ImageScreenDescriptor previmg;
|
|||
|
|
|||
|
u8 Disposal;
|
|||
|
int TransIndex;
|
|||
|
u8 Introducer;
|
|||
|
TransIndex=-1;
|
|||
|
do
|
|||
|
{
|
|||
|
res=f_read(gfile,&Introducer,1,(UINT*)&readed);//读取一个字节
|
|||
|
if(res)return 1;
|
|||
|
switch(Introducer)
|
|||
|
{
|
|||
|
case GIF_INTRO_IMAGE://图像描述
|
|||
|
previmg.xoff=gif->gifISD.xoff;
|
|||
|
previmg.yoff=gif->gifISD.yoff;
|
|||
|
previmg.width=gif->gifISD.width;
|
|||
|
previmg.height=gif->gifISD.height;
|
|||
|
|
|||
|
res=f_read(gfile,(u8*)&gif->gifISD,9,(UINT*)&readed);//读取一个字节
|
|||
|
if(res)return 1;
|
|||
|
if(gif->gifISD.flag&0x80)//存在局部颜色表
|
|||
|
{
|
|||
|
gif_savegctbl(gif);//保存全局颜色表
|
|||
|
numcolors=2<<(gif->gifISD.flag&0X07);//得到局部颜色表大小
|
|||
|
if(gif_readcolortbl(gfile,gif,numcolors))return 1;//读错误
|
|||
|
}
|
|||
|
if(Disposal==2)gif_clear2bkcolor(x0,y0,gif,previmg);
|
|||
|
gif_dispimage(gfile,gif,x0+gif->gifISD.xoff,y0+gif->gifISD.yoff,TransIndex,Disposal);
|
|||
|
while(1)
|
|||
|
{
|
|||
|
f_read(gfile,&temp,1,(UINT*)&readed);//读取一个字节
|
|||
|
if(temp==0)break;
|
|||
|
readed=f_tell(gfile);//还存在块.
|
|||
|
if(f_lseek(gfile,readed+temp))break;//继续向后偏移
|
|||
|
}
|
|||
|
if(temp!=0)return 1;//Error
|
|||
|
return 0;
|
|||
|
case GIF_INTRO_TERMINATOR://得到结束符了
|
|||
|
return 2;//代表图像解码完成了.
|
|||
|
case GIF_INTRO_EXTENSION:
|
|||
|
//Read image extension*/
|
|||
|
res=gif_readextension(gfile,gif,&TransIndex,&Disposal);//读取图像扩展块消息
|
|||
|
if(res)return 1;
|
|||
|
break;
|
|||
|
default:
|
|||
|
return 1;
|
|||
|
}
|
|||
|
}while(Introducer!=GIF_INTRO_TERMINATOR);//读到结束符了
|
|||
|
return 0;
|
|||
|
}
|
|||
|
|
|||
|
//退出当前解码.
|
|||
|
void gif_quit(void)
|
|||
|
{
|
|||
|
gifdecoding=0;
|
|||
|
}
|
|||
|
|
|||
|
//解码一个gif文件
|
|||
|
//t,解码使用的结构体指针,将在此函数申请内存空间
|
|||
|
//filename:带路径的gif文件名字
|
|||
|
int GIF_Decode(GIF_DecodeStruct *gif,const u8 *filename)
|
|||
|
{
|
|||
|
u16 x;u16 y;u16 width;u16 height;
|
|||
|
u8 res=0;
|
|||
|
u16 dtime=0;//解码延时
|
|||
|
gif89a *mygif89a;
|
|||
|
FIL *gfile;
|
|||
|
|
|||
|
// GIF_DecodeStructFree(g_decode);
|
|||
|
// g_decode=mymalloc (sizeof (GIF_DecodeStruct));
|
|||
|
g_decode=gif;
|
|||
|
if(g_decode==0) return 0;
|
|||
|
mymemset (g_decode,0,sizeof (GIF_DecodeStruct));
|
|||
|
|
|||
|
gfile=(FIL*)mymalloc(sizeof(FIL));
|
|||
|
mygif89a=(gif89a*)mymalloc(sizeof(gif89a));
|
|||
|
mymemset (mygif89a,0,sizeof(gif89a));
|
|||
|
mygif89a->lzw=(LZW_INFO*)mymalloc(sizeof(LZW_INFO));
|
|||
|
mymemset (mygif89a->lzw,0,sizeof(LZW_INFO));
|
|||
|
|
|||
|
if(res==0)//OK
|
|||
|
{
|
|||
|
res=f_open(gfile,(TCHAR *)filename,FA_READ);
|
|||
|
if(res==0)//打开文件ok
|
|||
|
{
|
|||
|
if(gif_check_head(gfile))res=PIC_FORMAT_ERR;
|
|||
|
if(gif_getinfo(gfile,mygif89a))res=PIC_FORMAT_ERR;
|
|||
|
x=0;y=0;width=mygif89a->gifLSD.width;height=mygif89a->gifLSD.height;
|
|||
|
|
|||
|
g_decode->x_size=width;g_decode->y_size=height;
|
|||
|
gifdecoding=1;
|
|||
|
while(gifdecoding&&res==0)//解码循环
|
|||
|
{
|
|||
|
if (g_decode->frameNumber==GIF_PICCONT_MAX) break;
|
|||
|
//为每一帧图像申请内存
|
|||
|
g_decode->frame[g_decode->frameNumber]=mymalloc_exm (g_decode->x_size*g_decode->y_size*2);
|
|||
|
if (g_decode->frame[g_decode->frameNumber]==0) break;//内存已用完
|
|||
|
if (g_decode->frameNumber)
|
|||
|
{
|
|||
|
//这里把前一张的数据复制到下一张中
|
|||
|
mymemcpy (g_decode->frame[g_decode->frameNumber],g_decode->frame[g_decode->frameNumber-1],g_decode->x_size*g_decode->y_size*2);
|
|||
|
}
|
|||
|
g_decode->frameNumber++;
|
|||
|
res=gif_drawimage(gfile,mygif89a,x,y);//显示一张图片
|
|||
|
if(mygif89a->gifISD.flag&0x80)gif_recovergctbl(mygif89a);//恢复全局颜色表
|
|||
|
if(mygif89a->delay)dtime=mygif89a->delay;
|
|||
|
else dtime=10;//默认延时
|
|||
|
g_decode->delay[g_decode->frameNumber-1]=dtime*10;
|
|||
|
if(res==2)
|
|||
|
{
|
|||
|
res=0;
|
|||
|
break;
|
|||
|
}
|
|||
|
if (res==1) {GIF_DecodeStructFree(g_decode);break;}//解码失败
|
|||
|
}
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
GIF_DecodeStructFree(g_decode);
|
|||
|
}
|
|||
|
f_close(gfile);
|
|||
|
}
|
|||
|
myfree(gfile);
|
|||
|
myfree(mygif89a->lzw);
|
|||
|
myfree(mygif89a);
|
|||
|
return 1;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
//释放GIF_DecodeStruct 结构体申请的内存
|
|||
|
void GIF_DecodeStructFree (GIF_DecodeStruct *gif)
|
|||
|
{
|
|||
|
if (gif)
|
|||
|
{
|
|||
|
for (int i=0;i<gif->frameNumber;i++)
|
|||
|
{
|
|||
|
myfree(gif->frame[i]);
|
|||
|
}
|
|||
|
// myfree(g_decode);
|
|||
|
}
|
|||
|
// g_decode=0;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|