✌BMP图片的显示

1. BMP图片的解析和显示

BMP是一种常见的图片存储格式,是由微软制定的一种无压缩的图片存储格式
bit map picture(位图) 的缩写


bmp存储的时候是把bmp图片中每一个像素点的每一个bit都直接存储到文件中(bmp图片是没有被压缩的)


关于“bmp”图片存储的具体格式,可以参考"维基百科"

关于“bmp”图片,有几个简单的概念:
     
   位深:每一个像素点占用的bit数量(RGB、ARGB...)
        常见的图片一般是24位位数,一个像素点占用24个bit位,存储了RGB信息

bmp文件格式:

2. 自己制作一张bmp图片

注意:把图片的后缀名修改为.bmp,是否可以呢?
        肯定不可以
文件的名字和文件的实际内容没有关系(文件的名字是目录的内容信息)

后缀名只是决定文件的打开方式

使用画图工具:
        1.bmp
    大小:300*300的24位位图
    理论大小:300*300*3 = 270000个字节
    实际大小:270,054
    54byte? 在bmp文件的头部,使用了54个字节保存了bmp图片的一些属性信息,如:深度,宽度,高度,大小....

     BMP大小 = 像素点的颜色数据 + 54 byte

        2.bmp
    大小:299*300的24位位图(水平 * 垂直)  
    理论大小:299*300*3 + 54 = 269,154个字节
    实际大小:270,054
    why???
   
windows规定bmp图片中,图片一行的像素点大小必须是4的整数倍,如果不是4的整数倍,则填充为4的整数倍(不解决癞子,显示的图片会发生倾斜)
    一行大小:299*3 = 897    =======>填充为900
    大小:900*300+54

        2.bmp
    大小:300*299的24位位图(水平 * 垂直)  
    理论大小:299*300*3 + 54 = 269,154个字节
    实际大小:269154

3. 把图片上传到开发板

在开发板设备上显示,则需要把图片上传到开发板

4. BMP图片的显示原理

从BMP图片文件中把所有的像素点的信息读取出来,解析出每一个点的颜色,把点描绘到指定的位置,就可以把图片显示出来了


步骤:
        1. 初始化LCD屏幕(打开屏幕+映射)
        2. 打开BMP图片
        3.
读取BMP图片的像素信息并解析   <------------
        4. 关闭BMP图片
        5. 把解析后的数据显示到屏幕对应的位置
   <------------

        6. 解映射
        7. 关闭LCD屏幕

bmp图片的存储是以小端模式存储的     
        存储的时候
                (高字节)RGB(低字节)
                  BGR         BGR        BGR
               第一个点   第二个点  第三个点  ......
        读取出来之后,buf就保存了所有像素点的信息(可能存在填充字节)

但是我们的LCD上面一个像素点的显示是AGRB
        BGR------>ARGB 
        位运算(&, |, ~, <<, >>, ^....)

图片显示到开发板上面其实是倒过来的
(54个字节中有一个位图高度,为负数就表示图片的像素是从第一行存储到最后一行--->从左至右,从上至下
        为正数就表示图片的像素是从最后一行存储到第一行--->从左至右,从下至上)
        很多图片存储的时候都是从下至上的,可以根据属性去判断

5. 练习

1. 显示一张bmp图片到开发板

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <unistd.h>

int main(int argc, char *argv[]) 
{
    // 1. 初始化LCD屏幕(打开屏幕+映射)
    int fd = open("/dev/fb0", O_RDWR);
    if (-1 == fd) 
    {
        perror("open lcd failed");
        return -1;
    }
    // plcd 指向了映射后的内存区域
    int *plcd = mmap(NULL, 800 * 480 * 4, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
    if (plcd == MAP_FAILED) 
    {
        perror("mmap failed");
        close(fd);
        return -1;
    }

    // 2. 打开BMP图片
    int fd_bmp = open(argv[1], O_RDONLY);
    if (-1 == fd_bmp) 
    {
        perror("open bmp failed");
        munmap(plcd, 800 * 480 *4);
        close(fd);
        return -1;
    }

    // 3. 读取BMP图片的像素信息并解析 
    // 小端模式
    // 第一种方法:
#if 0
    lseek(fd_bmp, 2, SEEK_SET);
    char buf0[4] = {0};
    int r_bmp = read(fd, buf0, 4);
    if (-1 == r_bmp) 
    {
        perror("read size failed");
        munmap(plcd, 800 * 480 *4);
        close(fd_bmp);
        close(fd);
        return -1;
    }
    // BMP文件的大小(单位为字节)
    int size = buf0[3] << 24 | buf0[2] << 16 | buf0[1] << 8 | buf0[0];

    lseek(fd_bmp, 0x12, SEEK_SET);
    r_bmp = read(fd_bmp, buf0, 4);
    if (-1 == r_bmp) 
    {
        perror("read w failed");
        munmap(plcd, 800 * 480 *4);
        close(fd_bmp);
        close(fd);
        return -1;
    }
    // 位图宽度
    int w = buf0[3] << 24 | buf0[2] << 16 | buf0[1] << 8 | buf0[0];

    r_bmp = read(fd_bmp, buf0, 4);
    if (-1 == r_bmp) 
    {
        perror("read h failed");
        munmap(plcd, 800 * 480 *4);
        close(fd_bmp);
        close(fd);
        return -1;
    }
    // 位图高度
    int h = buf0[3] << 24 | buf0[2] << 16 | buf0[1] << 8 | buf0[0];

    lseek(fd_bmp, 0x1c, SEEK_SET);
    r_bmp = read(fd_bmp, buf0, 2);
    if (-1 == r_bmp) 
    {
        perror("read colour failed");
        munmap(plcd, 800 * 480 *4);
        close(fd_bmp);
        close(fd);
        return -1;
    }
    // 位深
    int colour_dep = buf0[1] << 8 | buf0[0];

    lseek(fd_bmp, 0, SEEK_SET);

    char buf[800 * 480 * 4 + 54] = {0};
    r_bmp = read(fd_bmp, buf, 800 * 480 * 4 + 54);
    if (-1 == r_bmp) 
    {
        perror("read bmp failed");
        munmap(plcd, 800 * 480 *4);
        close(fd_bmp);
        close(fd);
        return -1;
    }
#endif

    // 第二种方法:
#if 1
    char buf[800 * 480 * 4 + 54] = {0};
    int r_bmp = read(fd_bmp, buf, 800 * 480 * 4 + 54);
    if (-1 == r_bmp) 
    {
        perror("read bmp failed");
        munmap(plcd, 800 * 480 *4);
        close(fd_bmp);
        close(fd);
        return -1;
    }
    int size = buf[5] << 24 | buf[4] << 16 | buf[3] << 8 | buf[2];
    int w = buf[21] << 24 | buf[20] << 16 | buf[19] << 8 | buf[18];
    int h = buf[25] << 24 | buf[24] << 16 | buf[23] << 8 | buf[22];
    int colour_dep = buf[29] << 8 | buf[28];
#endif

    // 大端模式
    // int size, w, h;
    // lseek(fd, 2, SEEK_SET);
    // read(fd, &size, 4);

    // lseek(fd, 0x12, SEEK_SET);
    // read(fd, &w, 4);

    // read(fd, &h, 4);

    // lseek(fd, 0, SEEK_SET);

    // 4. 关闭BMP图片
    close(fd_bmp);

    // 判断是否超出屏幕范围
    if (w > lp->xres || h > lp->yres)
    {
        printf("brother,Out of range\n");
        close(fd);
        return -1;
    }

    // 5. 把解析后的数据显示到屏幕对应的位置
    int k = 54;
    unsigned char a, r, g, b;
    /* 
        h<0:表示从上到下,从左到右存放数据
        h>0:表示从下到上,从左到右存放数据
    */
    printf("w = %d, h = %d\n", w, h);
    for (int j = h - 1; j >= 0; j--) // 图片有h行
    {
        // 显示当前行的每一个点
        for (int i = 0; i < w; i++) // 每一行w个点
        {
            // 解析每一个像素点
            b = buf[k++];
            g = buf[k++];
            r = buf[k++];
            a = (colour_dep == 32) ? buf[k++] : 0;
            int colour = (a << 24) | (r << 16) | (g << 8) | b;
            // 从(0, 0)开始
            *(plcd + j * 800 + i) = colour;
        }
        // 每一行完成之后,处理赖子
        if ((w * (colour_dep / 8)) % 4 != 0) 
        {
            k = k + 4 - (w * (colour_dep / 8)) % 4;
        }
    }

    // 6. 解映射
    munmap(plcd, 800 * 480 *4);

    // 7. 关闭LCD屏幕
    close(fd);

    return 0;
}
  • 10
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值