Day5_BMP

BMP图片显示

微软公司制定的一种无压缩的图片文件格式

Jpeg jpg压缩的图片格式

btimap文件,文件中保存的是每一个像素点的颜色值。

BMP文件的具体格式,如下:

1.BITMAP文件头

image-20220520094201105

固定大小:14字节

判断魔数,防止”挂羊头卖狗肉“。

参考代码:

//1.打开图片
int fd = open(bmp_file,O_RDONLY);
if(-1 == fd)
{
  printf("%s",bmp_file);
  perror("open fail");
  return ;
}
//2.判断到底是不是一张bmp图片
char buf[2]={0};
read(fd,buf,2);
if(buf[0]!=0x42 || buf[1]!=0x4D)
{
  printf("NOT BMP\n");
  return ;
}

2.DIB头

image-20220520095049684

固定大小:40字节

包含图片的属性

image-20220520095247847

计算机中数据存储有两种方式:

小端模式:低地址存放低字节

大端模式:低地址存放高字节

image-20220520095858789

位图宽度:4个字节 位于0x12

解析宽度的参考代码

char buf[4]={0};
lseek(fd,0x12,SEEK_SET);
read(fd,buf,4);

int width = buf[3]<<24 | buf[2]<<16 | buf[1]<<8 | buf[0];

width>0 每一行的像素点是由左到右来保存的

width<0 每一行的像素点是由右到左来保存的

位图高度:4个字节 位于0x16。

解析高度的参考代码:

lseek(fd,0x16,SEEK_SET);
read(fd,buf,4);

int height = buf[3]<<24 | buf[2]<<16 | buf[1]<<8 | buf[0];

height>0 从下到上保存每一行

height<0 从上到下保存每一行

色深:每个像素所占位数

Depth == 1 颜色值占1个bit位
	1
  0
depth == 4 颜色值4个bit位
	0000 ~ 1111  表示16种颜色 
...
	1010 是什么颜色??? 调色板
depth == 24 颜色值占24bit,3个字节,标准色RGB
depth == 32 ARGB 0x12345678

3.调色板(颜色值数组)

image-20220520101546295

当色深为24或32,不需要调色板。

默认只支持24或32的图片

4.像素点数组

保存的是每一行的每一个像素点的颜色值。

只考虑色深为24或32的情况,像素数组位于文件偏移量为(14+40=54字节的地方)。

有效像素数组占多大的空间
abs(width)*abs(height)*depth/8
为了保证每行数据的字节数是4的倍数,可能会在每一行末尾填充“赖子”。
int line_vaild_bytes=abs(width)*depth/8;
int line_bytes;//一行总字节数=有效字节数+赖子数
int laizi = 0;

if(line_vaild_bytes%4)
{
  laizi = 4 - line_vaild_bytes%4;
}
line_bytes = line_vaild_bytes + laizi;
int total_bytes = line_bytes*abs(height);//整个像素数组的大小

//从文件中读取像素数组
lseek(fd,54,SEEK_SET);
unsigned char piexl[total_bytes];
read(fd,piexl,total_bytes);

在屏幕上一一显示

image-20220520103008420

image-20220520103328457

image-20220520105803012

unsigned char a,r,g,b;
int color;
int i=0;
int x,y;
//遍历整个像素数组
for(y=0;y<abs(height);y++)
{
  for(x=0;x<abs(width);x++)
  {
    b=piexl[i++];
    g=piexl[i++];
    r=piexl[i++];
    if(depth==32)
    {
      a=piexl[i++];
    }
    else
    {
      a=0;//不透明
    }
    color=a<<24|r<<16|g<<8|b;
    Lcd_draw_point(width>0?x+x0:x0+abs(width)-x-1,
          heitht>0?y0+abs(height)-y-1:y0+y,color,plcd);
	}
  //每一行末尾可能存在赖子
  i+=laizi;
}

5.使用U盘来传输文件

使用rx来传输文件的特点:

慢,很慢,特别慢,数据容易丢失。

使用U盘来传输文件:

设备:U盘,要求文件系统格式为FAT32
注意:开发板不支持中文。所以文件不要包含中文字符,不然会显示乱码。
a.复制到U盘中。
b.把U盘插入开发板。
c.在CRT输入cd /mnt/udisk
d.ls 查看U盘里面的文件,如果说查看不到那就是挂载失败,考虑换一个U盘。
e.把文件复制(移动)到开发板
	cp:cp 1.c /LJ 复制1.c到/LJ
		  cp -r 文件夹的名字 /LJ
	mv:move 
			和cp的用法一样
image-20220520141134555

练习

image-20220520144556523

提示

"/LJ/1.bmp" 路径名 字符串 
char * s= "/LJ/1.bmp";
需要存储多个路径呢?
char *bmp_path[]={"/LJ/1.bmp","/LJ/2.bmp",...};//字符串数组
bmp_path[0] <==>"/LJ/1.bmp"
/*头文件*/
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <sys/mman.h>
#include <stdlib.h>

/*宏定义*/
#define FILE_PATH "/dev/fb0"

/*函数声明*/
int *Init_LCD(int *fd);
void Uninit_LCD(int fd,int *plcd);
void Lcd_draw_point(int x,int y,int color,int *plcd);
int Bmp_display(const char *bmp_file,int x0,int y0,int *plcd);


int main(int argc,char **argv)
{
	int fd=-1;
	int* plcd = Init_LCD(&fd);

	int x,y;
    char* str[]={"1.bmp","2.bmp","3.bmp","4.bmp","5.bmp","6.bmp","7.bmp","8.bmp","9.bmp","10.bmp"};
	//初始化屏幕
    for(y=0;y<480;y++)
	{
		for(x=0;x<800;x++)
		{
			Lcd_draw_point(x,y,0x58962564,plcd);
		}
	}
    long int i=0;
    while(1)
    { 
        i=random()%10;
        Bmp_display("start.bmp",300,180,plcd);
        sleep(0.5);
        Bmp_display(str[i],0,0,plcd);
        Bmp_display("start.bmp",300,180,plcd);
        sleep(1);
    }
	
	
	Uninit_LCD(fd,plcd);
}

/*
	Init_LCD:初始化显示屏
	参数为空
	返回值 int*
		成功 返回映射区域的首地址
		失败 返回NULL
*/
int *Init_LCD(int *fd)
{
	//1.打开帧缓冲
	*fd = open("/dev/fb0",O_RDWR);
	if(-1 == *fd)
	{

		perror("open fail");
		return NULL;
	}
	//2.映射
	int *plcd = mmap(NULL,800*480*4
			,PROT_READ |  PROT_WRITE,
			MAP_SHARED,*fd,0);
	if(MAP_FAILED == plcd)
	{
		perror("mmap fail");
		return NULL;
	}
	return plcd;
}

/*
	Uninit_LCD:解初始化屏幕
	@fd:帧缓冲的文件描述符
	@plcd:
	返回值:无
*/
void Uninit_LCD(int fd,int *plcd)
{
	//1.解映射
	munmap(plcd,800*480*4);
	//2.关闭帧缓冲
	close(fd);
}

void Lcd_draw_point(int x,int y,int color,int *plcd)
{
    if(NULL == plcd)
    {
        printf("error:plcd == NULL\n");
        return ;
    }
    if(x>=0&&x<800&&y>=0&&y<480)
    {
   		*(plcd+800*y+x) = color;
	}
}

/*
	Bmp_display:在屏幕的指定的位置显示bmp图片
	@bmp_file:图片的路径名
	@x0 y0 图片左上角在屏幕上的坐标
	@plcd:帧缓冲映射区域的首地址
	返回值:
		-1 失败
		0  成功
*/
int Bmp_display(const char *bmp_file,int x0,int y0,int *plcd)
{
	if(plcd == NULL || !(x0>=0&&x0<800&&y0>=0&&y0<480))
	{
		return -1;
	}
	//1.打开图片
	int fd = open(bmp_file,O_RDONLY);
	if(-1 == fd)
	{
		printf("%s",bmp_file);
		perror("open fail");
		return -1;
	}
	//2.判断到底是不是一张bmp图片
	char buf[4]={0};
	read(fd,buf,2);
	if(buf[0]!=0x42 || buf[1]!=0x4D)
	{
		printf("NOT BMP\n");
		close(fd);
		return -1;
	}
	//3.解析图片 宽 高 色深
	lseek(fd,0x12,SEEK_SET);
	read(fd,buf,4);
	int width = buf[3]<<24 | buf[2]<<16 | buf[1]<<8 | buf[0];

	lseek(fd,0x16,SEEK_SET);
	read(fd,buf,4);
	int height = buf[3]<<24 | buf[2]<<16 | buf[1]<<8 | buf[0];

	lseek(fd,0x1c,SEEK_SET);
	read(fd,buf,2);
	short depth = buf[1]<<8 | buf[0];

	if(!(depth == 24 || depth == 32))
	{
		printf("NOT SUPPORT!\n");
		close(fd);
		return -1;
	}

	printf("%s:%d*%d depth:%d\n",bmp_file,width,height,depth);
	//4.获取像素数组
	int line_vaild_bytes=abs(width)*depth/8;
	int line_bytes;//一行总字节数=有效字节数+赖子数
	int laizi = 0;

	if(line_vaild_bytes%4)
	{
		laizi = 4 - line_vaild_bytes%4;
	}
	line_bytes = line_vaild_bytes + laizi;
	int total_bytes = line_bytes*abs(height);//整个像素数组的大小

	//从文件中读取像素数组
	lseek(fd,54,SEEK_SET);
	unsigned char piexl[total_bytes];
	read(fd,piexl,total_bytes);
	//5.在屏幕的对应位置显示即可
	unsigned char a,r,g,b;
	int color;
	int i=0;
	int x,y;
	//遍历整个像素数组
	for(y=0;y<abs(height);y++)
	{
  		for(x=0;x<abs(width);x++)
  		{
			b=piexl[i++];
			g=piexl[i++];
			r=piexl[i++];
    		if(depth==32)
			{
				a=piexl[i++];
			}
    		else
			{
				a=0;//不透明
			}
    		color=a<<24|r<<16|g<<8|b;
    		Lcd_draw_point(width>0?x+x0:x0+abs(width)-x-1,
          	height>0?y0+abs(height)-y-1:y0+y,color,plcd);
		}
  		//每一行末尾可能存在赖子
  		i+=laizi;
	}
	close(fd);
	return 0;
}

bmp文件格式

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值