嵌入式Linux小项目之图片编解码播放器(3)

一、BMP图片的显示

1、图片文件的本质

(1)二进制文件

  文件分2种:2进制文件和文本文件,压缩包也属于二进制文件。

  二进制即010101,文本即ASCII编码,计算机中所有数据本质上都是数字0和1,如果我们将一个文件以数字进行解析,那其就是二进制文件,若我们按照ASCII编码的方式去解析,那它就是文本文件。

  图片本质是二进制文件,我们可以借助一些查看二进制文件的工具去打开它,比如WinHex。
在这里插入图片描述
(2)不同格式的图片文件的差别

(3)BMP图片的基本特征:未被压缩的元素位图格式,这里的位图是指用二进制位的方式一位一位表示图片。
  .jpg格式一种经过压缩的图片格式,占用空间较小相对BMP格式而言。不同的格式有不同的特点。

2、BMP图片详解

(1)BMP文件如何识别:每种图片格式都有定义好的一种识别方法,BMP图片特征是以0x424D开头,B对应的ASCII码值为42,M对应的ASCII码值为4D
在这里插入图片描述
(2)BMP文件组成:头信息(BMP图片的一些属性,如分辨率)+有效信息(所有的像素数据)

3、BMP文件头、信息头、图片有效数据区

1dword=4字节
在这里插入图片描述

4、写代码解析BMP图片

第一步:打开BMP图片
第二步:判断图片格式是否真是BMP
第三步:解析头信息,得到该BMP图片的详细信息
第四步:根据第三步得到的信息,去合适位置提取真正的有效图片信息
第五步:将得到的有效数据丢到fb中去显示

5、解析BMP文件头

参考学习:https://blog.csdn.net/ybhuangfugui/article/details/110458541

(1)用数组方式进行解析

//参数列表:path:要解析的图片的文件名
//函数功能  :解析bmp图片,并将解析出的数据放到bmp_buf[]数组中
//返回值     :错误时返回-1,正确时返回0
int bmp_analyze(char *path)
{
	int ret, fd = -1;
	unsigned char buf[54] = {0};//用于存储读取的bmp文件的头信息
							    //之所以大小设为54是根据bmp文件的	
								//头信息组成的各部分的大小决定的	


	//第一步:打开BMP图片
	fd = open(path, O_RDONLY);
	if (fd < 0)
	{
		//fprintf函数格式化输出到一个流文件中		
		fprintf(stderr,"open %s error.\n", path);
		return -1;
	}


	//第二步:判断图片格式是否真是BMP
	ret = read(fd, buf, 54);
	if (ret != 54)
	{
		fprintf(stderr,"read file header error.\n");
		close(fd);
		return -1;
	}


	//第三步:解析头信息,得到该BMP图片的详细信息
	printf("%x %x.\n", buf[0], buf[1]);
	if((buf[0] != 'B') || (buf[1] != 'M'))
	{
		fprintf(stderr,"file %s is not a bmp picture.\n", path);
		close(fd);
		return -1;
	} 


	//第四步:根据第三步得到的信息,去合适位置提取真正的有效图片信息
	printf("%s is a real bmp picture.\n", path);
	printf("width is %u\n", *((unsigned int*)(buf+0x12)));
	printf("height is %u\n", *((unsigned int*)(buf+0x16)));
	

	//第五步:将得到的有效数据丢到fb中去显示	


	//第六步:关闭打开的文件
	close(fd);
	
	return 0;
}

(2)用结构体方式

typedef struct tagBITMAPFILEHEADER
{
	//unsigned short      bfType;//文件的标识,值必须是0x4D42(也就是“BM”两个字符,注意是Little-Endian)
	unsigned long       bfSize;//是整个文件的大小
	unsigned short      bfReserved1;//bfReserved1和bfReserved2必须是0.
	unsigned short      bfReserved2;//bfReserved1和bfReserved2必须是0.
	unsigned long       bfOffBits;//是位图数据在文件中的偏移
} BITMAPFILEHEADER, *PBITMAPFILEHEADER;

	BITMAPFILEHEADER fHeader;
	unsigned short temp;
	
	//第一步:打开BMP图片
	fd = open(path, O_RDONLY);
	if (fd < 0)
	{
		//fprintf函数格`式化输出到一个流文件中		
		fprintf(stderr,"open %s error.\n", path);
		return -1;
	}

	//第二步:读取bmp文件头部信息,得到该BMP图片的详细信息
	read(fd, &temp, sizeof(temp));//跳过开头的两个字节,避免结构体对齐带来的影响
	read(fd, &fHeader, sizeof(fHeader));//读取文件头
	printf("bfSize = %ld.\n", fHeader.bfSize);
	printf("bfOffBits = %d.\n", fHeader.bfOffBits);

6、解析BMP文件的信息头

//BMP图像信息头
typedef struct tagBITMAPINFOHEADER
{
	unsigned long       biSize;//BITMAPINFOHEADER这个结构体的大小。必须为40(字节
	long                biWidth;//BMP位图的宽度
	long                biHeight;//BMP位图的高度
	unsigned short      biPlanes;//位图的“位面数”。这个值必须为1.
	unsigned short      biBitCount;//位图的“颜色位数”,颜色位数为1表示单色(其实是“双色”,通常是黑白,也可以是别的两个颜色。)为2表示四色,也就是四种颜色。为4表示16种颜色。为8表示有256种颜色。
	unsigned long       biCompression;//位图的压缩格式
	unsigned long       biSizeImage;//位图数据块的大小。以字节为单位。如果你的位图没有经过压缩,这个值可以是0.
	long                biXPelsPerMeter;//表示横向的每米的像素数。可以为0.
	long                biYPelsPerMeter;//表示纵向的每米的像素数。可以为0.
	unsigned long       biClrUsed;//位图实际使用过的调色板的颜色数。如果这个值为0,表示这个位图使用了整个调色板。只有8位以及8位以下的索引颜色位图才需要考虑这个值。
	unsigned long       biClrImportant;//指定重要的颜色数
} BITMAPINFOHEADER, *PBITMAPINFOHEADER;
	BITMAPINFOHEADER info;

	read(fd, &info, sizeof(info));//读取信息头
	printf("picture resolution:%d*%d.\n", info.biWidth, info.biHeight);
	printf("picture bpp:%d.\n", info.biBitCount);

7、BMP图片的显示

	//第三步:根据第二步得到的信息,去合适位置提取真正的有效图片信息
	//先将文件指针移动到有效信息所在的偏移量bfOffBits处
	//然后读出(info.biWidth*info.biHeight*info.biBitCount/3)字节大小的数据
	lseek(fd, fHeader.bfOffBits, SEEK_SET);
	len = info.biWidth*info.biHeight*info.biBitCount/3;
	read(fd, &bmp_buf, len);

	
	//第四步:将得到的有效数据丢到fb中去显示	
	lcd_display_picture(0, 0, bmp_buf, info.biWidth, info.biHeight);
//因为该BMP图片数据的存储方式是自底至上,与之前使用软件得到的自上至底的数据是不同的
//故显示函数也需要做出一定的改变
void lcd_display_picture(int x0, int y0, const unsigned char *pData, long width, long height)
{
	unsigned int x, y, color, p = 0;

	p = width*height*3-3 ;
		
	for(y = y0; y < (height+y0); y++)
	{
		if(y > HEIGHT)
			break;
		for(x = x0; x < (width+x0); x++)
		{
			if(x > WIDTH)
			{
				p += 3;
				continue;
			}	
			color = ((pData[p+2] << 16)|(pData[p+1] << 8)|(pData[p+0] << 0));//得到图片一个像素点的颜色
			*(pfb + y * WIDTH + x) = color;//将图片像素点的颜色填充到LCD屏幕的某个像素点上
			p -= 3;
		}

	}

	printf("lcd_display_picture ending.\n");

}

注:本资料大部分由朱老师物联网大讲堂课程笔记整理而来并且引用了部分他人博客的内容,如有侵权,联系删除!水平有限,如有错误,欢迎各位在评论区交流。

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

小嵌同学

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

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

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

打赏作者

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

抵扣说明:

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

余额充值