BMP文件解析及显示

我们在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; /*完成一次拷贝后将目的地址指向下一行*/
    }    
}

 

  • 5
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值