OK6410 裸机BMP图片解码

来源:互联网 发布:三维迷宫软件 编辑:程序博客网 时间:2024/06/11 15:39

主要在之前的解码的基础上面添加了图片缩放功能。

大家可以看看BMP解码过程或者思路。

资料网上非常多,在此就不在说明,直接上代码。


BMPdecode.c

/************************************************************************************************************* * 文件名:bmpdecode.c * 功能:BMP图片软件解码 * 作者:cp1300@139.com * 创建时间:2012年12月7日20:30 * 最后修改时间:2012年12月9日 * 详细:只支持非压缩的BMP,16bit,24bit,32bit * 图片文件最大由BMP_MAX_BUFF决定 * 因为使用了FATFS,以及比较多的临时变量,内联函数可能需要比较大的堆栈 * 因为添加了图片缩放功能,因此程序比以前的效率稍微低下了一点,主要是因为画点的时候需要判断了*************************************************************************************************************/#include "tft_lcd.h"#include "system.h"#include "bmpdecode.h"#include "ff.h"//图片缓冲区,目前定义为10MB,也就意味着最大只能打开10MB的位图文件#define BMP_MAX_BUFF  10*1024*1024//定义缓冲区最大大小static u8 BmpImageBuff[BMP_MAX_BUFF];//图片缓冲区//显示窗口的最大值,一般定义为显示器大小#define LCD_MAX_WIDTH800//最大宽度#define LCD_MAX_HEIGHT480//最大高度//图像数据压缩类型,目前只支持没有压缩的位图#define BI_RGB       0//没有压缩#define BI_RLE8      1//每个象素8比特的RLE压缩编码,压缩格式由2字节组成(重复象素计数和颜色索引)#define BI_RLE4      2//每个象素4比特的RLE压缩编码,压缩格式由2字节组成#define BI_BITFIELDS 3//每个象素的比特由指定的掩码决定//16,24,32位BMP文件头部信息结构typedef  struct{u16 Invalid;//无效的填充字节,用于让数据对齐 u16 bfType ; //文件标志.只对'BM',用来识别BMP位图类型u32 bfSize ; //文件大小,占四个字节u32 bfReserved1 ;//保留u32 bfOffBits ; //从文件开始到位图数据(bitmap data)开始之间的的偏移u32 bmfHeaderSize;//图像描述信息块的大小,常为28Hu32 biWidth ; //说明图象的宽度,以象素为单位u32 biHeight ; //说明图象的高度,以象素为单位u16 biPlanes ; //为目标设备说明位面数,其值将总是被设为1u16 biBitCount ; //说明比特数/象素,其值为1、4、8、16、24、或32u32 biCompression ; //说明图象数据压缩的类型。其值可以是下述值之一://BI_RGB:没有压缩;//BI_RLE8:每个象素8比特的RLE压缩编码,压缩格式由2字节组成(重复象素计数和颜色索引);//BI_RLE4:每个象素4比特的RLE压缩编码,压缩格式由2字节组成//BI_BITFIELDS:每个象素的比特由指定的掩码决定。u32 biSizeImage ;//说明图象的大小,以字节为单位。当用BI_RGB格式时,可设置为0u32 biXPelsPerMeter ;//说明水平分辨率,用象素/米表示u32 biYPelsPerMeter ;//说明垂直分辨率,用象素/米表示u32 biClrImportant ; //说明对图象显示有重要影响的颜色索引的数目,如果是0,表示都重要。}BMPFILEHEADER;//BMP图片相关的信息结构struct BMP_IMAGE{u16 bfOffBits ; //从文件开始到位图数据(bitmap data)开始之间的的偏移u16 biWidth ; //说明图象的宽度,以象素为单位u16 biHeight ; //说明图象的高度,以象素为单位u16biBitCount ; //说明比特数/象素,其值为1、4、8、16、24、或32u32 biSizeImage;//位图数据的大小u32 biSizeFile;//位图文件大小}BmpFile;//图像信息struct BMPPIC_POS{ u32 ImgWidth;//图像的实际宽度和高度u32 ImgHeight;u32 Div_Fac;//图像缩放系数(扩大了10000倍)u32 S_Height;//设定的显示高度和宽度u32 S_Width;u32S_XOFFSET;//X,Y起始偏移量u32 S_YOFFSET;u32 staticx;//当前显示的X,Y坐标u32 staticy;}BMPPICINFO;//内部函数声明static BMP_ERROR OpenBmpFile(const char *FileName,u8 *buff,u32 FileMaxSize);//打开BMP图像,并将数据读取到内存__inline u8 ReadByteData(u32 Offset);//读取一字节指定偏移的图片数据static BMP_ERROR DecodingHead(u8 *FileBuff);//解码BMP图片头部__inline void BmpImageDrow(u16 x,u16 y,u16 data);//BMP图像画点函数static BMP_ERROR BmpDecode(u16 x1,u16 y1,u16 x2,u16 y2,u8 *BmpBuff);//BMP图像解码核心static void ImageDrow_Init(void);//BMP画点函数初始化/**************************************************************************************************************************函数        :static BMP_ERROR OpenBmpFile(const char *FileName,u8 *buff,u32 FileMaxSize)*功能        :打开BMP图像,并将数据读取到内存*参数        :FileName:文件名,路径指针;buff:读取缓冲区;FileMaxSize:文件最大限制*返回        :BMP_ERROR*依赖     : FATFS文件系统支持*作者        :cp1300@139.com*时间     :20121207*最后修改时间:20121207*说明     :调用FATFS打开BMP图片文件*************************************************************************************************************************/static BMP_ERROR OpenBmpFile(const char *FileName,u8 *buff,u32 FileMaxSize){FIL file;UINT cnt;int status;BMP_ERROR error = BMP_OK;status = f_open(&file,FileName,FA_READ);//只读方式打开文件if(status != FR_OK)//打开文件错误{uart_printf("open \"%s\" error!\r\n",FileName);status = BMP_OPEN_ERROR;}else{//获取文件大小uart_printf("file size : %dB\r\n",file.fsize);//输出文件大小if(file.fsize > FileMaxSize){uart_printf("file size > %d\r\n",FileMaxSize);status = BMP_SIZE_ERROR;}else{status = f_read(&file,buff,file.fsize,&cnt);//读取文件uart_printf("Read File Num=%d\r\n",cnt);if(cnt == file.fsize)//判断文件是否读取完毕{uart_printf("read file end!\r\n");BmpFile.biSizeFile = file.fsize;//存储位图文件大小status =  BMP_OK;}else{uart_printf("read file error!\r\n");status = BMP_READ_ERROR;}}}f_close(&file);return error;}/**************************************************************************************************************************函数        :__inline u8 ReadByteData(u32 Offset)*功能        :读取一字节指定偏移的图片数据*参数        :Offset:地址偏移*返回        :数据*依赖     : 无*作者        :cp1300@139.com*时间     :20121207*最后修改时间:20121207*说明     :方便移植*************************************************************************************************************************/__inline u8 ReadByteData(u32 Offset){return BmpImageBuff[Offset];}/**************************************************************************************************************************函数        :static BMP_ERROR DecodingHead(u8 *FileBuff)*功能        :解码BMP图片头部*参数        :*FileBuff:bmp图像数据缓冲区指针*返回        :BMP_ERROR*依赖     : static BMP_ERROR OpenBmpFile(const char *FileName,u8 *buff,u32 FileMaxSize)*作者        :cp1300@139.com*时间     :20121207*最后修改时间:20121207*说明     :注意BMP的头部信息并没有按照32BIT对齐,在前面插了两个字节后即可对齐,非对齐访问会发生异常*************************************************************************************************************************/static BMP_ERROR DecodingHead(u8 *FileBuff){BMP_ERROR error = BMP_OK;u8 buff[52];u8 cnt;BMPFILEHEADER *pbmp;//临时指针,用于获取BMP文件的头部信息u8 *p = buff + 2;//BMP头部共50字节,前面的两个字节用于偏移对齐for(cnt = 0;cnt < 50;cnt ++){p[cnt] = FileBuff[cnt];//复制(读取)头部到缓冲区}pbmp = (BMPFILEHEADER*)buff;//得到BMP的头部信息BmpFile.bfOffBits = pbmp->bfOffBits; //位图数据偏移地址偏移BmpFile.biBitCount = pbmp->biBitCount;//位图数据的颜色深度只支持16bit,24bit,32bitBmpFile.biWidth = pbmp->biWidth;//位图的水平像素数BmpFile.biHeight = pbmp->biHeight;//位图的垂直像素数BmpFile.biSizeImage = pbmp->biSizeImage;//位图的数据大小,有的图片这个值为0/****************************************************///调试uart_printf("地址偏移:%d\r\n",BmpFile.bfOffBits);uart_printf("颜色深度:%d\r\n",BmpFile.biBitCount);uart_printf("水平分辨率:%d\r\n",BmpFile.biWidth);uart_printf("垂直分辨率:%d\r\n",BmpFile.biHeight);uart_printf("数据大小:%d\r\n",BmpFile.biSizeImage);uart_printf("位图标志:%X\r\n",pbmp->bfType);/****************************************************/if(pbmp->bfType == 0x4d42)//检测位图头部信息{if((BmpFile.biBitCount != 16) && (BmpFile.biBitCount != 24) && (BmpFile.biBitCount != 32))error = BMP_TYPE_ERROR;elseerror = BMP_OK;}elseerror = BMP_TYPE_ERROR;return error;}/**************************************************************************************************************************函数        :__inline void BmpImageDrow(u16 x,u16 y,u16 data)*功能        :BMP图像画点函数*参数        :x,y:xy坐标,data:RGB565数据*返回        :无*依赖     : 无*作者        :cp1300@139.com*时间     :20121207*最后修改时间:20121207*说明     :因为进行缩放的时候,有些点不用进行显示*************************************************************************************************************************/__inline void BmpImageDrow(u16 x,u16 y,u16 data){  if(x != BMPPICINFO.staticx || y != BMPPICINFO.staticy){BMPPICINFO.staticx = x;BMPPICINFO.staticy = y;LCD_DrawPoint(x+BMPPICINFO.S_XOFFSET,y+BMPPICINFO.S_YOFFSET,data);}}/**************************************************************************************************************************函数        :static BMP_ERROR BmpDecode(u16 x1,u16 y1,u16 x2,u16 y2,u8 *BmpBuff)*功能        :BMP图像解码核心*参数        :x1,y1:窗口起始坐标;x2,y2:窗口结束坐标;BmpBuff:图像缓冲区指针*返回        :BMP_ERROR*依赖     : 需要先解码头信息*作者        :cp1300@139.com*时间     :20121207*最后修改时间:20121209*说明     :解码图像*************************************************************************************************************************/static BMP_ERROR BmpDecode(u16 x1,u16 y1,u16 x2,u16 y2,u8 *BmpBuff){BMP_ERROR error = BMP_OK;u32 data;//存放24BIT图片的一个像素颜色值u32 bmp_cnt;//已经读取的照片数据计数u16 uiTemp;  //x轴方向实际存储的像素数据字节数u16 xValid;//x轴方向有效的像素数据字节数u16 xcnt; //X轴方向像素点数据字节数计数u16 x,y;//画点坐标u8 temp;if((BmpFile.biWidth * BmpFile.biBitCount / 8) % 4)//水平像素字节数不是4的整数倍uiTemp = ((BmpFile.biWidth * BmpFile.biBitCount / 8) / 4 + 1) * 4;//将水平像素字节数扩展成4的整数倍elseuiTemp = BmpFile.biWidth * BmpFile.biBitCount / 8;xValid = BmpFile.biWidth * (BmpFile.biBitCount / 8);//计算水平有效地数据字节数y = BMPPICINFO.ImgHeight - 1;//BMP图片由左下角到右上角刷新,因此起点y坐标要加上图片的高度x = 0;bmp_cnt = BmpFile.bfOffBits;//将文件数据开始赋值给数据计数器xcnt = 0;//X方向像素点计数器清零do{switch (BmpFile.biBitCount)//判断图片颜色深度{case 32: //32BIT   ARGB8888  //之所以使用一个字节读取一方面方便移植到内存较小的单片机上面执行,另一方面避免内存非对齐访问产生异常。{data = ReadByteData(bmp_cnt++);temp = ReadByteData(bmp_cnt++);data |= temp << 8;temp = ReadByteData(bmp_cnt++);data |= temp << 16;bmp_cnt ++;data = RGB565(data);//RGB888 ---> RGB565}break;case 24: //24BIT RGB888//可能存在4字节对齐问题{data = ReadByteData(bmp_cnt++);temp = ReadByteData(bmp_cnt++);data |= temp << 8;temp = ReadByteData(bmp_cnt++);data |= temp << 16;xcnt += 3;data = RGB565(data);//RGB888 ---> RGB565}break;case 16: //16BIT  RGB555 //可能存在4字节对齐问题{data = ReadByteData(bmp_cnt++);temp = ReadByteData(bmp_cnt++);data |= temp << 8;xcnt += 2;data = ((data & 0xffe0) << 1) | (data & 0x001f);//RGB555  --->  RGB565data |= ((data & BIT6) ? BIT5 : 0);};break;default : break;//只支持16BIT,24BIT,32BIT图片的解码}switch(BMPPICINFO.Div_Fac){case 10000:BmpImageDrow(x,y,data);break;//图片无需缩放default:BmpImageDrow(x*BMPPICINFO.Div_Fac/10000,y*BMPPICINFO.Div_Fac/10000,data);break;//图片需要缩放}x ++;if(x == BMPPICINFO.ImgWidth)//一行解码完成,换行{x = 0;if(y == 0) break;y --;}if(xcnt == xValid)//插值,无效数据,跳过{bmp_cnt += uiTemp - xcnt;xcnt = 0;}}while(bmp_cnt  < BmpFile.biSizeFile);//判断数据是否读取完毕uart_printf("bmp_cnt = 0x%X; BmpFile.biSizeFile = 0x%X\r\n",bmp_cnt,BmpFile.biSizeFile);return error;}/**************************************************************************************************************************函数        :static void ImageDrow_Init(void)*功能        :BMP画点函数初始化*参数        :无*返回        :无*依赖     : 无*作者        :cp1300@139.com*时间     :20121207*最后修改时间:20121209*说明     :用于计算显示坐标以及缩放系数*************************************************************************************************************************/static void ImageDrow_Init(void){float temp,temp1;BMPPICINFO.ImgWidth = BmpFile.biWidth;//获取图像实际宽度BMPPICINFO.ImgHeight = BmpFile.biHeight;//获取图像实际高度temp=(float)BMPPICINFO.S_Width / BMPPICINFO.ImgWidth;temp1=(float)BMPPICINFO.S_Height / BMPPICINFO.ImgHeight;if(temp < temp1) temp1 = temp;//取较小的那个边的缩放系数if(temp1 > 1) temp1 = 1;//不能放大,原图大小显示BMPPICINFO.Div_Fac = temp1 * 10000;//将缩放系数扩大10000倍//计算偏移,将图片置于显示区域的起始位置BMPPICINFO.S_XOFFSET += (BMPPICINFO.S_Width - temp1 * BMPPICINFO.ImgWidth) / 2;BMPPICINFO.S_YOFFSET += (BMPPICINFO.S_Height - temp1 * BMPPICINFO.ImgHeight) / 2;//将当前显示坐标放到一个不可能的值上面BMPPICINFO.staticx = 0xffff;BMPPICINFO.staticy = 0xffff;}/**************************************************************************************************************************函数        :BMP_ERROR ShowBmpImage(u16 x1,u16 y1,u16 x2,u16 y2,const char *BmpFile)*功能        :指定位置显示一张BMP图片*参数        :x1,y1:窗口起始坐标;x2,y2:窗口结束坐标;BmpFile:BMP文件路径以及名称*返回        :BMP_ERROR*依赖     : static BMP_ERROR BmpDecode(u16 x1,u16 y1,u16 x2,u16 y2,u8 *BmpBuff)*作者        :cp1300@139.com*时间     :20121207*最后修改时间:20121207*说明     :直接在LCD上面显示一张BMP图片,需要FATFS支持* 当结束窗口坐标为0的时候结束坐标自动换成屏幕结束坐标*************************************************************************************************************************/BMP_ERROR ShowBmpImage(u16 x1,u16 y1,u16 x2,u16 y2,const char *BmpFile){BMP_ERROR error;BMPPICINFO.S_Width = (((x2 - x1 + 1) > LCD_MAX_WIDTH) || (x2 == 0)) ? (LCD_MAX_WIDTH-x1): (x2 - x1 + 1);//计算设定的显示宽度和高度BMPPICINFO.S_Height = (((y2 - y1 + 1) > LCD_MAX_HEIGHT) || (y2 == 0)) ? (LCD_MAX_HEIGHT-y1): (y2 - y1 + 1);BMPPICINFO.S_XOFFSET = x1;//初始化偏移为起始坐标BMPPICINFO.S_YOFFSET = y1;error = OpenBmpFile(BmpFile,BmpImageBuff,BMP_MAX_BUFF);if(error == BMP_OK){error = DecodingHead(BmpImageBuff);if(error == BMP_OK){ImageDrow_Init();error = BmpDecode(x1,y1,x2,y2,BmpImageBuff);}}return error;}

bmpdecode.h

/************************************************************************************************************* * 文件名:bmpdecode.h * 功能:BMP图片软件解码 * 作者:cp1300@139.com * 创建时间:2012年12月7日20:30 * 最后修改时间:2012年12月9日 * 详细:只支持非压缩的BMP,16bit,24bit,32bit * 图片文件最大由BMP_MAX_BUFF决定 * 因为使用了FATFS,以及比较多的临时变量,内联函数可能需要比较大的堆栈*************************************************************************************************************/#ifndef BMPDECODE_H_#define BMPDECODE_H_//BMP错误定义typedef enum{BMP_OK=0,//正常处理完成BMP_OPEN_ERROR=1,//图像打开错误BMP_READ_ERROR=2,//图像读取错误BMP_SIZE_ERROR  = 3,//图像大小错误BMP_TYPE_ERROR  = 4,//不支持的图像类型,图像类型错误BMP_OTHER_ERROR=5//其它未知错误} BMP_ERROR;BMP_ERROR ShowBmpImage(u16 x1,u16 y1,u16 x2,u16 y2,const char *BmpFile);//指定位置显示一张BMP图片#endif /*BMPDECODE_H_*/

main.c

#include "system.h"#include "uart.h"#include "tft_lcd.h"#include "other.h"#include "delay.h"#include "timer.h"#include "ff.h"#include "rtc.h"#include "bmpdecode.h"#include "jpeg.h"u8 jpeg_buff[10*1024*1024];u8 buff[10*1024*1024];FATFS fs;//LED1闪烁程序,在定时器0中断服务程序中闪烁,周期400MSvoid LED1_flash(void){LED1_FLASH();}void PrintfDirFile(void){int result;DIR DirInf;  FILINFO FileInf;int cnt;result = f_opendir(&DirInf, "/"); /* 如果不带参数,则从当前目录开始 */if (result != FR_OK) {lcd_printf("Root Directory is Open Error (%d)\n", result);}/* 读取当前文件夹下的文件和目录 */lcd_printf("Name             Tyepe         Size\n");for (cnt = 0; ;cnt++) {result = f_readdir(&DirInf,&FileInf); /* 读取目录项,索引会自动下移 */if (result != FR_OK || FileInf.fname[0] == 0){break;}if (FileInf.fname[0] == '.'){continue;}lcd_printf("%s  ", FileInf.fname);if (FileInf.fattrib == AM_DIR){lcd_printf("Directory ");} else {lcd_printf("File  ");}lcd_printf("%d\n", FileInf.fsize);}}//主函数int main(void){int result;LCD_Init();//初始化LCDUART0_Init(DISABLE,115200);//初始化串口,失能中断接收,波特率115200LED_Init();//初始化LEDTimer1_Init(400000-1,ENABLE,LED1_flash);//初始化定时器1,周期400msRTC_Init(ENABLE);//初始化RTC时钟JPEG_Init();//初始化JPEG解码器result = disk_initialize (DISK_SDMMC);//初始化磁盘if(result == RES_OK){lcd_printf("Disk Init OK!\n");result = f_mount(DISK_SDMMC,&fs);if(result == FR_OK){lcd_printf("Mount Disk OK!\n");PrintfDirFile();//打印根目录下的文件ShowBmpImage(0,0,0,0,"bmp24.BMP");//显示全屏图片ShowBmpImage(200,200,0,0,"bmp24.BMP");//显示缩小的图片}else{lcd_printf("Mount Disk ERROR(%d)!\n",result);}}else{lcd_printf("Disk Init ERROR(%d)!\n",result);}while(1){LED2_FLASH();//LED2闪烁Delay_US(600000);//lcd_printf("%d-%d-%d %d:%d\n",Timer.w_year,Timer.w_month,Timer.w_date,Timer.hour,Timer.min);}}



开发板上面的效果图



原创粉丝点击