利用GEC6818屏幕 显示一张bmp图片

这时候有同学就会问,GEC6818是啥?不明白的同学可以去百度哈.....

为什么是显示bmp格式的图片呢?而不是常见的jpg格式的图片呢?

因为BMP格式是微软(MicroSoft)公司发明的数据封装格式,这种格式最大的特征是都没有任何的压缩,缺点文件尺寸都比较大,不适合在互联网上传播,所以在网上常见的是jpg这种经过压缩处理的图片,优点是数据读取出来即可使用,无需任何解码器支持。因此BMP格式文件内部存储的就是RGB数据,无需任何解码。

那怎么样才能将图片显示在屏幕上呢?

Linux下一切皆文件:

在Linux系统中,一个bmp格式的图片相当于一个存储着这张图片的RGB数据的文件,开发板的屏幕也相当于一个文件,而让bmp图片显示在屏幕上,不就是将图片文件的数据写在屏幕文件里面吗?就相当于抄作业、拷贝等类似的操作。

那怎么样把图片数据抄到屏幕上面呢?

一、打开bmp文件,利用open函数打开文件,不明白open函数怎么样,自行去查手册。

二、把bmp文件内容读取出来,用read函数读,那要读多少才合适呢?首先bmp图片是有一个个像素点组合而成的,一个像素点是3个字节,解析图如下,这个是从winhex软件看到的一个红色的bmp图片文件的数据,里面的RGB数据存放是反过来的实际上是BGR,文件的不全是存放着图片的RGB数据,在文件前54个字节里面存着图片高度宽度等信息。图中的蓝色框是RGB数据开始的地方,前面存的是图片的基本信息了。

读多少就得看前面文件头的图片信息了,在这里,我就不读了,自己定制一个800*480个像素大小的bmp图片,因为开发板的屏幕的分辨率就是800*480的,也就是屏幕的一行由800个像素点排列而成,宽度为480个像素点,而一个像素点由3个字节组成,所以要定义一个800*480*3个字节大小的数组例如

unsigned char bmpbuff[800*480*3] = {0};

 三、怎么把读到的数据放到屏幕文件呢?

同样第一步就是打开屏幕文件。

到这里说一下屏幕的像素点是四个字节的,ARGB前面的A的位置一般是保留为0的,所以只用后面三个字节RGB,这样就要定义800*480*4个字节大小的数组,刚好int 是4个字节,可以这样子定义

unsigned int buff[800*480] = {0};

传统的抄作业是一个个字地抄,如果用write函数的话,系统也会像小学生抄作业一样,一个一个地抄,这样就有一个缺点,会很慢,导致屏幕显示图片地时候要一段时间才能把图片完全显示出来,现在用一种相当于直接抄一页作业的方法,就是映射,相当于一张复印纸,直接一拍在作业上就把作业的所有内容都刻在一页纸上面,到时候屏幕显示图片的时候,不是一个个地写,就直接把照片贴上去,这样显得速度快多了。下面是申请的方法

 unsigned int  mem_p = (unsigned int *)mmap(NULL, 800*480*4, PROT_READ|PROT_WRITE, MAP_SHARED, lcd_fd, 0);

四、刚刚说到bmp图片的像素是3个字节的,而屏幕像素是4个字节的,虽然前面一个不用,但是还得要有的,而且bmp像素的RGB是反过来的,如图所示

所以就要把相对应的字节移位到字节相对应的位置,B位置不动,G左移1个字节就是8位,R左移2个字节就是16位,这样就能够刚刚好对应上屏幕像素点了。

buff[i] = bmpbuff[3*i+0] | bmpbuff[3*i+1]<<8 | bmpbuff[3*i+2]<<16; 

五、把申请的映射和两个打开i的文件关闭就OK了

munmap(mem_p, 800*480*4);

close(lcd_fd);

close(bmp_fd);

六、实现理论

注意的是要想在6818板上面运行程序,要使用交叉编译工具链,因为开发板用的是arm架构的,所以要用对的编译器编译出来的程序才能正常运行。下面我用下面的程序显示我们麦麦的图片



//显示一张800*480的图片
#include <stdio.h>
#include <dlfcn.h>  // 动态加载动态库的头文件:dlopen()、dlsym()
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <fcntl.h>
#include <stdbool.h>

#include <sys/stat.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <sys/mman.h>

// BMP格式头规范
struct bitmap_header
{
	int16_t type;
	int32_t size; // 图像文件大小
	int16_t reserved1;
	int16_t reserved2;
	int32_t offbits; // bmp图像数据偏移量
}__attribute__((packed));

struct bitmap_info
{
	int32_t size;   // 本结构大小	
	int32_t width;  // 图像宽
	int32_t height; // 图像高
	int16_t planes;

	int16_t bit_count; // 色深
	int32_t compression;
	int32_t size_img; // bmp数据大小,必须是4的整数倍
	int32_t X_pel;
	int32_t Y_pel;
	int32_t clrused;
	int32_t clrImportant;
}__attribute__((packed));

// 以下结构体不一定存在于BMP文件中,除非:
// bitmap_info.compression为真
struct rgb_quad
{
	int8_t blue;
	int8_t green;
	int8_t red;
	int8_t reserved;
}__attribute__((packed));


#define FB_FILE  "/dev/fb0"

unsigned int *mem_p;

int lcd_fd;

int lcd_init(void);
int lcd_uninit(void);
int show_bmp(const char *pathname);

int main(void)
{
    lcd_init();
    show_bmp("a.bmp");

    lcd_uninit();
    return 0;
}


int lcd_init(void)
{
    //打开file.txt文件, 文件不存在,则打开失败,如果使用O_CREAT,那必须要添加文件权限。
    lcd_fd = open(FB_FILE, O_RDWR);
    if(lcd_fd == -1)
    {
        printf("open a.txt fail\n");
        return -1;
    }   

    //屏幕映射
    mem_p = (unsigned int *)mmap(NULL, 800*480*4, PROT_READ|PROT_WRITE, MAP_SHARED, lcd_fd, 0);
    if(mem_p == MAP_FAILED)
    {
        printf("mmap fail\n");
    }

    return 0;
}
int lcd_uninit(void)
{
   // 解除映射
    munmap(mem_p, 800*480*4);
    close(lcd_fd);

}


int show_bmp(const char *pathname)
{
    int i, j, x, y;
    unsigned char bmpbuff[800*480*3] = {0};
    unsigned int buff[800*480] = {0};

	int bmp_fd = open(pathname, O_RDONLY);
    if(bmp_fd == -1)
    {
        printf("open bmp fail\n");
        return -1;
    }
    //跳过54个字节头
    lseek(bmp_fd, 54, SEEK_SET);

    read(bmp_fd, bmpbuff, sizeof(bmpbuff));

    for(i=0; i<800*480; i++)
    {
        //buff[0] = bmpbuff[0]<<16 | bmpbuff[1]<<8 | bmpbuff[2];
        buff[i] = bmpbuff[3*i+0] | bmpbuff[3*i+1]<<8 | bmpbuff[3*i+2]<<16;
    }

//显示图片(倒置:反过来的)
    for(y=0; y<480; y++)
    {
        for(x=0; x<800; x++)
        {
            *(mem_p+y*800+x) = buff[y*800+x];
        }

    }

    close(bmp_fd);

    return 0;
}

 

 

 发现我们麦麦的图片反过来显示了,看规律发现只是上下的位置倒过来了,左右的位置没有发生变化,方法思路如图所示

 

 以此类推,把上下行的数据倒过来放到屏幕文件里面进行了。

下面是倒置过来的全代码,可以看得出区别在哪里



//显示一张800*480的图片
#include <stdio.h>
#include <dlfcn.h>  // 动态加载动态库的头文件:dlopen()、dlsym()
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <fcntl.h>
#include <stdbool.h>

#include <sys/stat.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <sys/mman.h>

// BMP格式头规范
struct bitmap_header
{
	int16_t type;
	int32_t size; // 图像文件大小
	int16_t reserved1;
	int16_t reserved2;
	int32_t offbits; // bmp图像数据偏移量
}__attribute__((packed));

struct bitmap_info
{
	int32_t size;   // 本结构大小	
	int32_t width;  // 图像宽
	int32_t height; // 图像高
	int16_t planes;

	int16_t bit_count; // 色深
	int32_t compression;
	int32_t size_img; // bmp数据大小,必须是4的整数倍
	int32_t X_pel;
	int32_t Y_pel;
	int32_t clrused;
	int32_t clrImportant;
}__attribute__((packed));

// 以下结构体不一定存在于BMP文件中,除非:
// bitmap_info.compression为真
struct rgb_quad
{
	int8_t blue;
	int8_t green;
	int8_t red;
	int8_t reserved;
}__attribute__((packed));


#define FB_FILE  "/dev/fb0"

unsigned int *mem_p;

int lcd_fd;

int lcd_init(void);
int lcd_uninit(void);
int show_bmp(const char *pathname);

int main(void)
{
    lcd_init();
    show_bmp("a.bmp");

    lcd_uninit();
    return 0;
}


int lcd_init(void)
{
    //打开file.txt文件, 文件不存在,则打开失败,如果使用O_CREAT,那必须要添加文件权限。
    lcd_fd = open(FB_FILE, O_RDWR);
    if(lcd_fd == -1)
    {
        printf("open a.txt fail\n");
        return -1;
    }   

    //屏幕映射
    mem_p = (unsigned int *)mmap(NULL, 800*480*4, PROT_READ|PROT_WRITE, MAP_SHARED, lcd_fd, 0);
    if(mem_p == MAP_FAILED)
    {
        printf("mmap fail\n");
    }

    return 0;
}
int lcd_uninit(void)
{
   // 解除映射
    munmap(mem_p, 800*480*4);
    close(lcd_fd);

}


int show_bmp(const char *pathname)
{
    int i, j, x, y;
    unsigned char bmpbuff[800*480*3] = {0};
    unsigned int buff[800*480] = {0};

	int bmp_fd = open(pathname, O_RDONLY);
    if(bmp_fd == -1)
    {
        printf("open bmp fail\n");
        return -1;
    }
    //跳过54个字节头
    lseek(bmp_fd, 54, SEEK_SET);

    read(bmp_fd, bmpbuff, sizeof(bmpbuff));

    for(i=0; i<800*480; i++)
    {
        //buff[0] = bmpbuff[0]<<16 | bmpbuff[1]<<8 | bmpbuff[2];
        buff[i] = bmpbuff[3*i+0] | bmpbuff[3*i+1]<<8 | bmpbuff[3*i+2]<<16;
    }

//显示图片(倒置:反过来的)
    // for(y=0; y<480; y++)
    // {
    //     for(x=0; x<800; x++)
    //     {
    //         *(mem_p+y*800+x) = buff[y*800+x];
    //     }

    // }

//正显示图片

    for(y=0; y<480; y++)
    {
        for(x=0; x<800; x++)
        {
            *(mem_p+y*800+x) = buff[(479-y)*800+x];
        }
    }

    close(bmp_fd);

    return 0;
}

这样,我们的麦麦就正过来了

 虽然这是一个很简单的知识,也很容易去实现,但是今天我才真正如此清晰其中的步骤,千里之行始于足下,共勉respect!下一个目标,学会怎么利用字库,将中文显示在屏幕上。

 

  • 14
    点赞
  • 102
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 5
    评论
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

三目条件

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值