显示BMP图片

1.什么是BMP图片

1.1bmp概念

  • BMP是英文Bitmap(位图)的简写,它是(Windows操作系统)中的标准(图像文件格式),能够被多种Windows应用程序所支持。随着Windows操作系统的流行与丰富的Windows应用程序的开发,BMP(位图)格式理所当然地被广泛应用。这种格式的特点是包含的图像信息较丰富,几乎不进行压缩,但由此导致了它与生俱生来的缺点--占用(磁盘)空间过大。所以,目前BMP在单机上比较流行。
  • bmp图片像素排列方式为BGR
  • bmp文件的图像深度可选1bit、4bit、8bit、24bit。bmp格式图片的扫描方式为从左到右,从上到下
  • 使用bmp格式图片优点是可以很方便的得到图片像素数据,而jpg/jpeg格式需要先解压图像数据之后才可得到像素数据
  • 本平台在显示图片时选择24位位图格式
  • bmp图片前54字节不是图片数据,而是保存图片信息,例如图片名称,尺寸等
  • 所以一张bmp图片大小为800*480*3+54=1152054字节,没有透明度选项
  • 更多详细信息

1.2制作bmp图片

  • 首先下载图片,使用win自带的画图软件打开
  • 设置图片大小为800*480
  • 另存为bmp格式图片
  • 查看图片信息,可看到图片大小为1152054字节

1.3将bmp图片整到开发板上

  • 按照传统代码烧写方法,通过SecureCRT将bmp图片传输到开发板上,理论可行,然现实却需要等待若干小时。因为串口波特率为115200,即115200bit/s=112.5Byte/s=0.1kB/s,一张bmp图片大小在1M左右,可看出传输时间会非常慢
  • 鉴于以上原因,可通过U盘将图片传输到开发板上。前提是开发板已经安装好对应USB驱动
  • 将事先准备好的bmp图片拷贝到U盘上,再将U盘插到开发板上,可看到有以下信息,证明有USB设备插入且成果识别USB设备信息
[root@GEC6818 /IOT/home]#[ 1981.712000] usb 1-1.2: new high-speed USB device number 3 using nxp-ehci
[ 1981.789000] usb 1-1.2: New USB device found, idVendor=048d, idProduct=1234
[ 1981.790000] usb 1-1.2: New USB device strings: Mfr=1, Product=2, SerialNumber=3
[ 1981.798000] usb 1-1.2: Product: UDisk           
[ 1981.802000] usb 1-1.2: Manufacturer: General 
[ 1981.806000] usb 1-1.2: SerialNumber: Љ
[ 1981.813000] scsi0 : usb-storage 1-1.2:1.0
[ 1982.819000] scsi 0:0:0:0: Direct-Access     General  UDisk            5.00 PQ: 0 ANSI: 2
[ 1982.825000] sd 0:0:0:0: [sda] 32768000 512-byte logical blocks: (16.7 GB/15.6 GiB)
[ 1982.827000] sd 0:0:0:0: Attached scsi generic sg0 type 0
[ 1982.835000] sd 0:0:0:0: [sda] Write Protect is off
[ 1982.840000] sd 0:0:0:0: [sda] No Caching mode page present
[ 1982.844000] sd 0:0:0:0: [sda] Assuming drive cache: write through
[ 1982.855000] sd 0:0:0:0: [sda] No Caching mode page present
[ 1982.856000] sd 0:0:0:0: [sda] Assuming drive cache: write through
[ 1982.863000]  sda:
[ 1982.868000] sd 0:0:0:0: [sda] No Caching mode page present
[ 1982.870000] sd 0:0:0:0: [sda] Assuming drive cache: write through
[ 1982.875000] sd 0:0:0:0: [sda] Attached SCSI removable disk
  • 去到/mnt目录下可看到相关文件夹
[root@GEC6818 /IOT/home]#cd /mnt/
[root@GEC6818 /mnt]#ls
sd     udisk
[root@GEC6818 /mnt]#
  • 之后会惊喜地发现该文件夹下啥都没有^x^
[root@GEC6818 /mnt]#ls -l sd
total 0
[root@GEC6818 /mnt]#ls -l udisk/
total 0
[root@GEC6818 /mnt]#
  • 此处需要通过mount指令挂载U盘
# 创建挂载文件夹
[root@GEC6818 /mnt]#mkdir usb
[root@GEC6818 /mnt]#ls
sd     udisk  usb

# 挂载U盘,将dev目录下的设备文件sda映射到刚刚创建的usb文件夹下
[root@GEC6818 /mnt]#mount /dev/sda /mnt/usb/

# 此处进入usb文件下面,就可看到U盘内文件了
[root@GEC6818 /mnt]#cd usb/
[root@GEC6818 /mnt/usb]#ls
1.bmp
2.bmp
201730133027
3.bmp
????.pdf
????2020
?????
???????.pdf
????????.doc
??????????.docx
??Arduino.pdf
AT89C51 ?????????????
Alarms
Android
Bandicam???
Chinatelecom_JSPortal
DCIM
Download
EasyX_2018???.exe
Fritzing0.9.3b.dmg
LOST.DIR
Movies
Music
Notifications
Pictures
Podcasts
Processing.app
RavV17std.exe
Ringtones
System Volume Information
Wireless LAN_Atheros_12.0.0.191_W10x64_A.zip
[Beginning.Arduino].Michael.McRoberts.???.pdf
arduino-1.8.7-macosx.zip
arduino??????.pdf
hq.txt
liz.txt
processing-3.4-macosx.zip
processing-3.4-windows64.zip
record
video
[root@GEC6818 /mnt/usb]#
  • 最终通过cp指令就可随心所欲地copy了哈
  • 取消挂载指令为umount /mnt/usb,类似win上的弹出U盘

2.屏幕适配bmp图片

2.1适配方法

  • 由于bmp图片像素排列方式不为RGB,所以需要我们通过移位操作完成像素重新排列的操作
  • LCD屏像素排列为ARGB,bmp图片像素排列为BGR
  • 针对一个像素点,可通过移位操作将bmp像素排列改为LCD屏像素排列
/*bmp格式*/
B   G   R
/*LCD排列*/
A   R   G   B
/*bmp--->LCD*/
(R<<16)|(G<<8)|(B)

2.2示例代码

  • 循环显示图片
#include 
#include 
#include 
#include 

/*全局变量,保存内存映射后的地址*/
int *p = NULL;
/*全局变量,保存驱动文件设备描述符*/
int fd;
/*二维数组,保存图片名称*/
char pic[3][10] = {"1.bmp", "2.bmp", "3.bmp"};

/*LCD屏幕初始化,即进行打开显示驱动文件、内存映射等工作*/
int lcd_init(void)
{
    fd = open("/dev/fb0", O_RDWR);
    if(fd == -1)
    {
        printf("open file error\n");
        return -1;
    }
    /*内存映射*/
    p = mmap(NULL, 800 * 480 * 4, PROT_WRITE|PROT_READ, MAP_SHARED, fd, 0);
    if(p == NULL)
    {
        printf("mmap error\n");
        close(fd);
        return -1;
    }
    return 0;
}
/*描绘像素点,即告诉每个像素点对应该显示的色域值*/
void lcd_draw_point(int x, int y, int color)
{
    *(p + y * 800 + x) = color;
}
/*将图片从bmp格式转换为LCD屏的显示格式,操作单位是像素点*/
int lcd_draw_bmp(char *pic_name)
{
    /*打开bmp图片文件*/
    int pic_fd = open(pic_name, O_RDWR);
    /*给每张图片申请缓存地址,注意申请大小*/
    char pic_buff[800 * 480 * 3] = {0};
    /*保存R、G、B像素值,单位是1字节*/
    char red, green, blue;
    int color;
    int p = 0;
    if(pic_fd < 0)
    {
        printf("open picture error\n");
        return -1;
    }
    
    /*根据bmp格式,应该跳过前54字节的内容*/
    lseek(pic_fd, 54, SEEK_SET);
    /*将bmp图片中的像素内容写入缓存区*/
    read(pic_fd, pic_buff, 800 * 480 * 3);
    /*像素点移位,适配LCD屏幕格式*/
    for(int i = 0; i < 480; i++)
    {
        for(int j = 0; j < 800; j++)
        {
            /*读bmp像素点中的B色域*/
            blue = pic_buff[p++];
            /*读bmp像素点中的G色域*/
            green = pic_buff[p++];
            /*读bmp像素点中的R色域*/
            red = pic_buff[p++];
            /*移位操作将BGR转RGB,将转换后结果保存到color(4字节)中间变量中*/
            color = (blue) | (green<<8) | (red<<16);
            /*将移动好的像素值写入对应位置*/
            //lcd_draw_point(j, i, color);//BUG版本,此举图像将按照镜面方式显示
            lcd_draw_point(j, 479 - i, color);//修复版本,更改刷新方式为从左到右,从下往上
        }
    }
    close(pic_fd);
}
int main()
{
    if(lcd_init() != 0)
    {
        printf("lcd init error\n");
        close(fd);
        return -1;
    }
    while (1)
    {
        /*循环显示3张图片*/
        for(int i = 0; i < 3; i++)
        {
            lcd_draw_bmp(pic[i]);
            sleep(1);
        }
    }
    /*解除映射*/
    munmap(p, 800 * 480 * 4);
    /*指针置空,防止野指针出现*/
    p = NULL;
    return 0;
}

你可能感兴趣的:(显示BMP图片)