欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  科技

BMP文件解析及显示

程序员文章站 2022-06-16 17:53:37
我们在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字节:

BMP文件解析及显示

1.2 位图信息头

位图信息头共40个字节:

BMP文件解析及显示

1.3 颜色数据

BMP文件除了上述文件头、信息头所占据的内容外,剩余数据都是RGB颜色数据,其中需要注意的是:BMP的颜色数据是按照自下而上,自左向右的顺序排列的。

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

相关标签: display linux