您当前的位置:首页 > 电子 > 嵌入式系统

粤嵌GEC6818实现图片显示

时间:03-12来源:作者:点击数:

要求

练习: 完成一张图片在板子上的显示

要求: 任意路径的图片

任意大小的图片

在板子上的任意位置显示

思路

	void show_bmp (char * pathname ,  int x,int y)
	{
		第一步:打开图片 ,读取宽度 高度 色深 
		
		第二步: 确定总字节数  然后malloc对应大小的内来保存这些颜色。unsigned char * p = malloc(total_bytes);
		
		//第三步: 打开帧缓冲设备  映射    init(); end();
		
		第四步: 把颜色的值写进去 要一个字节一个字节地写入 为什么呢?   
					因为32位和24位地A是不一样的。
					unsigned char a,r,g,b ;
					我们把前面保存的像素数组的对应内容 一个一个字节地给我的argb 。
					24位的像素数组只有RGB    a直接给0 
					32位的像素数组有a  需要给一个字节给a 
		
					每写完四个字节  写完一个argb 。 这四个字节是不是就是组成一个color ? 
					这个时候是不是就该调用我们draw_point函数。
		
		
		          注意: 每行跳过癞子。
				  
		第五步: 关闭图片 //关闭帧缓冲 解除映射
	}

代码

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <sys/mman.h>
#include <math.h>
#include <stdlib.h>
int * p = NULL ;

void draw_point(int x,int y,int color)
{
	if(x>=0 && x<800 && y>=0 && y<480 )
	{
		*(p+800*y+x) = color ;
	}
}
/*
函数功能:在屏幕的任意一个位置  显示任意一张  任意大小的bmp图片 
函数参数: 
		@pathname : 要显示的图片 的路径名 
		@x : 在屏幕X轴值为x的地方开始显示
		@y :  在屏幕Y轴值为y的地方开始显示
*/
void show_bmp (char * pathname ,int x ,int y)
{
	int fd = open(pathname,O_RDONLY);
	if(fd == -1)
	{
		perror("open error\n");
		return ;
	}
	int fd1 = open("/dev/fb0",O_RDWR);
	if(fd1 == -1)
	{
		perror("open error\n");
		return ;
	}
	printf("open success\n");
	
	p = mmap(NULL,800*480*4,PROT_READ | PROT_WRITE,MAP_SHARED ,fd1,0);
	if(p == NULL )
	{
		perror("mmap error\n");
		return ;
	}
	int width,height;
	short depth;
	unsigned char buf[4] ;
	//读取宽度
	lseek(fd,0x12,SEEK_SET);
	read(fd,buf,4);
	width = buf[3]<<24 | buf[2]<< 16 | buf[1] << 8 | buf[0];
	//读取高度
	read(fd,buf,4);
	height  = buf[3]<<24 | buf[2]<< 16 | buf[1] << 8 | buf[0];
	//读取色深
	lseek(fd,0x1c,SEEK_SET);
	read(fd,buf,2);
	depth = buf[1] << 8  | buf[0];
	//打印信息
	printf("width = %d  height = %d  depth = %d \n",width,height,depth);

	//像素数组 
	int line_valid_bytes = abs(width) * depth / 8 ; //一行本有的有效字节
	int laizi=0;//填充字节
	if( (line_valid_bytes % 4) !=0   )
	{
		laizi =  4 - line_valid_bytes%4;
	}
	int line_bytes = line_valid_bytes  +  laizi ;//一行所有的字节数
	
	int total_bytes = line_bytes * abs(height) ; //整个像素数组的大小
	
	unsigned char * p1  = malloc(total_bytes);
	
	lseek(fd,54,SEEK_SET);
	read(fd,p1,total_bytes);
	
	//调用draw_point 函数 。
	unsigned char a ,r ,g, b ;
	int i = 0;//用来做指针运动的
	int x0=0,y0=0; //用来循环计数
	int color ;
	for(y0=0;y0<abs(height);y0++)//画满每一列
	{
		for(x0=0;x0<abs(width);x0++)//画满每一行
		{
			//现在开始一个字节一个字节写入颜色
			// i++  先用后加     
			// ++i  先加后用
			b = p1[i++];
			g = p1[i++];
			r = p1[i++];
			if(depth == 32)
			{
				a=p1[i++];
			}
			if(depth == 24)
			{
				a = 0;
			}
			color = a << 24 | r << 16 | g << 8 | b ;
			draw_point(width>0?x+x0:abs(width)+x-1-x0,
					height>0? y+height-1-y0 : y+y0,color);
			
			
		}
		i = i +laizi ;//每一行后面的癞子数 跳过去。
			
	}
	free(p1);
	close(fd1);
	munmap(p,800*480*4);
	close(fd);
	
}
int main()
{
	show_bmp("1.bmp",-100 ,-100);
	//show_bmp("3.bmp",0,0);
	return 0;
}

具体步骤

1、读取文件设置缓冲区

int fd = open(pathname,O_RDONLY);
	if(fd == -1)
	{
		perror("open error\n");
		return ;
	}
	int fd1 = open("/dev/fb0",O_RDWR);
	if(fd1 == -1)
	{
		perror("open error\n");
		return ;
	}
	printf("open success\n");

2、测量待显示图片的宽度、高度、色深

p = mmap(NULL,800*480*4,PROT_READ | PROT_WRITE,MAP_SHARED ,fd1,0);
	if(p == NULL )
	{
		perror("mmap error\n");
		return ;
	}
	int width,height;
	short depth;
	unsigned char buf[4] ;
	//读取宽度
	lseek(fd,0x12,SEEK_SET);
	read(fd,buf,4);
	width = buf[3]<<24 | buf[2]<< 16 | buf[1] << 8 | buf[0];
	//读取高度
	read(fd,buf,4);
	height  = buf[3]<<24 | buf[2]<< 16 | buf[1] << 8 | buf[0];
	//读取色深
	lseek(fd,0x1c,SEEK_SET);
	read(fd,buf,2);
	depth = buf[1] << 8  | buf[0];
	//打印信息
	printf("width = %d  height = %d  depth = %d \n",width,height,depth);

  • BMP图片的显示 :
    bmp:bit map picture 位图
    bmp文件格式的图片, 没有经过任何压缩技术生成的图片。
    无压缩:保存了图片的每一个像素点的rgb颜色分量的值。
    我们按照bmp图片文件的固定的内容格式将他的数据读出来,进行一些简单的操作。我们就可以完成这个图片的显示。
    BMP图片文件格式:
    头两个字节 BM 我们是自己用BMP图片 所以就不用判定。
	宽度: 一行有多少个像素点:
			偏移量:0x12 
			大小: 4个字节
			可正可负 
			正负只表示一行像素点的存储方式
			为正说明行像素点是从左到右排列
			为负说明行像素点是从右往左排列
	高度: 一列有多少个像素点
			偏移量:0X16
			大小 : 4个字节
			可正可负 
			正负只表示一列像素点的存储方式
			为正说明行像素点是从下到上排列
			为负说明行像素点是从上往下排列
	色深: 每个像素所占的位数 bit  
			怎么求每个像素的大小?字节
				色深/8
			 24 
			 32  
			偏移量:0x1c
			大小: 2个字节

小端模式和大端模式

小端模式: 存储器(内存)的低地址 存放 寄存器(数据)的低地址字节

大端模式: 存储器(内存)的低地址 存放 寄存器(数据)的高地址字节

两者的区别就是 高字节位、低字节位存放次序不同;小端先存低,大端先存高,大端模式用于比较高端的场景,处理速度快。

	获取图片的宽度 高度 色深信息。
	思路: 
		int width,height;
		short depth;
		unsigned char buf[4];
		
	 第一步: 打开图片  open("./1.bmp")
	 第二步: lseek 偏移对应偏移量大小
			  read   读取对应数据大小的内容
			  。。。。。
	 第三步: 关闭图片

buf[4]

buf[0]  buf[1]  buf[2]  buf[3]  

我们真正想要的正确的数据是多少

buf[3]  buf[2]  buf[1]  buf[0] 



buf[0]  buf[1]  buf[2]  buf[3]  ---> buf[3]  buf[2]  buf[1]  buf[0] 

buf[3] << 24        buf[3]    _______    ________    _________  

buf[2] << 16       _________   buf[2]  __________  ___________

buf[1] << 8       __________  _______   buf[1]   ____________

buf[0]             _________  _________  ________     buf[0]


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

将图像字节写入一个数组

//像素数组 
	int line_valid_bytes = abs(width) * depth / 8 ; //一行本有的有效字节
	int laizi=0;//填充字节
	if( (line_valid_bytes % 4) !=0   )
	{
		laizi =  4 - line_valid_bytes%4;
	}
	int line_bytes = line_valid_bytes  +  laizi ;//一行所有的字节数
	
	int total_bytes = line_bytes * abs(height) ; //整个像素数组的大小
	
	unsigned char * p1  = malloc(total_bytes);
	

像素数组: 保存了图片像素点的所有argb颜色分量的值

	偏移量: 54
	大小:  ???
	
	大小需要根据宽度和高度和色深来求 。
	格式规定图片每行的字节数为4字节的倍数
	大小: 图片的宽度的绝对值   *  图片的高度的绝对值  *  色深/ 8
	if(depth == 32)
	{
		(图片的宽度的绝对值  *  32/ 8) % 4 一定为0 ;
	}
	
	if(depth == 24 )
	{
		(图片的宽度的绝对值  *  24 / 8)  % 4  不一定为 0 ;
	}

	是不是我们24位的图片就需要填充若干个字节 来满足每行大小为4字节倍数要求
	这些填充的字节数 我们叫癞子。
	
	那我们怎么求出每行的填充的字节数呢?癞子?
	
	int laizi;
	if (    ( 宽度*色深/8 ) %4  !=0    )
	{
		laizi = 4 -  宽度*色深/8 ) %4 ;
	}


	我真正意义上一行的字节数 是多少?   line_bytes = ( 宽度*色深/8 ) %4   +  laizi ;
	总共的字节数呢?     total_bytes = line_bytes * height 
	
	unsigned char * p = malloc(total_bytes);

将图像字节写入屏幕

void draw_point(int x,int y,int color)
{
	if(x>=0 && x<800 && y>=0 && y<480 )
	{
		*(p+800*y+x) = color ;
	}
}
lseek(fd,54,SEEK_SET);
	read(fd,p1,total_bytes);
	
	//调用draw_point 函数 。
	unsigned char a ,r ,g, b ;
	int i = 0;//用来做指针运动的
	int x0=0,y0=0; //用来循环计数
	int color ;
	for(y0=0;y0<abs(height);y0++)//画满每一列
	{
		for(x0=0;x0<abs(width);x0++)//画满每一行
		{
			//现在开始一个字节一个字节写入颜色
			// i++  先用后加     
			// ++i  先加后用
			b = p1[i++];
			g = p1[i++];
			r = p1[i++];
			if(depth == 32)
			{
				a=p1[i++];
			}
			if(depth == 24)
			{
				a = 0;
			}
			color = a << 24 | r << 16 | g << 8 | b ;
			draw_point(width>0?x+x0:abs(width)+x-1-x0,
					height>0? y+height-1-y0 : y+y0,color);
			
			
		}
		i = i +laizi ;//每一行后面的癞子数 跳过去。
			
	}

注意事项

  • bmp图片需要传在GEC818上
    在这里插入图片描述
  • 如果要显示两张图片改变两张图片的起始位置即可
    在这里插入图片描述
  • width>0?x+x0:abs(width)+x-1-x0
    当width>0,也就是从左到右时,横坐标位置为x+x0
    当width<0,也就是从右到左时,横坐标位置为abs(width)+x-1-x0`
    在这里插入图片描述


模块化思想: 
	
	。。。
	只有一个唯一的main函数‘
	一个或者多个功能函数 
	main.c
	lcd.c   lcd.h
	bmp.c   bmp.h
	led.c   led.h
	beef.c   beef.h
	.....
	
	
	
	.h怎么写? 
	例:led.h
	
	#ifndef  __LED_H__
	#define  __LED_H__
	
	
	// 变量的定义 
	// 函数的声明
	
	//。。。
	
	#endif
	
	
	
	功能函数: 封装一个函数 
	/*
		功能函数:对一个坐标点为(x,y)的像素点上色。
		参数: 
			@x : 像素点的X轴坐标值
			@y :像素点的Y轴坐标值
			@color : 要画的颜色
	*/
	void draw_point (  int x, int y, int color )
	{
		if(x>=0 && x<800 && y>=0 && y<480)
		*(p + 800*y +x ) = 0x00ff0000 ;//p定义成全局变量
	}
	 
	
	
	
	
BMP图片的显示 : 

	bmp:bit map picture 位图
	bmp文件格式的图片, 没有经过任何压缩技术生成的图片。
	无压缩:保存了图片的每一个像素点的rgb颜色分量的值。
	我们按照bmp图片文件的固定的内容格式将他的数据读出来,进行一些简单的操作。我们就可以完成这个图片的显示。
	
	
	BMP图片文件格式 
		见图:
		
		头两个字节  BM 我们是自己用BMP图片 所以就不用判定。
		
		
		宽度: 一行有多少个像素点: 
		
				偏移量:0x12 
				大小: 4个字节 
				
				可正可负 
				正负只表示一行像素点的存储方式
				为正说明行像素点是从左到右排列
				为负说明行像素点是从右往左排列
				
		高度: 一列有多少个像素点
			
				偏移量:0X16
				大小 : 4个字节
		
				可正可负 
				正负只表示一列像素点的存储方式
				为正说明行像素点是从下到上排列
				为负说明行像素点是从上往下排列
		
		
		色深: 每个像素所占的位数 bit  
				怎么求每个像素的大小?字节
					色深/8
				 
				 24 
				 32  
				 
				偏移量:0x1c
				大小: 2个字节
		
		
	小端模式和大端模式 
	小端模式: 存储器(内存)的低地址  存放 寄存器(数据)的低地址字节
	大端模式: 存储器(内存)的低地址  存放 寄存器(数据)的高地址字节
		
		练习: 获取图片的宽度 高度 色深信息。
		
		思路: 
			int width,height;
			short depth;
			unsigned char buf[4];
			
		 第一步: 打开图片  open("./1.bmp")
		 第二步: lseek 偏移对应偏移量大小
				  read   读取对应数据大小的内容
				  。。。。。
				  
				  
				  
				  
		
		 第三步: 关闭图片
		
		
			
	buf[4] 
	
	buf[0]  buf[1]  buf[2]  buf[3]  
	
	我们真正想要的正确的数据是多少
	
	buf[3]  buf[2]  buf[1]  buf[0] 



	buf[0]  buf[1]  buf[2]  buf[3]  ---> buf[3]  buf[2]  buf[1]  buf[0] 
	
	buf[3] << 24        buf[3]    _______    ________    _________  
	
	buf[2] << 16       _________   buf[2]  __________  ___________
	
	buf[1] << 8       __________  _______   buf[1]   ____________
	
	buf[0]             _________  _________  ________     buf[0]
 	
	
	width = buf[3] << 24 | buf[2] << 16 | buf[1] << 8  | buf[0] 
	
	同样的方法求高度 色深...
	
	见code  : 
	
	
	像素数组: 保存了图片像素点的所有argb颜色分量的值
	
		偏移量: 54
		大小:  ???
		
		大小需要根据宽度和高度和色深来求 。
		
		大小: 图片的宽度的绝对值   *  图片的高度的绝对值  *  色深/ 8
		if(depth == 32)
		{
			(图片的宽度的绝对值  *  32/ 8) % 4 一定为0 ;
		}
		
		if(depth == 24 )
		{
			(图片的宽度的绝对值  *  24 / 8)  % 4  不一定为 0 ;
		}
	
		是不是我们24位的图片就需要填充若干个字节 来满足每行大小为4字节倍数要求
		这些填充的字节数 我们叫癞子。
		
		那我们怎么求出每行的填充的字节数呢?癞子?
		
		int laizi;
		if (    ( 宽度*色深/8 ) %4  !=0    )
		{
			laizi = 4 -  宽度*色深/8 ) %4 ;
		}
	
	
		我真正意义上一行的字节数 是多少?   line_bytes = ( 宽度*色深/8 ) %4   +  laizi ;
		总共的字节数呢?     total_bytes = line_bytes * height 
		
		unsigned char * p = malloc(total_bytes);
	
	
	练习: 完成一张图片在板子上的显示
			要求: 任意路径的图片 
					任意大小的图片
					在板子上的任意位置显示 
					
		void show_bmp (char * pathname ,  int x,int y)
		{
			第一步:打开图片 ,读取宽度 高度 色深 
			
			第二步: 确定总字节数  然后malloc对应大小的内来保存这些颜色。unsigned char * p = malloc(total_bytes);
			
			//第三步: 打开帧缓冲设备  映射    init(); end();
			
			第四步: 把颜色的值写进去 要一个字节一个字节地写入 为什么呢?   
						因为32位和24位地A是不一样的。
						unsigned char a,r,g,b ;
						我们把前面保存的像素数组的对应内容 一个一个字节地给我的argb 。
						24位的像素数组只有RGB    a直接给0 
						32位的像素数组有a  需要给一个字节给a 
			
						每写完四个字节  写完一个argb 。 这四个字节是不是就是组成一个color ? 
						这个时候是不是就该调用我们draw_point函数。
			
			
			          注意: 每行跳过癞子。
					  
			第五步: 关闭图片 //关闭帧缓冲 解除映射
			
			
		}
	

效果图

在这里插入图片描述
方便获取更多学习、工作、生活信息请关注本站微信公众号城东书院 微信服务号城东书院 微信订阅号
推荐内容
相关内容
栏目更新
栏目热门