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;
|
||
}
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|