http://weibo.com/GTY55IW
在液晶显示需要图片的点阵代码有时需要将BMP图片解码以获取点阵代码,以下为解码分析:
/* 解析
"file1.txt" a file on drive 0
"/file1.txt" (same as above)
"dir1/dir2/file1.txt" a file on drive 0
"2:dir3/file2.txt" a file on drive 2
"2:/dir5" a directory on drive 2
"" the root directory on drive 0
"/" (same as above)
"2:" the root directory on drive 2
*/
//支持24bit BMP图片显示
#include "config.h"
#include "./BMP/BMP.h"
#include "GUI_Private.h"
#include "./FATFS/src/ff.h"
static U16 _Read16(const U8 ** ppData)
{
const U8 *pData;
U16 Value;
pData = *ppData;
Value = *pData;
Value |= (U16)(*(pData + 1) << 8);
pData += 2;
*ppData = pData;
return Value;
}
static U32 _Read32(const U8 ** ppData)
{
const U8 * pData;
U32 Value;
pData = *ppData;
Value = *pData;
Value |= ( *(pData + 1) << 8);
Value |= ((U32)*(pData + 2) << 16);
Value |= ((U32)*(pData + 3) << 24);
pData += 4;
*ppData = pData;
return Value;
}
static int _GetStep(int *pYSize,int *pY)
{
if(*pYSize>0)
{
*pY=*pYSize-1 ;
return -1 ;
}
else if(*pYSize<0)
{
*pYSize=-*pYSize ;
*pY=0 ;
return 1 ;
}
else
{
return 0 ;
}
}
//BMP文件数据缓冲区
INT8U BMP_Buffer[960];
static bool Get_BMP_Info(char *file, BMP_FILEHEADER *BmpHead)
{
FATFS fs ;
FIL fsrc;
FRESULT res ;
UINT br;
//获取bmp文件长度、宽度等信息
const U8 *pSrc=BMP_Buffer;
//读取bmp文件
f_mount(0,&fs);
// f_mount(1,&fs);
// f_mount(2,&fs);
res=f_open(&fsrc,file,FA_OPEN_EXISTING|FA_READ);
if(res) return FALSE;
res=f_read(&fsrc,BMP_Buffer,sizeof(BMP_Buffer),&br);
if(res) return FALSE;
f_close(&fsrc);
f_mount(0,NULL);
// f_mount(1,NULL);
// f_mount(2,NULL);
//BMP位图文件头
BmpHead->bfType = _Read16(&pSrc);//Offset:0x0000,文件标志.只对'BM',用来识别BMP位图类型
BmpHead->bfSize = _Read32(&pSrc);//Offset:0x0002,文件大小,占四个字节;注意是大字节序还是小字节序,实际BMP格式中是小字节序
BmpHead->bfReserved1 = _Read16(&pSrc);//Offset:0x0006,保留
BmpHead->bfReserved2 = _Read16(&pSrc);//Offset:0x0008,保留
BmpHead->bfOffBits = _Read32(&pSrc);//Offset:0x000A,从文件开始到位图数据(bitmap data)开始之间的的偏移量
//BMP位图信息头
BmpHead->biSize = _Read32(&pSrc);//Offset:0x000E,位图信息头字节数量。一般为0x28,最好取其实际值
BmpHead->biWidth = _Read32(&pSrc);//Offset:0x0012,说明图象的宽度,以象素为单位
BmpHead->biHeight = _Read32(&pSrc);//Offset:0x0016,说明图象的高度,以象素为单位,如果这是一个正数,说明图像数据是从图像左下角到右上角排列的。
BmpHead->biPlanes = _Read16(&pSrc);//Offset:0x001A,为目标设备说明位面数,其值将总是被设为1
BmpHead->biBitCount = _Read16(&pSrc);//Offset:0x001C,说明比特数/象素,其值为1、4、8、16、24、或32
BmpHead->biCompression = _Read32(&pSrc);//Offset:0x001E,说明图象数据压缩的类型 0表示没有压缩
BmpHead->biSizeImage = _Read32(&pSrc);//Offset:0x0022,说明图象的大小,以字节为单位。当用BI_RGB格式时,可设置为0
BmpHead->biXPelsPerMeter = _Read32(&pSrc);//Offset:0x0026,说明水平分辨率,用象素/米表示,有符号整数
BmpHead->biYPelsPerMeter = _Read32(&pSrc);//Offset:0x002A,说明垂直分辨率,用象素/米表示,有符号整数
BmpHead->biClrUsed = _Read32(&pSrc);//Offset:0x002E,说明位图实际使用的彩色表中的颜色索引数
BmpHead->biClrImportant = _Read32(&pSrc);//Offset:0x0032,说明对图象显示有重要影响的颜色索引的数目,如果是0,表示都重要。
printf("/r/n【BMP位图文件头】");
printf("/r/nBmpHead->bfType =0x%0X",BmpHead->bfType);
printf("/r/nBmpHead->bfSize =%d",BmpHead->bfSize);
printf("/r/nBmpHead->bfReserved1 =%d",BmpHead->bfReserved1);
printf("/r/nBmpHead->bfReserved2 =%d",BmpHead->bfReserved2);
printf("/r/nBmpHead->bfOffBits =%d",BmpHead->bfOffBits);
printf("/r/n【BMP位图信息头】");
printf("/r/nBmpHead->biSize =%d",BmpHead->biSize);
printf("/r/nBmpHead->biWidth =%d",BmpHead->biWidth);
printf("/r/nBmpHead->biHeight =%d",BmpHead->biHeight);
printf("/r/nBmpHead->biPlanes =%d",BmpHead->biPlanes);
printf("/r/nBmpHead->biBitCount =%d",BmpHead->biBitCount);
printf("/r/nBmpHead->biCompression =%d",BmpHead->biCompression);
printf("/r/nBmpHead->biSizeImage =%d",BmpHead->biSizeImage);
printf("/r/nBmpHead->biXPelsPerMeter=%d",BmpHead->biXPelsPerMeter);
printf("/r/nBmpHead->biYPelsPerMeter=%d",BmpHead->biYPelsPerMeter);
printf("/r/nBmpHead->biClrUsed =%d",BmpHead->biClrUsed);
printf("/r/nBmpHead->biClrImportant =%d",BmpHead->biClrImportant);
return TRUE;
}
bool GUI_BMP_Draw_From_SD(char *file,int x0,int y0)
{
BMP_FILEHEADER BmpHead;
int Width,Height ;
U16 Type ;
U32 OffBits,Compression ;
FATFS fs;
FIL fsrc;
FRESULT res;
UINT br;
int x=0,y=0,BytesPerLine,Step ;
//获得BMP头文件信息
if(Get_BMP_Info(file, &BmpHead)==FALSE)
{
return FALSE;
}
Type = BmpHead.bfType;
Width = BmpHead.biWidth;
Height = BmpHead.biHeight;
//BitCount = BmpHead.biBitCount;
Compression = BmpHead.biCompression;
//ClrUsed = BmpHead.biClrUsed;
OffBits = BmpHead.bfOffBits;//bmp颜色数据起始位置
if((Type!=0x4d42)||(Compression))
{
printf("/r/n不支持该图片显示!");
return FALSE;
}
//if((Width>320)||(Height>240))
if(Width>320)//图片宽度不能超过320,因为缓冲数组为960
{
printf("/r/n图片太大,无法显示!");
return FALSE;
}
//开始画图
f_mount(0,&fs);
// f_mount(1,&fs);
// f_mount(2,&fs);
res=f_open(&fsrc,file,FA_OPEN_EXISTING|FA_READ);
if(res) return FALSE;
res=f_lseek(&fsrc,OffBits); //找到bmp颜色数据起始位置
if(res) return FALSE;
Step=_GetStep(&Height,&y); //判断是否从底向上读数据
if(!Step) return FALSE;
BytesPerLine=((24*Width+31)>>5)<<2 ;
for(;(y
{
//每次读取一行数据进行显示,然后再读取下一行数据,行数据个数为BytesPerLine
//对TFT320*240,16bpp,每行320*3=960个字节
res=f_read(&fsrc,BMP_Buffer,BytesPerLine,&br);
if(res) return FALSE;
for(x=0;x
const U8 *pColor=BMP_Buffer+3*x ;
U8 r,g,b ;
//U16 color ;
b=*(pColor);
g=*(pColor+1);
r=*(pColor+2);
LCD_SetPixelIndex(x0+x,y0+y,LCD_Color2Index(((U32)b<<16)|(g<<8)|r));
}
}
f_close(&fsrc);
f_mount(0,NULL);
// f_mount(1,NULL);
// f_mount(2,NULL);
return TRUE;
}
/*************************** End of file ****************************/
以下为头文件:
//1、位图中头的信息是按小字节序存储的,注意编译器如果是大字节序的需要字节顺序调整才可以。
//2、位图中图象信息的第一个像素在图象中是左下角的像素,先最下一行从左往右,然后上面一行
//3、文档中有这样的说法:像素数据的长度(按字节计)要是4的倍数,这个4的倍数是怎么体现的呢?
// 首先,这个规定并不是可遵守不可遵守的,一旦不遵守,图象水平方向上像素数是4的倍数还好,不然肯定会出错。
// 这个4的倍数该怎么理解呢?我的像素怎么排?是不是每个像素占4个字节?
// 经过实际用画图板制作各种尺寸的图象得到下面的结论:
// 每个像素只占3个字节,水平方向上所有像素连续排列,
//统计水平方向像素所占的字节数(像素数*3),如果得到的结果是4的倍数,就继续下一行数据,
// 如果不是4的倍数,在最后一个像素数据后面补0,使这一行的总字节数等于4的倍数,然后开始下一行数据
// 如:
// 3*5的图象:
// 水平方向有3个像素,像素占的字节数为9,不是4的倍数,在第三个像素数据后面补3个0,使这一行的总字节数为12,补完0,开始下一行数据。
// 5*3的图象:
// 水平方向有5个像素,像素占的字节数为15,不是4的倍数,在第五个像素后面补1个0,使此行的总字节数为16,继续下一行数据
//bmp文件头(bmp file header):提供文件的格式、大小等信息
//1/位图信息头(bitmap information):提供图像数据的尺寸、位平面数、压缩方式、颜色索引等信息
//2/调色板(color palette):可选,如使用索引来表示图像,调色板就是索引与其对应的颜色的映射表
// 调色板其实是一张映射表,标识颜色索引号与其代表的颜色的对应关系。
// 它在文件中的布局就像一个二维数组palette[N][4],其中N表示总的颜色索引数,
// 每行的四个元素分别表示该索引对应的B、G、R和Alpha的值,每个分量占一个字节。
// 如不设透明通道时,Alpha为0。因为前面知道,本图有256个颜色索引,因此N = 256。
// 索引号就是所在行的行号,对应的颜色就是所在行的四个元素。
//3/位图数据(bitmap data):就是图像数据啦^_^
#ifndef __BMP_H__
#define __BMP_H__
#include "def.h"
typedef struct
{
//BMP位图文件头
INT16U bfType; //Offset:0x0000,文件标志.只对'BM',用来识别BMP位图类型
INT32U bfSize; //Offset:0x0002,文件大小,占四个字节;注意是大字节序还是小字节序,实际BMP格式中是小字节序
INT16U bfReserved1; //Offset:0x0006,保留
INT16U bfReserved2; //Offset:0x0008,保留
INT32U bfOffBits; //Offset:0x000A,从文件开始到位图数据(bitmap data)开始之间的的偏移量,看后面的图象信息头的多少定,图象信息头大小为0x28则本字段值为0x36,本字段的值实际上为"图象信息头长度+14+调色板信息长度"
//BMP位图信息头
INT32U biSize; //Offset:0x000E,位图信息头字节数量。一般为0x28,最好取其实际值
INT32S biWidth; //Offset:0x0012,说明图象的宽度,以象素为单位
INT32S biHeight; //Offset:0x0016,说明图象的高度,以象素为单位,如果这是一个正数,说明图像数据是从图像左下角到右上角排列的。
INT16U biPlanes; //Offset:0x001A,为目标设备说明位面数,其值将总是被设为1
INT16U biBitCount; //Offset:0x001C,说明比特数/象素,其值为1、4、8、16、24、或32
INT32U biCompression; //Offset:0x001E,说明图象数据压缩的类型。其值可以是下述值之一:
//BI_RGB:没有压缩;
//BI_RLE8:每个象素8比特的RLE压缩编码,压缩格式由2字节组成(重复象素计数和颜色索引);
//BI_RLE4:每个象素4比特的RLE压缩编码,压缩格式由2字节组成
//BI_BITFIELDS:每个象素的比特由指定的掩码决定。
INT32U biSizeImage; //Offset:0x0022,说明图象的大小,以字节为单位。当用BI_RGB格式时,可设置为0
INT32U biXPelsPerMeter;//Offset:0x0026,说明水平分辨率,用象素/米表示,有符号整数
INT32U biYPelsPerMeter;//Offset:0x002A,说明垂直分辨率,用象素/米表示,有符号整数
INT32U biClrUsed; //Offset:0x002E,说明位图实际使用的彩色表中的颜色索引数
INT32U biClrImportant; //Offset:0x0032,说明对图象显示有重要影响的颜色索引的数目,如果是0,表示都重要。
}BMP_FILEHEADER;
//从SD卡获取bmp文件,并显示
bool GUI_BMP_Draw_From_SD(char *file,int x0,int y0);
#endif