BMP文件解析及显示
程序员文章站
2022-03-07 23:41:19
我们在LCD上显示内容的时候,经常会有显示bmp文件的需求,例如显示一个logo、菜单图标等。我们可以在应用程序中打开bmp文件,然后将它解析成rgb格式的数据写入frame buffer中就可以完成显示。1 BMP文件的格式BMP图像文件格式是Windows采用的图像文件存储格式,在Windows环境下的所有图像处理软件都支持这种格式。它是由3个部分组成:位图文件头、位图信息头、颜色点阵数据。1.1 位图文件头位图文件头分为4个部分,共占据14字节:1.2 位图信息头位图信息头...
我们在LCD上显示内容的时候,经常会有显示bmp文件的需求,例如显示一个logo、菜单图标等。我们可以在应用程序中打开bmp文件,然后将它解析成rgb格式的数据写入frame buffer中就可以完成显示。
1 BMP文件的格式
BMP图像文件格式是Windows采用的图像文件存储格式,在Windows环境下的所有图像处理软件都支持这种格式。它是由3个部分组成:位图文件头、位图信息头、颜色点阵数据。
1.1 位图文件头
位图文件头分为4个部分,共占据14字节:
1.2 位图信息头
位图信息头共40个字节:
1.3 颜色数据
BMP文件除了上述文件头、信息头所占据的内容外,剩余数据都是RGB颜色数据,其中需要注意的是:BMP的颜色数据是按照自下而上,自左向右的顺序排列的。
这个排列的顺序非常关键,因为我们LCD显示的时候。是自上而下、自左向右的,所以我们在解析这个rgb数据的时候需要重新按照LCD的顺序放入buffer中。
2 代码实现
2.1 头文件<pic_operation.h>
/*
* 1、需要一个内存来保存从BMP文件解析得到的颜色数据;
* 2、需要一个函数来判断打开的文件是否是我们需要的BMP文件;
* 3、需要一个函数来完成对BMP文件的解析;
* 4、需要一个函数来释放分配给保存颜色数据的内存;
*/
/* 保存RGB数据的地方 */
typedef struct PixelDatas{
int iWideth;
int iHeight;
int iBpp;
unsigned char *aucPixelDatas;
}T_PixelDatas,*PT_PixelDatas;
/* 封装好对一个文件的处理 */
typedef struct PicFileParser{
char *name;
int (*isSupport)(unsigned char *aFileHead);
int (*GetPixelDatas)(unsigned char *aFileHead,PT_PixelDatas tPixelDatas);
int (*FreePixelDatas)(PT_PixelDatas tPixelDatas);
}T_PicFileParser,*PT_PicFileParser;
2.2 C文件实现<bmp_operation.c>
#include <bmp_operation.h>
/*
* 1、需要定义一个struct PicFileParser 类型的结构体;
* 2、需要实现一个函数来判断打开的文件是否是我们需要的BMP文件;
* 3、需要实现一个函数来释放分配给保存RGB数据的内存;
* 4、需要实现一个函数来解析BMP文件;
*/
static int isSupportBmp(unsigned char *aFileHead);
static int GetPixelDatasFormBmp(unsigned char *aFileHead,PT_PixelDatas ptPixelDatas);
static int FreePixelDatasForBmp(PT_PixelDatas tPixelDatas);
T_PicFileParser g_tBmpParser = {
.name = "bmp",
.isSupport = isSupportBmp,
.GetPixelDatas = GetPixelDatasFromBmp,
.FreePixelDatas = FreePixelDatasForBmp,
}
/* 功能:判断一个文件是否是BMP文件
* 参数aFileHead : 读入文件的头
* 返回值:1-该文件是BMP文件;0-该文件不是BMP文件
*/
static int isSupportBmp(unsigned char *aFileHead){
if(aFileHead[0] != 0x42 || aFileHead[1] != 0x4d)
return 0;
else
return 1;
}
/* 功能:释放分配给存储RGB数据的内存
* 参数tPixelDatas: 从BMP文件解析出来数据存储的地方
* 返回值:0
*/
static int FreePixelDatasForBmp(PT_PixelDatas tPixelDatas){
free(tPixelDatas->aucPixelDatas);
}
/******************************************************************/
/* 解析 BMP 文件 */
/* 1、定义一个位图文件头 */
typedef struct tagBITMAPFILEHEADER{
unsigned short bfType;
unsigned long bfSize;
unsigned short bfReserved1;
unsigned short bfReserved2;
unsigned long bfOffBits;
}BITMAPFILEHEADER;
/* 2、定义一个位图信息头 */
typedef struct tagBITMAPINFOHEADER{
unsigned long biSize;
unsigned long biWidth;
unsigned long biHeight;
unsigned short biPlanes;
unsigned short bitBitCount;
unsigned long bitCompression;
unsigned long bitSizeImage;
unsigned long biXPelPerMeter;
unsigned long biYPelPerMeter;
unsigned long biClrUsed;
unsigned long biClrImportant;
}BITMAPINFOHEADER;
/*
/* 3、解析BMP文件 */
static int GetPixelDatasFormBmp(unsigned char *aFileHead,PT_PixelDatas ptPixelDatas){
/* 定义文件头和信息头 */
BITMAPFILEHEADER *ptBITMAPFILEHEADER;
BITMAPINFOHEADER *ptBITMAPINFOHEADER ;
/* 将文件头指针指向文件的开始 */
ptBITMAPFILEHEADER = (BITMAPFILEHEADER *)aFileHead;
/*将信息头指针指向文件中信息头的起始处*/
ptBITMAPINFOHEADER = (BITMAPINFOHEADER *)(aFileHead + sizeof(BITMAPFILEHEADER ));
/* 计算需要分配内存的大小 */
int iWidth = ptBITMAPINFOHEADER->biWidth;
int iHeight = ptBITMAPINFOHEADER->biHeight;
int iBpp = ptBITMAPINFOHEADER->bitBitCount;
ptPixelDatas->aucPixelDatas = malloc(iWidth*iHeight*iBpp/8);
if(NULL == ptPixelDatas->aucPixelDatas){
return -1;
}
/* 确定取数据以及存数据的位置 */
unsigned char *pucSrc;
unsigned char *pucData;
pucSrc = aFileHead + ptBITMAPFILEHEADER->bfOffBits;/*让数据源指针指向文件中数据的起始处*/
int iLineWidthReal = iWidth * iBpp /8; /*确定每行的字节数*/
int iLineWidthAlign = (iLineWidthReal + 3)&~0x3;/*将每行的字节数向4取整得到对齐后的每行字节数*/
pucSrc = pucSrc + (iHeight-1) * iLineWidthAlign ; /*将数据源指针指向图像的最后一行起始处,该处的数据对应LCD显示时的第一行*/
pucData = ptPixelDatas->aucPixelDatas;/*数据的目的地址就是刚分配的内存处*/
/* 一行一行的从源地址取出数据放入目的地址 */
int x;
int y;
for(y = 0;y < iHeight; y++){
memcpy(pucData,pucSrc,iLineWidthReal); /*每次从源地址拷贝iLienWidthReal长度的数据到目的地址*/
pucSrc -= iLineWidthAlign;/*完成一次拷贝后将源地址指向上一行*/
pucData += iLineWidthReal; /*完成一次拷贝后将目的地址指向下一行*/
}
}
本文地址:https://blog.csdn.net/qq_40629752/article/details/110141919
上一篇: MYSQL大量写入问题优化详解