粤嵌实习-学习bmp文件格式并解析一张bmp图片、交叉开发在开发板上显示一张图片

文章目录

  • 粤嵌实习(电梯运行演示系统)
  • 了解并使用bmp图片和交叉开发
  • bmp文件格式
  • 应用:读取一张图片的数据
  • 交叉开发:
  • 1.连接与配置
  • 2.在开发板上运行一个程序
  • 应用:读取图片的数据并显示到开发板上
  • 粤嵌实习(电梯运行演示系统)

    了解并使用bmp图片和交叉开发

    bmp文件格式

    bitmap文件头(14字节):

    偏移量 大小 用途
    0000H 2字节 用于标识BMP和DIB文件的魔数,一般为0x42 0x4D
    0002H 4字节 BMP文件的大小(单位为字节)
    0006H 2字节 保留,实际值因创建程序而异
    0008H 2字节 保留,实际值因创建程序而异
    000AH 4字节 位图数据(像素数组)的地址偏移,也就是起始地址。

    DIB头(40字节):

    偏移量 大小 用途
    OEH 4字节 该头结构的大小(40字节)
    12H 4字节 位图宽度,单位为像素(有符号整数)
    16H 4字节 位图宽度,单位为像素(有符号整数)
    1AH 2字节 色彩平面数,只有1为有效值
    1CH 2字节 每个像素所占位数,即图像的色深,典型值为1、4、8、16、24和32
    1EH 4字节 所使用的的压缩方法
    22H 4字节 图像大小。原指位图数据的大小,与文件大小不是同一概念
    26H 4字节 图像的横向分辨率,单位为像素每米(有符号整数)
    2AH 4字节 图像的纵向分辨率,单位为像素每米(有符号整数)
    2EH 4字节 调色板的颜色数,为0时表示颜色数为默认的2的色深数次方个
    32H 4字节 重要颜色数,为0时表示所有颜色都是重要的,通常不使用本项

    调色板(颜色值数组)

    像素数组:这部分逐个像素表示图像,每一个像素使用一个或多个字节表示。通常像素是从上到下,从左到右保存的。

    应用:读取一张图片的数据

    先在共享文件夹下存放一张图片。

    编写代码读取图片信息并打印。

    int fd = open("./kkk.bmp",O_RDONLY);//共享文件夹下的图片
     if(fd == -1)
     {
      perror("open bmp error:");
      return -1;
     }
    	unsigned char buf[64] = {0};
    	read(fd,buf,64);
    
     //操作
     //判断是否为BMP图片
     if(buf[0] != 0x42 || buf[1] != 0x4d)
     {
      printf("NO\n");
      close(fd);
      return -1;
     }
     printf("Yes\n");
    }
    
    
        //bmp图片信息的读取
    	int fd = open(bmpname,O_RDWR);
    	int size,width,high;
        short depth;     //两个字节
    	lseek(fd,2,SEEK_SET);
    	read(fd,&size,4);//读取图片的大小
    	lseek(fd,0x12,SEEK_SET);
    	read(fd,&width,4);//读取图片的宽度
    	lseek(fd,0x16,SEEK_SET);
    	read(fd,&high,4);//读取图片的高度
    	lseek(fd,0x1C,SEEK_SET);
    	read(fd,&depth,2);//读取图片的色深
    	printf("bmp size=%d width=%d high = %d depth=%d\n",size,width,high,depth);
    

    结果如下:

    交叉开发:

    1.连接与配置

    (1)连接好开发板,启动开发板。

    (2)打开设备管理器,查找识别出的端口号。

    ​ 若不能正确识别端口号,则需要安装驱动。

    (3)使用SecureCRT软件来对开发板进行终端控制。

    (4)打开SecureCRT.exe文件,连接开发板。

    连接成功:

    (5)创建工作文件夹。

    ①先删除home目录下的所有文件。

    cd /home 
    rm -rf *
    

    ②创建并进入自己的工作文件夹,下次使用开发板先进入此文件夹。

    mkdir /home/117
    cd /home/117
    

    如下:

    2.在开发板上运行一个程序

    (1)编辑一个C文件,并保存到共享文件夹中。

    (2)将其在虚拟机中编译成开发板上可执行文件。

    如:

    arm-linux-gcc hello.c -o hello
    

    (3)传送可执行文件到开发板上,并执行。

    rx 可执行文件名
    
    chmod 0777 可执行文件名
    
    ./可执行文件名
    

    应用:读取图片的数据并显示到开发板上

    开发板屏幕为800*480。

    定义BMP数据结构:

    //定义一个bmp图片信息相关的结构体类型
    typedef struct BMP
    {
        char* bmpname;          //保存bmp图片的名称
        int size;               //文件的总大小
        int width;              //文件的宽
        int height;             //文件的高
        short bpp;              //色深
        char* data;             //像素数组的首地址
    }BMP;
    

    定义相关要用到的函数:

    //屏幕初始化
    void lcd_init();
    //解除屏幕初始化
    void lcd_uninit();
    //画点
    void lcd_point(int x,int y,int color);
    //获取bmp图片信息
    BMP get_bmp_info(char* bmpname);
    //画一张bmp图片
    void lcd_draw_bmp(char* bmpname, int x, int y);
    

    全部写在bmp.h文件中,具体文件内容如下:

    #ifndef __BMP_H
    #define __BMP_H
    
    #include <stdio.h>
    #include <stdlib.h>
    //open
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <fcntl.h>
    //mmap
    #include <sys/mman.h>
    //close,read,write
    #include <unistd.h>
    
    //定义一个bmp图片信息相关的结构体类型
    typedef struct BMP
    {
        char* bmpname;          //保存bmp图片的名称
        int size;               //文件的总大小
        int width;              //文件的宽
        int height;             //文件的高
        short bpp;              //色深
        char* data;             //像素数组的首地址
    }BMP;
    
    //屏幕初始化
    void lcd_init();
    //解除屏幕初始化
    void lcd_uninit();
    //画点
    void lcd_point(int x,int y,int color);
    //获取bmp图片信息
    BMP get_bmp_info(char* bmpname);
    //画一张bmp图片
    void lcd_draw_bmp(char* bmpname, int x, int y);
    
    #endif
    

    ①读取所有像素点的信息。

    BMP get_bmp_info(char* bmpname)
    {
    	//可以下载其他格式的图片,在电脑自带的图片编辑中,将图片的像素进行调整,另存为bmp(24位)图片即可
    	//size --> 0x02 - 4字节   宽 --> 0x12 -- 4字节  高 ->> 0x16 -- 4字节      色深 ->> 0x1c -- 2字节
    	int fd_bmp = open(bmpname, O_RDONLY);//写入bmp文件名
    	if (fd_bmp == -1)
    	{
    		printf("open bmp error\n");
    		exit(1);
    	}
        //判断是否是bmp文件
    	char bm[2] = {0};
    	read(fd_bmp, bm, 2);
    	if (!(bm[0] == 'B' && bm[1] == 'M'))
    	{
    	printf("%s is not a bmp file\n", bmpname);
    	exit(1);
    	}
    	
    BMP bmp;
    bmp.bmpname = bmpname;
    
    //大小
    lseek(fd_bmp, 0x02, SEEK_SET);
    read(fd_bmp, &bmp.size, 4);
    
    //宽
    lseek(fd_bmp, 0x12, SEEK_SET);
    read(fd_bmp, &bmp.width, 4);
    //高
    read(fd_bmp, &bmp.height, 4);
    //色深
    lseek(fd_bmp, 0x1c, SEEK_SET);
    read(fd_bmp, &bmp.bpp, 2);
    
    //开辟一块空间用来保存像素数组
    bmp.data = (char*)malloc(bmp.size - 54);
    lseek(fd_bmp, 0x36, SEEK_SET);
    read(fd_bmp, bmp.data, (bmp.size-54));
    
    close(fd_bmp);
    return bmp;
    }
    

    ②将图片显示到开发板上。

    void lcd_draw_bmp(char* bmpname, int x, int y)
    {
    	BMP bmp = get_bmp_info(bmpname);
    	//打印图片的基本信息
    	printf("bmpname = %s, size = %d, width = %d, height = %d, bpp = %hd\n", 
    			bmp.bmpname, bmp.size, bmp.width, bmp.height, bmp.bpp);
    
    	//一行的有效字节数
    	int line_types = abs(bmp.width) * bmp.bpp / 8;
    
    	//一行的填充字节数
    	int pad_types = (line_types % 4 == 0) ? 0 : (4 - (line_types % 4));
    
    	int color;
    	char* p = bmp.data; //遍历指针,遍历整个像素数组
    
    	//解析像素数组中的数据并画到开发板上
    	for (int h = 0; h < abs(bmp.height); h++) //表示行
    	{
    		for (int w = 0; w < abs(bmp.width); w++) //表示列
    		{
    			char b = *(p++);
    			char g = *(p++);
    			char r = *(p++);
    			char a = (bmp.bpp == 24) ? 0 : *(p++);
    
    			color = a << 24 | r << 16 | g << 8 | b;
    
    			// width > 0 : 从左到右保存每一个像素点
                // width < 0 : 从右到左保存每一个像素点
    			// height > 0: 从下到上保存每一个像素点
                // height < 0: 从上到下保存每一个像素点
    
    			int m =x+(bmp.width>0?w:(bmp.width-1-w));
    			int n =y+(bmp.height<0?h:(bmp.height-1-h));
    
    			lcd_point(m, n, color);
    		}
    		p += pad_types;//跳过填充字节
    	}
    

    ③编译运行程序

    1.先在linux下编译程序。

    ​ 此处采用了gcc编译同时编译多个c文件,需将各个.c文件和.h文件放在同一个文件夹下。

    2.向工作文件夹中传入所需的图片(此处已经传入在开发板中文件名为bg1的图片bg1.bmp)

    3.传入并执行文件。

    4.结果如下:

    物联沃分享整理
    物联沃-IOTWORD物联网 » 粤嵌实习-学习bmp文件格式并解析一张bmp图片、交叉开发在开发板上显示一张图片

    发表评论