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

📄 jpegdecode.c

📁 基于stm32的MP3播放器
💻 C
📖 第 1 页 / 共 3 页
字号:
//SRAM缩减优化后,消耗SRAM:12288BYTE			  
//移植到了SD卡上,可以解码JPEG/JPG和BMP
//同时支持两种格式的图片显示了

//对代码进行了初步优化
//对JPEG格式,把不应该显示的列和行的颜色计算省去了.
//在显示大图片的时候,速度明显提高
//对BMP,优化了显示支持,对大图片的行和列也进行了取舍
//把不应该显示的行和列去掉.同时把LCD显示模式设置为自动
//添加,提高了速度.

//对BMP,支持16bit 24bit 和32bit图片显示
//对JPG,基本只支持JFIF格式
//如果不是JFIF格式,用windows的画图打开然后保存一下,就是这个格式了!

//正点原子@HYW
//2009.04.21
//V1.4			  
#include "BMP.H"  
//////////////////////////////////////////////////
//全局变量声明,BMP和JPEG共用	   	
FileInfoStruct *CurFile;//当前解码/操作的文件
//图像信息
typedef struct
{			 
	u16 ImgWidth; //图像的实际宽度和高度
	u16 ImgHeight;
	float Div_Fac;//缩放系数 
	
	u16 S_Height; //设定的高度和宽度
	u16 S_Width;
	
	u8	S_XOFF;	  //x轴和y轴的偏移量
	u16 S_YOFF;
	u8  staticx;  //当前显示到的xy坐标
	u16 staticy;
}PIC_POS;
		  
PIC_POS PICINFO;//图像位置信息

//数据缓冲区		  
unsigned char jpg_buffer[1024];//数据缓存区	

BOOL AI_LoadPicFile(FileInfoStruct *FileName,u8 sx,u16 sy,u8 ex,u16 ey);//智能显示图片		 
void AI_Drow_Init(void);        //智能画图,初始化.得到比例因子PICINFO.Div_Fac	   
//////////////////////////////////////////////////
//在JPEG函数里面用到的变量
short			SampRate_Y_H,SampRate_Y_V;
short			SampRate_U_H,SampRate_U_V;
short			SampRate_V_H,SampRate_V_V;
short			H_YtoU,V_YtoU,H_YtoV,V_YtoV;
short			Y_in_MCU,U_in_MCU,V_in_MCU;			   
unsigned char   *lp;//取代lpJpegBuf
short			qt_table[3][64];
short			comp_num;
BYTE			comp_index[3];
BYTE		    YDcIndex,YAcIndex,UVDcIndex,UVAcIndex;
BYTE			HufTabIndex;
short		    *YQtTable,*UQtTable,*VQtTable;
short		    code_pos_table[4][16],code_len_table[4][16];
unsigned short	code_value_table[4][256];
unsigned short	huf_max_value[4][16],huf_min_value[4][16];
short			BitPos,CurByte;//byte的第几位,当前byte
short			rrun,vvalue;
short			MCUBuffer[10*64];    
short			QtZzMCUBuffer[10*64];
short			BlockBuffer[64];
short			ycoef,ucoef,vcoef;
BOOL			IntervalFlag;
short			interval=0;
short			Y[4*64],U[4*64],V[4*64];//
DWORD		    sizei,sizej;
short 			restart;
long iclip[1024];//4k BYTES
long *iclp;


//初始化智能画点
void AI_Drow_Init(void)
{
	float temp;	   
	temp=(float)PICINFO.S_Width/PICINFO.ImgWidth;
	PICINFO.Div_Fac=(float)PICINFO.S_Height/PICINFO.ImgHeight;
	if(temp<PICINFO.Div_Fac)PICINFO.Div_Fac=temp;	 
	if(PICINFO.Div_Fac>1)PICINFO.Div_Fac=1;
	//使图片处于所给区域的中间
	PICINFO.S_XOFF+=(PICINFO.S_Width-PICINFO.Div_Fac*PICINFO.ImgWidth)/2;
	PICINFO.S_YOFF+=(PICINFO.S_Height-PICINFO.Div_Fac*PICINFO.ImgHeight)/2;
	
	PICINFO.staticx=250;
	PICINFO.staticy=350;//放到一个不可能的值上面
	
	if(CurFile->F_Type==T_BMP) //得到BMP图片,改变显示屏的显示方向
	{	
		TFT_WR_CMD(0,0x00,0x24);	//扫描方向控制 左至右,下至上	  		   
		//设置面板大小
		TFT_WR_CMD(0,0x02,PICINFO.S_XOFF);	//设置X坐标点
		TFT_WR_CMD(1,0x03,PICINFO.S_YOFF);	//设置Y坐标点		  	 
		temp=PICINFO.Div_Fac*PICINFO.ImgWidth+PICINFO.S_XOFF-1;//显示宽度	  
		TFT_WR_CMD(0,0x04,temp);	//结束列数(0~239)				 
		temp=PICINFO.Div_Fac*PICINFO.ImgHeight+PICINFO.S_YOFF-1;//显示高度 
		TFT_WR_CMD(1,0x05,temp);	//结束行数(0~319) 	    
		TFT_WR_REG(0x0E);
	} 				 										    
}   
//判断这个像素是否可以显示
//(x,y) :像素原始坐标
//chg   :功能变量. 
//返回值:0,不需要显示.1,需要显示
u8 IsElementOk(u16 x,u16 y,u8 chg)
{				  
	if(x!=PICINFO.staticx||y!=PICINFO.staticy)
	{
		if(chg==1)
		{
			PICINFO.staticx=x;
			PICINFO.staticy=y;
		} 
		return 1;
	}
	else return 0;
}
//智能画图
//FileName:要显示的图片文件  BMP/JPG/JPEG
//(sx,sy) :开始显示的坐标点
//(ex,ey) :结束显示的坐标点
//图片在开始和结束的坐标点范围内显示
BOOL AI_LoadPicFile(FileInfoStruct *FileName,u8 sx,u16 sy,u8 ex,u16 ey)
{	
	int	funcret;//返回值	
	//得到显示方框大小	  	 
	if(ey>sy)PICINFO.S_Height=ey-sy;
	else PICINFO.S_Height=sy-ey;	 
	if(ex>sx)PICINFO.S_Width=ex-sx;
	else PICINFO.S_Width=sx-ex;
	//显示区域无效
	if(PICINFO.S_Height==0||PICINFO.S_Width==0)
	{
		PICINFO.S_Height=320;
		PICINFO.S_Width=240;
		return FALSE;   
	}
	//影响速度
	//SD_Init();//初始化SD卡,在意外拔出之后可以正常使用
	//显示的开始坐标点
	PICINFO.S_YOFF=sy;
	PICINFO.S_XOFF=sx;
	//文件名传递
	CurFile=FileName;
	if(CurFile->F_Type==T_BMP)//得到一个BMP图像
	{
		funcret=BmpDecode(CurFile); //得到一个BMP图像
		TFT_WR_CMD(0,0x00,0x04);	//扫描方向控制 
		TFT_WR_CMD(0,0x01,0x07);	//扫描方向控制 
		//设置面板大小
		TFT_WR_CMD(0,0x02,0);	//设置X坐标点
		TFT_WR_CMD(1,0x03,0);	//设置Y坐标点    						  
		TFT_WR_CMD(0,0x04,239);	//结束列数(0~239)	  				  	  
		TFT_WR_CMD(1,0x05,319);	//结束行数(0~319) 
		//恢复进入时的设置
		return funcret;    		  
	}
	else if(CurFile->F_Type==T_JPG||CurFile->F_Type==T_JPEG)//得到JPG/JPEG图片
	{
		//得到JPEG/JPG图片的开始信息		 
		F_Open(CurFile);
		//开始时读入1024个字节到缓存里面.方便后面提取JPEG解码的信息
		F_Read(CurFile,jpg_buffer);	   //读第一次
		F_Read(CurFile,jpg_buffer+512);//读第二次
											   
		InitTable(); //初始化各个数据表 
		if((funcret=InitTag())!=FUNC_OK)return FALSE;//初始化表头不成功    
		if((SampRate_Y_H==0)||(SampRate_Y_V==0))return FALSE ;//采样率错误  
		AI_Drow_Init();  //初始化PICINFO.Div_Fac,启动智能画图	   
		funcret=Decode();//解码JPEG开始
	}else return FALSE;  //非图片格式!!!
	if(funcret==FUNC_OK)return TRUE;//解码成功
	else return FALSE;   //解码失败	
}

//解码这个BMP文件
//存在一点点小问题,就是第一个点不显示!!
BOOL BmpDecode(FileInfoStruct *BmpFileName)
{
    u16 count;		    	   
	u8  rgb ,color_byte;
	u16 x ,y,color,tmp_color ;	    

	u16 uiTemp;	   //x轴方向像素计数器 
	u16 countpix=0;//记录像素 
	
	//x,y的实际坐标	
	u8  realx=0;
	u16 realy=0;
	u8  yok=1;
							   
	BITMAPINFO *pbmp;//临时指针 
	CurFile=BmpFileName;	  
					 
	F_Open(CurFile);//打开文件	 						  
	F_Read(CurFile,jpg_buffer);//读出512个字节	  
	pbmp=(BITMAPINFO*)jpg_buffer;//得到BMP的头部信息
	
	count=pbmp->bmfHeader.bfOffBits;        //数据偏移,得到数据段的开始地址
	color_byte=pbmp->bmiHeader.biBitCount/8;//彩色位 16/24/32
										    
	PICINFO.ImgHeight=pbmp->bmiHeader.biHeight;//得到图片高度
	PICINFO.ImgWidth=pbmp->bmiHeader.biWidth;  //得到图片宽度  		  
		
	//水平像素必须是4的倍数!!
	if((PICINFO.ImgWidth*color_byte)%4)
		uiTemp=((PICINFO.ImgWidth*color_byte)/4+1)*4;
	else
		uiTemp=PICINFO.ImgWidth*color_byte;	 
				 
	AI_Drow_Init();//初始化智能画图	    
	//开始解码BMP   	 													 
	x =0 ;
	y=PICINFO.ImgHeight;
	rgb=0;      
	realy=y*PICINFO.Div_Fac;
	while(1)
	{				 
		while(count<512)  //读取一簇512扇区 (SectorsPerClust 每簇扇区数)
	    {
			if(color_byte == 3)   //24位颜色图
			{
				switch (rgb) 
				{
					case 0:
						tmp_color = jpg_buffer[count]>>3 ;
						color |= tmp_color;
						break ;	   
					case 1: 
						tmp_color = jpg_buffer[count]>>2 ;
						tmp_color <<= 5 ;
						color |= tmp_color ;
						break;	  
					case 2 : 
						tmp_color = jpg_buffer[count]>>3 ;
						tmp_color <<= 11 ;
						color |= tmp_color ;
						break ;			
				}   
			}
			else
			{
				if(color_byte==2)  //16位颜色图
				{
					switch(rgb)
					{
						case 0 : 
							tmp_color = jpg_buffer[count] ;
							break ;   
						case 1 :    
							color = jpg_buffer[count] ;
							color<<=8 ;
							color |= tmp_color ;
							break ;	 
					}		     
				}
				else 
				{
					if(color_byte==4)//32位颜色图
					{
						switch (rgb)
						{
							case 0 :  
								tmp_color=jpg_buffer[count];
								color|=tmp_color>>3;
								break ;     
							case 1 :  
								tmp_color=jpg_buffer[count];
								tmp_color>>=2;
								color|=tmp_color<<5;
								break ;	  
							case 2 :  
								tmp_color=jpg_buffer[count];
								tmp_color>>=3;
								color|=tmp_color<<11;
								break ;	 
							case 3 :break ;   
						}		  	 
					}  
				}     
			}//位图颜色得到	
			rgb++;	  
			count++ ;		  
			if(rgb==color_byte) //水平方向读取到1像素数数据后显示
			{	
				x++;//x轴增加一个像素 
				if(x<=PICINFO.ImgWidth)	 					 			   
				{	
					realx=x*PICINFO.Div_Fac;//x轴实际值
					if(IsElementOk(realx,realy,1)&&yok&&realx)//符合条件
					{						 				 	  	       
						TFT_WR_Data16(color);	
					}   									    
				}
				color=0x00; 
				rgb=0;  		  
			}
			countpix++;//像素累加
			if(countpix>=uiTemp)//水平方向像素值到了.换行
			{		 
				y--; 
				if(y<=0)return TRUE; 
				 
				realy=y*PICINFO.Div_Fac;//实际y值改变	 
				if(IsElementOk(realx,realy,0))yok=1;//此处不改变PICINFO.staticx,y的值	 
				else yok=0;	  

				x=0; 
				countpix=0;
				color=0x00;
				rgb=0;
			}	 
		} 
	   	if(!F_Read(CurFile,jpg_buffer))break;//读出512个字节,读数失败时自动退出
	 	count=0 ;
	}		 
	return TRUE;//BMP显示结束.    					   
}   
//对指针地址进行改变!
//pc    :当前指针
//返回值:当前指针的减少量.在d_buffer里面自动进行了偏移
unsigned int P_Cal(unsigned char*pc)
{										   
	unsigned short cont=0;//计数器
	unsigned long buffer_val=0;  //寄存区首地址
	unsigned long point_val=0;	 //指针所指的当前地址

	unsigned char secoff;	 
	unsigned short t;
	unsigned char *p;	  
	p=jpg_buffer+512;//偏移到中间

	point_val=(unsigned long)pc;//得到当前指针所指地址
	buffer_val=(unsigned long)&jpg_buffer;//得到缓存区首地址
	cont=point_val-buffer_val;//得到两者之差
	if(cont>=512)//数据超过了中间
	{
		secoff=cont/512;//超出了多少secoff个512字节	 
		while(secoff)   //读取secoff次512个字节
		{
			for(t=0;t<512;t++)jpg_buffer[t]=p[t];//复制后512个字节 给前512个字节		    
			if(!F_Read(CurFile,p))//读取512个字节到d_buffer的后半部分
			{//读取结束了			
				//printf("read Fail!\n");
				break;//读数失败!break;
			}
			secoff--;
		}     		 
	}
	return cont-cont%512;//指针地址缩减								 
}
//初始化d_buffer的数据  														 
int InitTag(void)
{
	BOOL finish=FALSE;
	BYTE id;
	short  llength;
	short  i,j,k;
	short  huftab1,huftab2;
	short  huftabindex;
	BYTE hf_table_index;
	BYTE qt_table_index;
	BYTE comnum;//最长为256个字节

	unsigned char  *lptemp;		 
	short  colorount;
		 			   	   	  
	lp=jpg_buffer+2;//跳过两个字节SOI(0xFF,0xD8 Start of Image) 
	lp-=P_Cal(lp);  									 
	while (!finish)
	{			 
		id=*(lp+1);//取出低位字节(高位在前,低位在后)
		lp+=2;     //跳过取出的字节
		lp-=P_Cal(lp);	   
		switch (id)
		{

⌨️ 快捷键说明

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