GEC6818的bmp图片显示

1、bmp概念

bitmap(位图)

.bmp图片与其它图片的区别
jpg/jpeg/png:这些图片都是经过数据压缩后的图片;如果直接读取,并不是图片的原始数据; 必须要先解压再读取。文件较小。
bmp:不采用任何压缩,存储的是图片原始数据;可以直接读取。文件较大。

大小(byte):800*480*3 + 54 = 1152000 + 54 = 1152054

说明:都出来的54个字节是bmp图片的头文件(包含图片的大小,格式等等)

bmp图片一个像素点的大小     24bit(3个字节)
说明:lcd一个像素点的大小是32bit(4个字节)

bmp图片一个像素点的组成方式
LCD:ARGB
BMP:RGB(少了一个透明度)

BMP文件开头部分是BMP格式头,里面存放了RGB数据的尺寸、分辨率、色深等重要信息。BMP格式头中包含了如下三个结构体:

  • bitmap_header(必有)
  • bitmap_info(必有)
  • rgb_quad(可选,一般没有)

 

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));

2、特殊规则

a. 4字节倍数行距
BMP图片文件的一个重要规则是,每行数据字节数必须是4的倍数,假设某BMP图片的分辨率是 65 × 200,也就是说宽是 65 像素,假设每个字节色深是24bits(即3字节),那么这张图片一行的实际数据量是 65×3=195个字节,但195不是4的倍数,因此在每一行的末尾都会添加一个无效字节,将行距尺寸补到196个字节。

处理的原则很简单,首先根据具体图片的尺寸和色深等信息,计算出一行中会出现的无效字节的个数(0-3个字节),计算公式参考:

int pad = ((4-( width * bpp/8 ) % 4)) % 4;
  • pad是最终计算得出的每一行的无效字节数,范围是0-3之间
  • width是图片的宽
  • bpp是图片的色深

在处理图像数据的时候,直接跳过这些无效字节就好了。

b. 上下颠倒
BMP图片中的RGB数据是上下颠倒的,因此文件数据中的最后一行是图像的最上面第一行。需要注意的是,上下是颠倒的,但是左右是正常的,因此在处理数据的时候不能从最后一个字节开始,而是从最末一行的首字节开始。

3、bmp图片读取步骤

1、打开lcd fd_lcd=open("/dev/fb0",O_RDWR);

2、内存映射 int* addr = mmap(NULL,大小,读写权限,分享权限,文件描述符,0);

3、打开bmp图读取数据 fd_bmp=open("bmp_name",O_RDWR);

4、跳过bmp图的头节点lseek(fd_bmp,54,SEEK_SET);

5、读取bmp的图片有效数据 char buf[800*480*3],read(fd_bmp,buf,800*480*3)

6、数据读取 *(addr+(479-y)*800+x) = buf[(y*800+x)*3+0] //B | (buf[(y*800+x)*3+1]<<8) //G | (buf[(y*800+x)*3+2]<<16); //R

7、取消内存映射munmap(addr,800*480*3)

8、关闭文件 close(fd_lcd) close(fd_bmp)

4、800*480bmp图片读取实现代码

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/mann.h>
#include<linux/input.h>

int main(int argc,char** argv)
{
    int fd_lcd,fd_bmp;
    int* addr = NULL;

    //1、打开lcd 
    fd_lcd=open("/dev/fb0",O_RDWR);
    if(fd_lcd == -1)
    {
        perror("open lcd fail");
        return -1;
    }

    //2、内存映射 int* addr = mmap(NULL,大小,读写权限,分享权限,文件描述符,0);
    addr = mmap(NULL,800*480*4,PROT_WRITE|PROT_READ,MAP_SHARED,fd_lcd,0);
    if(addr == NULL)    
    {
        perror("mmap addr fail");
        return -1;
    }

    //3、打开bmp图读取数据 
    fd_bmp=open("bmp_name",O_RDWR);    //这里的bmp_name为bmp图片的名字
    if(fd_bmp == -1)
    {
        perror("open bmp fail");
        return -1;
    }

    //4、跳过bmp图的头节点
    lseek(fd_bmp,54,SEEK_SET);

    //5、读取bmp的图片有效数据 
    char buf[800*480*3] = {0}; //只存储图片的有效数据
	read(fd_bmp,buf,800*480*3);

    //6、数据读取 bmp图是从下到上读取,所以从最后一行开始读取
    int x,y;
    for(x = 0;x < 800;x++)
    {
        for(y = 0;y < 480;y++)
        {
            *(addr + (479 - x)*800 + y) =  buf[(x * 800 + y)*3] | (buf[(x * 800 + y)*3 + 1] << 8) | (buf[(x * 800 + y) * 3 + 2] << 16) |  
        }
    }    

    //7、取消内存映射
    munmap(addr,800*480*3)

    //8、关闭LCD文件 
    close(fd_lcd)

    //9、关闭BMP文件
    close(fd_bmp);

    return 0;
}


//bmp图片的算法,不同显示方法
//方法一
for(x = 0;x < 480;x++)
	{
		for(z=0;z<=x;z++)
		{
			for(y = 0;y < 800;y++)
			{
				*(addr +(479-x)*800+y) = buf[(x*800+y)*3] | (buf[(x*800+y)*3+1] << 8) | (buf[(x*800+y)*3+2] << 16);
			}
		}
	}

//方法二
	for(y = 0;y < 800;y++)
	{
		for(z=0;z<=y;z++)
		{
			for(x = 0;x < 480;x++)
			{
				*(addr +(479-x)*800+y) = buf[(x*800+y)*3] | (buf[(x*800+y)*3+1] << 8) | (buf[(x*800+y)*3+2] << 16);
			}
		}
	}

//方法三
	for(y=799;y>=0;y--)
	{
		for(z=0;z<=y;z++)
			for(x=479;x>=0;x--)
			{
				*(addr +(479-x)*800+y) = buf[(x*800+y)*3] | (buf[(x*800+y)*3+1] << 8) | (buf[(x*800+y)*3+2] << 16);
			}
	}

5、任意大小bmp图片读取

格式跟读取800*480大小的bmp图类似,只需要添加获取bmp照片宽度和高度的代码,任意大小的bmp图片可以自己挑选出现的位置,但是要注意非法访问的情况,容易造成段错误。任意大小bmp图片制作的时候一定要注意宽度是4的倍数,但实际上我们使用bmp照片较少,因为占用空间大,占用硬件成本。

实现的代码如下:

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

int main(int argc,char **argv)
{
	//1、打开LCD
	int fd_lcd = open("/dev/fb0",O_RDWR);
	if(fd_lcd == -1)
	{
		perror("open lcd fail");
		return -1;
	}
	
	
	//2、LCD的映射--效率要高于LCD的读写
	int *addr = NULL;
	addr = mmap(NULL,800*480*4,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);
	if(addr == NULL)
	{
		perror("mmap fail");
		return -1;
	}
	
	//3、读取一张bmp图
	//制作照片时的宽度必须是4的倍数,否则要做像素点补偿
	int fd_bmp = open("zhu400_200.bmp",O_RDWR); 
	if(fd_bmp == -1)
	{
		perror("open bmp fail");
		return -1;
	}
	
	//4、读取任意bmp图片的分辨率(高度与宽度)
	int height=0;//高度
	int width=0;//宽度
	lseek(fd_bmp,18,SEEK_SET); 
	read(fd_bmp,&width,4); //读取它的宽度,读完之后此时指针已近偏移到第22个字节的位置
	read(fd_bmp,&height,4); 
	printf("width=%d height=%d\n",width,height);
	
	//5、去除掉头54个字节
	lseek(fd_bmp,54,SEEK_SET);
	char buf[height*width*3]; //只存储图片的有效数据
	read(fd_bmp,buf,height*width*3);    //柔性数组不能初始化

    //6、自己选择照片初始位置
	int offset_x=100;  //照片x轴的偏移位置
	int offset_y=100; //照片y轴的偏移位置
	
	//7、操作LCD这段映射内存空间
	int x,y;   
	for(y=0;y<height;y++)
	{
		for(x=0;x<width;x++)
		{	
			//照片最后一行起始点y轴坐标 offset_y+height
			//照片最后一行起始点x轴坐标 offset_x
			*(addr+(offset_y+height-1-y)*800+offset_x+x) = buf[(y*width+x)*3+0]
														| (buf[(y*width+x)*3+1]<<8)  
														| (buf[(y*width+x)*3+2<<16); 
		}		
	}		

	//8、LCD映射的释放
	munmap(addr,800*480*4);
	
	//9、关闭LCD
	close(fd_lcd);
	
	//10、关闭BMP
	close(fd_bmp);

	return 0;
}

  • 9
    点赞
  • 50
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值