bmp图片编程一

一、bmp图片编程

任务:在开发板上显示一张800*480的24位的bmp图片。

1、思路

1)、打开液晶屏文件  
2)、打开bmp图片文件  
3)、读取bmp图片的数据   
4)、写入到液晶屏上  
5)、关闭液晶屏文件、bmp图片文件

2、分析bmp图片格式

(1)液晶屏的像素点格式:

首先,图片也是由像素点组成的。

(2)BMP(Bitmap)图像文件格式:

        它采用位映射存储格式,除了图像深度可选以外,不采用其他任何压缩,因此,BMP文件所占用的空间很大。BMP文件的图像深度可选lbit、4bit、8bit及24bitBMP文件存储数据时,图像的扫描方式是按从左到右、从下到上的顺序

(3)格式组成:

典型的BMP图像文件由四部分组成:

1:位图头文件数据结构,它包含BMP图像文件的类型、显示内容等信息;

2:位图信息数据结构,它包含有BMP图像的宽、高、压缩方法,以及定义颜色等信息;

3:调色板,这个部分是可选的,有些位图需要调色板,有些位图,比如真彩色图(24位的BMP)就不需要调色板;

4:位图数据,这部分的内容根据BMP位图使用的位数不同而不同,在24位图中直接使用RGB,而其他的小于24位的使用调色板中颜色索引值。

(4)格式类型:

        位图一共有两种类型,即:设备相关位图(DDB)和设备无关位图(DIB)。DDB位图在早期的Windows系统(Windows 3.0以前)中是很普遍的,事实上它也是唯一的。然而,随着显示器制造技术的进步,以及显示设备的多样化,DDB位图的一些固有的问题开始浮现出来了。比如,它不能够存储(或者说获取)创建这张图片的原始设备的分辨率,这样,应用程序就不能快速的判断客户机的显示设备是否适合显示这张图片。为了解决这一难题,微软创建了DIB位图格式。

        设备无关位图 (Device-Independent Bitmap)

        DIB位图包含下列的颜色和尺寸信息:

        * 原始设备(即创建图片的设备)的颜色格式。

        * 原始设备的分辨率。

        * 原始设备的调色板

        * 一个位数组,由红、绿、蓝(RGB)三个值代表一个像素。

(5)对应数据结构:

1:BMP文件组成

BMP文件由文件头、位图信息头、颜色信息和图形数据四部分组成。

2:BMP文件头(14字节

BMP文件头数据结构含有BMP文件的类型、文件大小和位图起始位置等信息。

3:位图信息头(40字节

BMP位图信息头数据用于说明位图的尺寸等信息。

5:位图数据

位图数据记录了位图的每一个像素值,记录顺序是在扫描行内是从左到右,扫描行之间是从下到上。位图的一个像素值所占的字节数:

当biBitCount=1时,8个像素占1个字节;

当biBitCount=4时,2个像素占1个字节;

当biBitCount=8时,1个像素占1个字节;

当biBitCount=24时,1个像素占3个字节,按顺序分别为B,G,R;

Windows规定一个扫描行所占的字节数必须是

4的倍数(即以long为单位),不足的以0填充,

biSizeImage = ((((bi.biWidth * bi.biBitCount) + 31) & ~31) / 8) * bi.biHeight;

(6)位图文件(*.BMP)的格式:

位图文件主要分为如下3个部分:

        1)文件信息头(BITMAPFILEHEADER

        结构体定义如下:

typedef struct tagBITMAPFILEHEADER { /* bmfh */
UINT bfType;  
DWORD bfSize; 
UINT bfReserved1; 
UINT bfReserved2; 
DWORD bfOffBits;
} BITMAPFILEHEADER;

        其中:

        2)位图信息头(BITMAPINFOHEADER

        结构体定义如下:

typedef struct tagBITMAPINFOHEADER { /* bmih */
DWORD biSize; 
LONG biWidth; 
LONG biHeight; 
WORD biPlanes; 
WORD biBitCount; 
DWORD biCompression; 
DWORD biSizeImage; 
LONG biXPelsPerMeter; 
LONG biYPelsPerMeter; 
DWORD biClrUsed; 
DWORD biClrImportant;
} BITMAPINFOHEADER;

        其中:

        3)RGB颜色阵列

        有关RGB三色空间我想大家都很熟悉,这里我想说的是在Windows下,RGB颜色阵列存储的格式其实BGR。也就是说,对于24位的RGB位图像素数据格式是:

对于32位的RGB位图像素数据格式是:

        透明通道也称Alpha通道,该值是该像素点的透明属性,取值在0(全透明)到255(不透明)之间。对于24位的图像来说,因为没有Alpha通道,故整个图像都不透明。

        由以上,可知我们24位bmp(1个像素点占3个字节)图片格式如下:

3、解决bmp转液晶屏格式

解决的问题:如何将bmp图片中的每个像素点 B G R 的颜色顺序 转换成 A R G B。

步骤:

(1)首先,将 R 左移 16 位,得到如下:

(2)其次,就要将 G 左移 8 位 ,得到如下:

(3)剩下的 B,不需要再移了,那么接下来就如何把他们凑在一起了,将三个进行位或操作即可:

(4)因为液晶屏还有一个 A,所以需要考虑如何将三个字节变成四个字节,0x00即8位,将其左移24位,再位或上上面的即可:

        那么就解决了像素点的颜色转换。

(5)一个像素点的转换:

(6)每个像素点怎么实现颜色转换:

int i,j;
char bmpbuf[800*480*3];
int tempbuf[800*480];

for(i=0,j=0; i<800*480; i++,j+=3)
{
    tempbuf[i] = (0x00<<24) | (bmpbuf[j+2]<<16) | (bmpbuf[j+1]<<8) | (bmpbuf[j]);
}

(7)因为图像的扫描方式是按从左到右,从下到上的顺序,那么我们读取得时候就需要反过来(头尾180度颠倒):

//3、读取bmp图片的数据
	char bmpbuf[800*480*3]={0};
	read(bmpfd,bmpbuf,800*480*3);
	//将bmp图片每个像素点的 B G R -->A R G  B
	for(i=0,j=0; i<800*480;i++,j+=3)
	{
		tempbuf[i] = 0x00<<24 | bmpbuf[j+2]<<16 | bmpbuf[j+1]<<8 | bmpbuf[j];
	}
	//上下180度颠倒 
	for(j=0; j<480; j++)
	{
		for(i=0; i<800; i++)
		{
			lcd_p[j*800+i] = tempbuf[(479-j)*800+i];
		}
	}

二、练习

1、练习1

        将bmp图片显示的源码封装成 一个 函数接口,并且把之前的内存映射加上来。

//在(0,0)的位置上显示一张800*480的图片
int showBmp(char *bmpPath)
{
	int i,j;
	int tempbuf[800*480];
	int lcdbuf[800*480];
	
	//2、打开bmp图片文件  
	int bmpfd = open(bmpPath,O_RDONLY);
	if(bmpfd == -1)
	{
		perror("open bmpfile error");//perror将错误的原因打印出来
		return -1;
	}
	
	//读取bmp图片的文件头 + 信息头数据
	BITMAPFILEHEADER fileHead;
	BITMAPINFOHEADER infoHead;
	
	read(bmpfd,&fileHead,14);//读取14个字节
	read(bmpfd,&infoHead,40);//读取40个字节
	
	//判断是否宽度等于 800 
	if(BMP_WIDTH != getBmpWidth(&infoHead))
	{
		printf("你要打印的图片宽度 不等于 800 请重新修改图片 error\n");
		//5、bmp图片文件	
		close(bmpfd);
		return -1;
	}
	//判断是否高度等于 480
	if(BMP_HEIGHT != getBmpHeight(&infoHead))
	{
		printf("你要打印的图片高度 不等于 480 请重新修改图片 error\n");
		//5、bmp图片文件	
		close(bmpfd);
		return -1;
	}
	
	//3、读取bmp图片的数据
	char bmpbuf[800*480*3]={0};
	read(bmpfd,bmpbuf,800*480*3);
	//将bmp图片每个像素点的 B G R -->A R G  B
	for(i=0,j=0; i<800*480;i++,j+=3)
	{
		tempbuf[i] = 0x00<<24 | bmpbuf[j+2]<<16 | bmpbuf[j+1]<<8 | bmpbuf[j];
	}
	//上下180度颠倒 
	for(j=0; j<480; j++)
	{
		for(i=0; i<800; i++)
		{
			lcd_p[j*800+i] = tempbuf[(479-j)*800+i];
		}
	}
	
	close(bmpfd);
}

2、练习2

        将图片进行切割,也就是将一张 800*480的图片 切割成 200*120 图片 在(0,0)上显示。

//在(0,0)的位置上显示一张800*480切割4倍后的200*120的图片
int showBmp_solv(char *bmpPath)
{
	int i,j;
	int tempbuf[800*480];
	int lcdbuf[800*480];
	int minbuf[200*120];
	
	//2、打开bmp图片文件  
	int bmpfd = open(bmpPath,O_RDONLY);
	if(bmpfd == -1)
	{
		perror("open bmpfile error");//perror将错误的原因打印出来
		return -1;
	}
	
	//读取bmp图片的文件头 + 信息头数据
	BITMAPFILEHEADER fileHead;
	BITMAPINFOHEADER infoHead;
	
	read(bmpfd,&fileHead,14);//读取14个字节
	read(bmpfd,&infoHead,40);//读取40个字节
	
	//判断是否宽度等于 800 
	if(BMP_WIDTH != getBmpWidth(&infoHead))
	{
		printf("你要打印的图片宽度 不等于 800 请重新修改图片 error\n");
		//5、bmp图片文件	
		close(bmpfd);
		return -1;
	}
	//判断是否高度等于 480
	if(BMP_HEIGHT != getBmpHeight(&infoHead))
	{
		printf("你要打印的图片高度 不等于 480 请重新修改图片 error\n");
		//5、bmp图片文件	
		close(bmpfd);
		return -1;
	}
	
	//3、读取bmp图片的数据
	char bmpbuf[800*480*3]={0};
	read(bmpfd,bmpbuf,800*480*3);
	//将bmp图片每个像素点的 B G R -->A R G  B
	for(i=0,j=0; i<800*480;i++,j+=3)
	{
		tempbuf[i] = 0x00<<24 | bmpbuf[j+2]<<16 | bmpbuf[j+1]<<8 | bmpbuf[j];
	}
	//上下180度颠倒 
	for(j=0; j<480; j++)
	{
		for(i=0; i<800; i++)
		{
			lcdbuf[j*800+i] = tempbuf[(479-j)*800+i];
		}
	}
	//切割算法 
	//思路:每隔4行取一行像素,在每一行中,每4个像素点取一个像素点
	//将lcdbuf --> 800*480  切割成  200*120 存储到 minbuf
	for(j=0; j<120; j++)
	{
		for(i=0; i<200; i++)
		{
			minbuf[j*200+i] = lcdbuf[j*4*800+i*4]; //i == 0 4 8 12 16
		}
	}
	//切割之后的数据存储在 minbuf ---200*120
	//显示 ,赋值到 lcd_p
	for(j=0; j<120; j++)
	{
		for(i=0; i<200; i++)
		{
			lcd_p[j*800+i] = minbuf[j*200+i];
		}
	}
	
	close(bmpfd);
}

3、练习3

        在指定的位置(posX,posY)上显示 一张切割后的图片。

//在(posX,posY)的位置上显示一张800*480切割4倍后的200*120的图片
//
int showBmp_solv_xy(char *bmpPath,int posX,int posY)
{
	int i,j;
	int tempbuf[800*480];
	int lcdbuf[800*480];
	int minbuf[200*120];
	
	//2、打开bmp图片文件  
	int bmpfd = open(bmpPath,O_RDONLY);
	if(bmpfd == -1)
	{
		perror("open bmpfile error");//perror将错误的原因打印出来
		return -1;
	}
	
	//读取bmp图片的文件头 + 信息头数据
	BITMAPFILEHEADER fileHead;
	BITMAPINFOHEADER infoHead;
	
	read(bmpfd,&fileHead,14);//读取14个字节
	read(bmpfd,&infoHead,40);//读取40个字节
	
	//判断是否宽度等于 800 
	if(BMP_WIDTH != getBmpWidth(&infoHead))
	{
		printf("你要打印的图片宽度 不等于 800 请重新修改图片 error\n");
		//5、bmp图片文件	
		close(bmpfd);
		return -1;
	}
	//判断是否高度等于 480
	if(BMP_HEIGHT != getBmpHeight(&infoHead))
	{
		printf("你要打印的图片高度 不等于 480 请重新修改图片 error\n");
		//5、bmp图片文件	
		close(bmpfd);
		return -1;
	}
	
	//3、读取bmp图片的数据
	char bmpbuf[800*480*3]={0};
	read(bmpfd,bmpbuf,800*480*3);
	//将bmp图片每个像素点的 B G R -->A R G  B
	for(i=0,j=0; i<800*480;i++,j+=3)
	{
		tempbuf[i] = 0x00<<24 | bmpbuf[j+2]<<16 | bmpbuf[j+1]<<8 | bmpbuf[j];
	}
	//上下180度颠倒 
	for(j=0; j<480; j++)
	{
		for(i=0; i<800; i++)
		{
			lcdbuf[j*800+i] = tempbuf[(479-j)*800+i];
		}
	}
	//切割算法 
	//思路:每隔4行取一行像素,在每一行中,每4个像素点取一个像素点
	//将lcdbuf --> 800*480  切割成  200*120 存储到 minbuf
	for(j=0; j<120; j++)
	{
		for(i=0; i<200; i++)
		{
			minbuf[j*200+i] = lcdbuf[j*4*800+i*4]; //i == 0 4 8 12 16
		}
	}
	//切割之后的数据存储在 minbuf ---200*120
	//显示 ,赋值到 lcd_p
	//在指定的位置(posX,posY)上显示
	for(j=0; j<120; j++)
	{
		for(i=0; i<200; i++)
		{
			//lcd_p[posY*800+posX+j*800+i] = minbuf[j*200+i];
			lcd_p[(posY+j)*800+i+posX] = minbuf[j*200+i];
		}
	}
	
	close(bmpfd);
}

4、综合

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

#include <sys/mman.h>
#include <stdbool.h>

#define UINT  unsigned short
#define DWORD unsigned  int
#define LONG unsigned  int
#define WORD unsigned short

#define BMP_WIDTH 	800
#define BMP_HEIGHT 	480


int lcdfd;
int *lcd_p;

//前面14个字节 文件信息头
typedef struct tagBITMAPFILEHEADER{
	UINT bfType;  //2
	DWORD bfSize; //DWORD 4
	UINT bfReserved1; //2
	UINT bfReserved2; //2
	DWORD bfOffBits; //DWORD 4
}BITMAPFILEHEADER;

//40个字节 位图信息头
typedef struct tagBITMAPINFOHEADER{ /* bmih */
	DWORD biSize; //DWORD 4
	LONG biWidth; //4  图像的宽度
	LONG biHeight;//4  图像的高度
	WORD biPlanes; //2
	WORD biBitCount;//2 
	DWORD biCompression; //DWORD 4
	DWORD biSizeImage; //DWORD 4
	LONG biXPelsPerMeter;//4
	LONG biYPelsPerMeter;//4
	DWORD biClrUsed; //DWORD 4
	DWORD biClrImportant; //DWORD 4
}BITMAPINFOHEADER;

//得到bmp图片的宽度
int getBmpWidth(BITMAPINFOHEADER *head)
{
	printf("Width:%d\n",head->biWidth);//图像的宽度
	return head->biWidth;
}
//得到bmp图片的高度
int getBmpHeight(BITMAPINFOHEADER *head)
{
	printf("Height:%d\n",head->biHeight);//图像的高度
	return head->biHeight;
}
//得到bmp图片的大小
int getBmpSize(BITMAPINFOHEADER *head)
{
	printf("fileSize:%d\n",head->biSizeImage+54);//文件的大小
	return head->biSizeImage+54;
}
//初始化液晶屏 和 内存映射
bool initLcdAndMmap()
{
	//1、打开液晶屏文件  
	lcdfd = open("/dev/fb0",O_RDWR);
	if(lcdfd == -1)
	{
		perror("open lcd error");//perror将错误的原因打印出来
		return false;
	}
	//将液晶屏文件 通过内存映射mmap的方式 映射到虚拟内存空间的某一块空间上,得到这一块内存的起始地址,后续我们操作这片内存空间,就相当于直接操作液晶屏文件
	lcd_p = mmap(NULL, //你要映射的内存空间的起始地址,为NULL系统自动给你分配
		 800*480*4,//你要映射的内存空间的大小
		 PROT_READ|PROT_WRITE,//映射的权限 
		 MAP_SHARED,//1、进程共享  2、对应的文件会同步发生变化 	
		 lcdfd,//映射液晶屏文件
		 0//偏移量 ,默认为0
		);
	if(lcd_p == MAP_FAILED)	
	{
		printf("mmap lcd error\n");
		return false;
	}
	
	return true;
}
//解除初始化
void uinitLcd()
{
	//解除映射
	munmap(lcd_p, 800*480*4);
	//5、关闭液晶屏文件、bmp图片文件	
	close(lcdfd);
}

//在(0,0)的位置上显示一张800*480的图片
int showBmp(char *bmpPath)
{
	int i,j;
	int tempbuf[800*480];
	int lcdbuf[800*480];
	
	//2、打开bmp图片文件  
	int bmpfd = open(bmpPath,O_RDONLY);
	if(bmpfd == -1)
	{
		perror("open bmpfile error");//perror将错误的原因打印出来
		return -1;
	}
	
	//读取bmp图片的文件头 + 信息头数据
	BITMAPFILEHEADER fileHead;
	BITMAPINFOHEADER infoHead;
	
	read(bmpfd,&fileHead,14);//读取14个字节
	read(bmpfd,&infoHead,40);//读取40个字节
	
	//判断是否宽度等于 800 
	if(BMP_WIDTH != getBmpWidth(&infoHead))
	{
		printf("你要打印的图片宽度 不等于 800 请重新修改图片 error\n");
		//5、bmp图片文件	
		close(bmpfd);
		return -1;
	}
	//判断是否高度等于 480
	if(BMP_HEIGHT != getBmpHeight(&infoHead))
	{
		printf("你要打印的图片高度 不等于 480 请重新修改图片 error\n");
		//5、bmp图片文件	
		close(bmpfd);
		return -1;
	}
	
	//3、读取bmp图片的数据
	char bmpbuf[800*480*3]={0};
	read(bmpfd,bmpbuf,800*480*3);
	//将bmp图片每个像素点的 B G R -->A R G  B
	for(i=0,j=0; i<800*480;i++,j+=3)
	{
		tempbuf[i] = 0x00<<24 | bmpbuf[j+2]<<16 | bmpbuf[j+1]<<8 | bmpbuf[j];
	}
	//上下180度颠倒 
	for(j=0; j<480; j++)
	{
		for(i=0; i<800; i++)
		{
			lcd_p[j*800+i] = tempbuf[(479-j)*800+i];
		}
	}
	
	close(bmpfd);
}

//在(0,0)的位置上显示一张800*480切割4倍后的200*120的图片
int showBmp_solv(char *bmpPath)
{
	int i,j;
	int tempbuf[800*480];
	int lcdbuf[800*480];
	int minbuf[200*120];
	
	//2、打开bmp图片文件  
	int bmpfd = open(bmpPath,O_RDONLY);
	if(bmpfd == -1)
	{
		perror("open bmpfile error");//perror将错误的原因打印出来
		return -1;
	}
	
	//读取bmp图片的文件头 + 信息头数据
	BITMAPFILEHEADER fileHead;
	BITMAPINFOHEADER infoHead;
	
	read(bmpfd,&fileHead,14);//读取14个字节
	read(bmpfd,&infoHead,40);//读取40个字节
	
	//判断是否宽度等于 800 
	if(BMP_WIDTH != getBmpWidth(&infoHead))
	{
		printf("你要打印的图片宽度 不等于 800 请重新修改图片 error\n");
		//5、bmp图片文件	
		close(bmpfd);
		return -1;
	}
	//判断是否高度等于 480
	if(BMP_HEIGHT != getBmpHeight(&infoHead))
	{
		printf("你要打印的图片高度 不等于 480 请重新修改图片 error\n");
		//5、bmp图片文件	
		close(bmpfd);
		return -1;
	}
	
	//3、读取bmp图片的数据
	char bmpbuf[800*480*3]={0};
	read(bmpfd,bmpbuf,800*480*3);
	//将bmp图片每个像素点的 B G R -->A R G  B
	for(i=0,j=0; i<800*480;i++,j+=3)
	{
		tempbuf[i] = 0x00<<24 | bmpbuf[j+2]<<16 | bmpbuf[j+1]<<8 | bmpbuf[j];
	}
	//上下180度颠倒 
	for(j=0; j<480; j++)
	{
		for(i=0; i<800; i++)
		{
			lcdbuf[j*800+i] = tempbuf[(479-j)*800+i];
		}
	}
	//切割算法 
	//思路:每隔4行取一行像素,在每一行中,每4个像素点取一个像素点
	//将lcdbuf --> 800*480  切割成  200*120 存储到 minbuf
	for(j=0; j<120; j++)
	{
		for(i=0; i<200; i++)
		{
			minbuf[j*200+i] = lcdbuf[j*4*800+i*4]; //i == 0 4 8 12 16
		}
	}
	//切割之后的数据存储在 minbuf ---200*120
	//显示 ,赋值到 lcd_p
	for(j=0; j<120; j++)
	{
		for(i=0; i<200; i++)
		{
			lcd_p[j*800+i] = minbuf[j*200+i];
		}
	}
	
	close(bmpfd);
}
//在(posX,posY)的位置上显示一张800*480切割4倍后的200*120的图片
//
int showBmp_solv_xy(char *bmpPath,int posX,int posY)
{
	int i,j;
	int tempbuf[800*480];
	int lcdbuf[800*480];
	int minbuf[200*120];
	
	//2、打开bmp图片文件  
	int bmpfd = open(bmpPath,O_RDONLY);
	if(bmpfd == -1)
	{
		perror("open bmpfile error");//perror将错误的原因打印出来
		return -1;
	}
	
	//读取bmp图片的文件头 + 信息头数据
	BITMAPFILEHEADER fileHead;
	BITMAPINFOHEADER infoHead;
	
	read(bmpfd,&fileHead,14);//读取14个字节
	read(bmpfd,&infoHead,40);//读取40个字节
	
	//判断是否宽度等于 800 
	if(BMP_WIDTH != getBmpWidth(&infoHead))
	{
		printf("你要打印的图片宽度 不等于 800 请重新修改图片 error\n");
		//5、bmp图片文件	
		close(bmpfd);
		return -1;
	}
	//判断是否高度等于 480
	if(BMP_HEIGHT != getBmpHeight(&infoHead))
	{
		printf("你要打印的图片高度 不等于 480 请重新修改图片 error\n");
		//5、bmp图片文件	
		close(bmpfd);
		return -1;
	}
	
	//3、读取bmp图片的数据
	char bmpbuf[800*480*3]={0};
	read(bmpfd,bmpbuf,800*480*3);
	//将bmp图片每个像素点的 B G R -->A R G  B
	for(i=0,j=0; i<800*480;i++,j+=3)
	{
		tempbuf[i] = 0x00<<24 | bmpbuf[j+2]<<16 | bmpbuf[j+1]<<8 | bmpbuf[j];
	}
	//上下180度颠倒 
	for(j=0; j<480; j++)
	{
		for(i=0; i<800; i++)
		{
			lcdbuf[j*800+i] = tempbuf[(479-j)*800+i];
		}
	}
	//切割算法 
	//思路:每隔4行取一行像素,在每一行中,每4个像素点取一个像素点
	//将lcdbuf --> 800*480  切割成  200*120 存储到 minbuf
	for(j=0; j<120; j++)
	{
		for(i=0; i<200; i++)
		{
			minbuf[j*200+i] = lcdbuf[j*4*800+i*4]; //i == 0 4 8 12 16
		}
	}
	//切割之后的数据存储在 minbuf ---200*120
	//显示 ,赋值到 lcd_p
	//在指定的位置(posX,posY)上显示
	for(j=0; j<120; j++)
	{
		for(i=0; i<200; i++)
		{
			//lcd_p[posY*800+posX+j*800+i] = minbuf[j*200+i];
			lcd_p[(posY+j)*800+i+posX] = minbuf[j*200+i];
		}
	}
	
	close(bmpfd);
}

int main(int argc,char*argv[])
{
	if(argc<2)// ./showbmp  2.bmp
	{
		printf("请把图片的名字传递进来,argv[1]现在是空的\n");
		return -1;
	}
	//初始化
	if(!initLcdAndMmap()) //if(initLcdAndMmap() = false)
	{
		//如果初始化失败
		printf("initLcdAndMmap error\n");
		return -1;
	}
	//showBmp_solv(argv[1]);
	showBmp_solv_xy(argv[1],300,200);
	//sleep(3);
	//showBmp(argv[2]);	
	
	//解除初始化
	uinitLcd();

	return 0;
}

5、作业

        加上触摸屏的代码,实现 点击 左边显示 上一张图片, 点击右边 显示 下一张图片
            char bmpName[3][256] = {"1.bmp","2.bmp","3.bmp"};

        如果当前显示的是1.bmp, 点击左边 显示 最后一张3.bmp   点击右边,显示 2.bmp。

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

#include <sys/mman.h>
#include <stdbool.h>



#include <linux/input.h>//触摸屏头文件

#define UINT  unsigned short
#define DWORD unsigned  int
#define LONG unsigned  int
#define WORD unsigned short

#define BMP_WIDTH 	800
#define BMP_HEIGHT 	480

#define BMP_NUMBER	5

int lcdfd;
int *lcd_p;

//前面14个字节 文件信息头
typedef struct tagBITMAPFILEHEADER{
	UINT bfType;  //2
	DWORD bfSize; //DWORD 4
	UINT bfReserved1; //2
	UINT bfReserved2; //2
	DWORD bfOffBits; //DWORD 4
}BITMAPFILEHEADER;

//40个字节 位图信息头
typedef struct tagBITMAPINFOHEADER{ /* bmih */
	DWORD biSize; //DWORD 4
	LONG biWidth; //4  图像的宽度
	LONG biHeight;//4  图像的高度
	WORD biPlanes; //2
	WORD biBitCount;//2 
	DWORD biCompression; //DWORD 4
	DWORD biSizeImage; //DWORD 4
	LONG biXPelsPerMeter;//4
	LONG biYPelsPerMeter;//4
	DWORD biClrUsed; //DWORD 4
	DWORD biClrImportant; //DWORD 4
}BITMAPINFOHEADER;

//得到bmp图片的宽度
int getBmpWidth(BITMAPINFOHEADER *head)
{
	printf("Width:%d\n",head->biWidth);//图像的宽度
	return head->biWidth;
}
//得到bmp图片的高度
int getBmpHeight(BITMAPINFOHEADER *head)
{
	printf("Height:%d\n",head->biHeight);//图像的高度
	return head->biHeight;
}
//得到bmp图片的大小
int getBmpSize(BITMAPINFOHEADER *head)
{
	printf("fileSize:%d\n",head->biSizeImage+54);//文件的大小
	return head->biSizeImage+54;
}
//初始化液晶屏 和 内存映射
bool initLcdAndMmap()
{
	printf("initLcdAndMmap start.......\n");
	//1、打开液晶屏文件  
	lcdfd = open("/dev/fb0",O_RDWR);
	if(lcdfd == -1)
	{
		perror("open lcd error");//perror将错误的原因打印出来
		return false;
	}
	//将液晶屏文件 通过内存映射mmap的方式 映射到虚拟内存空间的某一块空间上,得到这一块内存的起始地址,后续我们操作这片内存空间,就相当于直接操作液晶屏文件
	lcd_p = mmap(NULL, //你要映射的内存空间的起始地址,为NULL系统自动给你分配
		 800*480*4,//你要映射的内存空间的大小
		 PROT_READ|PROT_WRITE,//映射的权限 
		 MAP_SHARED,//1、进程共享  2、对应的文件会同步发生变化 	
		 lcdfd,//映射液晶屏文件
		 0//偏移量 ,默认为0
		);
	if(lcd_p == MAP_FAILED)	
	{
		printf("mmap lcd error\n");
		return false;
	}
	
	return true;
}
//解除初始化
void uinitLcd()
{
	//解除映射
	munmap(lcd_p, 800*480*4);
	//5、关闭液晶屏文件、bmp图片文件	
	close(lcdfd);
}
/*触摸屏代码*/
int ts_func(int *x,int *y)
{
	printf("ts_func 请用手触摸屏幕.......\n");
	//1)打开触摸屏设备文件 ---
	int tsfd = open("/dev/input/event0",O_RDWR);
	if(tsfd == -1)
	{
		printf("open /dev/input/event0 error\n");
		return -1;
	}
	
	while(1)
	{
		//2)分析 触摸屏的数据是什么数据类型???
		//输入子系统计算完结果之后会将这个结果存储在结构体中
		struct input_event info;
		
		//3)读取触摸屏数据 --如果你没有用手触摸屏幕,当前会阻塞在这里
		read(tsfd,&info,sizeof(struct input_event));
		
		//判断当前发生的是触摸屏事件,接着判断触发的是X轴事件
		if(info.type == EV_ABS && info.code == ABS_X)
			*x = info.value;
		//判断当前发生的是触摸屏事件,接着判断触发的是Y轴事件
		if(info.type == EV_ABS && info.code == ABS_Y)
			*y = info.value;
		
		//松开的时候,才进行打印  type:1 code:330 value:0
		if(info.type == EV_KEY && info.code == BTN_TOUCH &&  info.value == 0){
			
			//如果你的板子是黑色的,那么需要进行坐标转换(1024,600) ---(800,480)
			//*x = (*x *1.0)/1024 * 800 ;
			//*y = (*y *1.0)/600  * 480 ;
			
			printf("(%d,%d)\n",*x,*y);
			break;
		}
	}
	
	//5)关闭触摸屏文件
	close(tsfd);
}


/*
showBmp:在(0,0)的位置上显示一张800*480的图片
返回值:
		成功返回 0
		失败返回 -1
*/
int showBmp(char *bmpPath)
{
	printf("showBmp bmpPath:%s\n",bmpPath);
	int i,j;
	int tempbuf[800*480];
	int lcdbuf[800*480];
	
	//2、打开bmp图片文件  
	int bmpfd = open(bmpPath,O_RDONLY);
	if(bmpfd == -1)
	{
		perror("open bmpfile error");//perror将错误的原因打印出来
		return -1;
	}
	
	//读取bmp图片的文件头 + 信息头数据
	BITMAPFILEHEADER fileHead;
	BITMAPINFOHEADER infoHead;
	
	read(bmpfd,&fileHead,14);//读取14个字节
	read(bmpfd,&infoHead,40);//读取40个字节
	
	//判断是否宽度等于 800 
	if(BMP_WIDTH != getBmpWidth(&infoHead))
	{
		printf("你要打印的图片宽度 不等于 800 请重新修改图片 error\n");
		//5、bmp图片文件	
		close(bmpfd);
		return -1;
	}
	//判断是否高度等于 480
	if(BMP_HEIGHT != getBmpHeight(&infoHead))
	{
		printf("你要打印的图片高度 不等于 480 请重新修改图片 error\n");
		//5、bmp图片文件	
		close(bmpfd);
		return -1;
	}
	
	//3、读取bmp图片的数据
	char bmpbuf[800*480*3]={0};
	read(bmpfd,bmpbuf,800*480*3);
	//将bmp图片每个像素点的 B G R -->A R G  B
	for(i=0,j=0; i<800*480;i++,j+=3)
	{
		tempbuf[i] = 0x00<<24 | bmpbuf[j+2]<<16 | bmpbuf[j+1]<<8 | bmpbuf[j];
	}
	//上下180度颠倒 
	for(j=0; j<480; j++)
	{
		for(i=0; i<800; i++)
		{
			lcd_p[j*800+i] = tempbuf[(479-j)*800+i];
		}
	}
	
	close(bmpfd);
	
	return 0;
}

//在(0,0)的位置上显示一张800*480切割4倍后的200*120的图片
int showBmp_solv(char *bmpPath)
{
	int i,j;
	int tempbuf[800*480];
	int lcdbuf[800*480];
	int minbuf[200*120];
	
	//2、打开bmp图片文件  
	int bmpfd = open(bmpPath,O_RDONLY);
	if(bmpfd == -1)
	{
		perror("open bmpfile error");//perror将错误的原因打印出来
		return -1;
	}
	
	//读取bmp图片的文件头 + 信息头数据
	BITMAPFILEHEADER fileHead;
	BITMAPINFOHEADER infoHead;
	
	read(bmpfd,&fileHead,14);//读取14个字节
	read(bmpfd,&infoHead,40);//读取40个字节
	
	//判断是否宽度等于 800 
	if(BMP_WIDTH != getBmpWidth(&infoHead))
	{
		printf("你要打印的图片宽度 不等于 800 请重新修改图片 error\n");
		//5、bmp图片文件	
		close(bmpfd);
		return -1;
	}
	//判断是否高度等于 480
	if(BMP_HEIGHT != getBmpHeight(&infoHead))
	{
		printf("你要打印的图片高度 不等于 480 请重新修改图片 error\n");
		//5、bmp图片文件	
		close(bmpfd);
		return -1;
	}
	
	//3、读取bmp图片的数据
	char bmpbuf[800*480*3]={0};
	read(bmpfd,bmpbuf,800*480*3);
	//将bmp图片每个像素点的 B G R -->A R G  B
	for(i=0,j=0; i<800*480;i++,j+=3)
	{
		tempbuf[i] = 0x00<<24 | bmpbuf[j+2]<<16 | bmpbuf[j+1]<<8 | bmpbuf[j];
	}
	//上下180度颠倒 
	for(j=0; j<480; j++)
	{
		for(i=0; i<800; i++)
		{
			lcdbuf[j*800+i] = tempbuf[(479-j)*800+i];
		}
	}
	//切割算法 
	//思路:每隔4行取一行像素,在每一行中,每4个像素点取一个像素点
	//将lcdbuf --> 800*480  切割成  200*120 存储到 minbuf
	for(j=0; j<120; j++)
	{
		for(i=0; i<200; i++)
		{
			minbuf[j*200+i] = lcdbuf[j*4*800+i*4]; //i == 0 4 8 12 16
		}
	}
	//切割之后的数据存储在 minbuf ---200*120
	//显示 ,赋值到 lcd_p
	for(j=0; j<120; j++)
	{
		for(i=0; i<200; i++)
		{
			lcd_p[j*800+i] = minbuf[j*200+i];
		}
	}
	
	close(bmpfd);
}
//在(posX,posY)的位置上显示一张800*480切割4倍后的200*120的图片
//
int showBmp_solv_xy(char *bmpPath,int posX,int posY)
{
	int i,j;
	int tempbuf[800*480];
	int lcdbuf[800*480];
	int minbuf[200*120];
	
	//2、打开bmp图片文件  
	int bmpfd = open(bmpPath,O_RDONLY);
	if(bmpfd == -1)
	{
		perror("open bmpfile error");//perror将错误的原因打印出来
		return -1;
	}
	
	//读取bmp图片的文件头 + 信息头数据
	BITMAPFILEHEADER fileHead;
	BITMAPINFOHEADER infoHead;
	
	read(bmpfd,&fileHead,14);//读取14个字节
	read(bmpfd,&infoHead,40);//读取40个字节
	
	//判断是否宽度等于 800 
	if(BMP_WIDTH != getBmpWidth(&infoHead))
	{
		printf("你要打印的图片宽度 不等于 800 请重新修改图片 error\n");
		//5、bmp图片文件	
		close(bmpfd);
		return -1;
	}
	//判断是否高度等于 480
	if(BMP_HEIGHT != getBmpHeight(&infoHead))
	{
		printf("你要打印的图片高度 不等于 480 请重新修改图片 error\n");
		//5、bmp图片文件	
		close(bmpfd);
		return -1;
	}
	
	//3、读取bmp图片的数据
	char bmpbuf[800*480*3]={0};
	read(bmpfd,bmpbuf,800*480*3);
	//将bmp图片每个像素点的 B G R -->A R G  B
	for(i=0,j=0; i<800*480;i++,j+=3)
	{
		tempbuf[i] = 0x00<<24 | bmpbuf[j+2]<<16 | bmpbuf[j+1]<<8 | bmpbuf[j];
	}
	//上下180度颠倒 
	for(j=0; j<480; j++)
	{
		for(i=0; i<800; i++)
		{
			lcdbuf[j*800+i] = tempbuf[(479-j)*800+i];
		}
	}
	//切割算法 
	//思路:每隔4行取一行像素,在每一行中,每4个像素点取一个像素点
	//将lcdbuf --> 800*480  切割成  200*120 存储到 minbuf
	for(j=0; j<120; j++)
	{
		for(i=0; i<200; i++)
		{
			minbuf[j*200+i] = lcdbuf[j*4*800+i*4]; //i == 0 4 8 12 16
		}
	}
	//切割之后的数据存储在 minbuf ---200*120
	//显示 ,赋值到 lcd_p
	//在指定的位置(posX,posY)上显示
	for(j=0; j<120; j++)
	{
		for(i=0; i<200; i++)
		{
			//lcd_p[posY*800+posX+j*800+i] = minbuf[j*200+i];
			lcd_p[(posY+j)*800+i+posX] = minbuf[j*200+i];
		}
	}
	
	close(bmpfd);
}

int main(int argc,char*argv[])
{
	int ts_x,ts_y;
	char bmpName[BMP_NUMBER][256] = {"1.bmp","2.bmp","3.bmp","4.bmp","5.bmp"};
	int bmpFlag = 0;//用来控制图片显示的标志位
	
	printf("main start.......\n");
	//初始化
	if(!initLcdAndMmap()) //if(initLcdAndMmap() = false)
	{
		//如果初始化失败
		printf("initLcdAndMmap error\n");
		return -1;
	}
	printf("initLcdAndMmap success.......\n");
	
	while(1)
	{
		ts_func(&ts_x,&ts_y);//触摸屏的代码调用一次,就是表示获取一次坐标,点击一次
		if(ts_x<400)//左边
		{
			bmpFlag--;
			
			//如果当前图片是第一张,点击左边时, 应该让其回到最后一张
			if(bmpFlag == -1){
				printf("当前是第一张,点击左边,回到最后一张\n");
				bmpFlag = BMP_NUMBER -1;
			}
			printf("left bmpFlag:%d\n",bmpFlag);
		}
		else { //右边
			
			bmpFlag++; //4 
			
			//如果当前图片是最后一张,点击右边时,应该让其回到第一张
			if(bmpFlag == BMP_NUMBER){
				printf("当前是最后一张,点击右边边,回到第一张\n");
				bmpFlag = 0;
			}
			printf("right bmpFlag:%d\n",bmpFlag);
		}
		//显示
		int ret = showBmp(bmpName[bmpFlag]);//bmpName[bmpFlag]---->char bmp[256]  
		if(ret == -1)//显示失败
		{
			printf("showBmp error %s\n",bmpName[bmpFlag]);
		}
		else 
			printf("-------------showBmp success---------------\n\n");
	}
	
	//解除初始化
	uinitLcd();

	return 0;
}

三、拆分文件

1、创建文件

2、各文件夹中存放的东西

(1)bin文件夹内

(2)c_source文件夹内

(3)include文件夹内

(4)resource文件夹内

(5)lib文件夹暂时为空

3、各文件的内容

(1)Makefile:

CC = arm-none-linux-gnueabi-gcc
TARGET = bin/main
C_SOURCE = $(wildcard c_source/*.c)
INCLUDE_PATH = -I ./include

$(TARGET):$(C_SOURCE)
	$(CC) $^  -o  $@ $(INCLUDE_PATH)

.PHONY:clean	
	
clean:
	$(RM) $(TARGET)

(2)main.c 文件

#include "showbmp.h"
#include "ts.h"
#include "debug.h"

#define BMP_NUMBER	5

#define DEBUG

//字符串拼接 sprintf 
char text[1024]={0};

int main(int argc,char*argv[])
{
	initLog();
	
	int ts_x,ts_y;
	char bmpName[BMP_NUMBER][256] = {"1.bmp","2.bmp","3.bmp","4.bmp","5.bmp"};
	int bmpFlag = 0;//用来控制图片显示的标志位
	
	XPRINTF("main start.......\n");
	//printf("main start.......\n");
	//初始化
	if(!initLcdAndMmap()) //if(initLcdAndMmap() = false)
	{
		//如果初始化失败
		XPRINTF("initLcdAndMmap error\n");
		//printf("initLcdAndMmap error\n");
		return -1;
	}
	XPRINTF("initLcdAndMmap success.......\n");
	
	while(1)
	{
		ts_func(&ts_x,&ts_y);//触摸屏的代码调用一次,就是表示获取一次坐标,点击一次
		if(ts_x<400)//左边
		{
			bmpFlag--;
			
			//如果当前图片是第一张,点击左边时, 应该让其回到最后一张
			if(bmpFlag == -1){
				XPRINTF("当前是第一张,点击左边,回到最后一张\n");
				bmpFlag = BMP_NUMBER -1;
			}
			bzero(text,1024);
			sprintf(text,"left bmpFlag:%d\n",bmpFlag);
			XPRINTF(text);
		}
		else { //右边
			
			bmpFlag++; //4 
			
			//如果当前图片是最后一张,点击右边时,应该让其回到第一张
			if(bmpFlag == BMP_NUMBER){
				XPRINTF("当前是最后一张,点击右边边,回到第一张\n");
				bmpFlag = 0;
			}
			bzero(text,1024);
			sprintf(text,"right bmpFlag:%d\n",bmpFlag);
			XPRINTF(text);
		}
		//显示
		int ret = showBmp(bmpName[bmpFlag]);//bmpName[bmpFlag]---->char bmp[256]  
		if(ret == -1)//显示失败
		{
			bzero(text,1024);
			sprintf(text,"showBmp error %s\n",bmpName[bmpFlag]);
			XPRINTF(text);
		}
		else 
			XPRINTF("-------------showBmp success---------------\n\n");
	}
	
	//解除初始化
	uinitLcd();

	return 0;
}

(3)debug.c文件

#include "debug.h"

//初始化调试文本
int initLog()
{
	//1、打开文本 并且 清空内容 ,如果不存在,新建
	FILE * fp = fopen(LOG_FILE,"wb+");
	if(fp == NULL)
	{
		printf("fopen %s error\n",LOG_FILE);
		return -1;
	}
	//3、关闭文件
	fclose(fp);
}

#ifdef DEBUG //开启调试功能

#ifndef DEBUG_TEXT
int XPRINTF(char *text) //1、调试功能 定位到屏幕终端
{
	printf("%s",text);
}
#else 
	
int XPRINTF(char *text)//2、调试功能 定位到文本中
{
	
	//1、以可写的方式打开log.txt,如果文件不存在则新建,如果存在了追加
	FILE * fp = fopen(LOG_FILE,"ab");
	if(fp == NULL)
	{
		printf("fopen %s error\n",LOG_FILE);
		return -1;
	}
	//2、将传递进来的信息写入到调试文本中 fprintf
	fprintf(fp,"%s",text);
	//3、关闭文件
	fclose(fp);
}
#endif

#else 
int XPRINTF(char *text)
{
	
}
#endif

(4)debug.h文件

#ifndef __DEBUG_H_
#define __DEBUG_H_

#include<stdio.h>
#include <strings.h>

#define LOG_FILE	"./log.txt"

#define DEBUG //是否开启调试功能  调试的总开关
#define DEBUG_TEXT //如果定义了该宏   将调试信息输出文本中  

extern int XPRINTF(char *text);

extern int initLog();

#endif

(5)showbmp.c文件

#include "showbmp.h"
#include "debug.h"

int lcdfd;
int *lcd_p;

extern char text[1024];

//得到bmp图片的宽度
int getBmpWidth(BITMAPINFOHEADER *head)
{
	bzero(text,1024);	
	sprintf(text,"Width:%d\n",head->biWidth);//图像的宽度
	XPRINTF(text);
	return head->biWidth;
}
//得到bmp图片的高度
int getBmpHeight(BITMAPINFOHEADER *head)
{
	bzero(text,1024);
	sprintf(text,"Height:%d\n",head->biHeight);//图像的高度
	XPRINTF(text);
	return head->biHeight;
}
//得到bmp图片的大小
int getBmpSize(BITMAPINFOHEADER *head)
{
	bzero(text,1024);
	sprintf(text,"fileSize:%d\n",head->biSizeImage+54);//文件的大小
	XPRINTF(text);
	return head->biSizeImage+54;
}

//初始化液晶屏 和 内存映射
bool initLcdAndMmap()
{
	XPRINTF("initLcdAndMmap start.......\n");
	//1、打开液晶屏文件  
	lcdfd = open("/dev/fb0",O_RDWR);
	if(lcdfd == -1)
	{
		XPRINTF("open lcd error");//perror将错误的原因打印出来
		return false;
	}
	//将液晶屏文件 通过内存映射mmap的方式 映射到虚拟内存空间的某一块空间上,得到这一块内存的起始地址,后续我们操作这片内存空间,就相当于直接操作液晶屏文件
	lcd_p = mmap(NULL, //你要映射的内存空间的起始地址,为NULL系统自动给你分配
		 800*480*4,//你要映射的内存空间的大小
		 PROT_READ|PROT_WRITE,//映射的权限 
		 MAP_SHARED,//1、进程共享  2、对应的文件会同步发生变化 	
		 lcdfd,//映射液晶屏文件
		 0//偏移量 ,默认为0
		);
	if(lcd_p == MAP_FAILED)	
	{
		XPRINTF("mmap lcd error\n");
		return false;
	}
	
	return true;
}
//解除初始化
void uinitLcd()
{
	//解除映射
	munmap(lcd_p, 800*480*4);
	//5、关闭液晶屏文件、bmp图片文件	
	close(lcdfd);
}

/*
showBmp:在(0,0)的位置上显示一张800*480的图片
返回值:
		成功返回 0
		失败返回 -1
*/
int showBmp(char *bmpPath)
{
	bzero(text,1024);
	sprintf(text,"showBmp bmpPath:%s\n",bmpPath);
	XPRINTF(text);
	int i,j;
	int tempbuf[800*480];
	int lcdbuf[800*480];
	
	//2、打开bmp图片文件  
	int bmpfd = open(bmpPath,O_RDONLY);
	if(bmpfd == -1)
	{
		XPRINTF("open bmpfile error");//perror将错误的原因打印出来
		return -1;
	}
	
	//读取bmp图片的文件头 + 信息头数据
	BITMAPFILEHEADER fileHead;
	BITMAPINFOHEADER infoHead;
	
	read(bmpfd,&fileHead,14);//读取14个字节
	read(bmpfd,&infoHead,40);//读取40个字节
	
	//判断是否宽度等于 800 
	if(BMP_WIDTH != getBmpWidth(&infoHead))
	{
		XPRINTF("你要打印的图片宽度 不等于 800 请重新修改图片 error\n");
		//5、bmp图片文件	
		close(bmpfd);
		return -1;
	}
	//判断是否高度等于 480
	if(BMP_HEIGHT != getBmpHeight(&infoHead))
	{
		XPRINTF("你要打印的图片高度 不等于 480 请重新修改图片 error\n");
		//5、bmp图片文件	
		close(bmpfd);
		return -1;
	}
	
	//3、读取bmp图片的数据
	char bmpbuf[800*480*3]={0};
	read(bmpfd,bmpbuf,800*480*3);
	//将bmp图片每个像素点的 B G R -->A R G  B
	for(i=0,j=0; i<800*480;i++,j+=3)
	{
		tempbuf[i] = 0x00<<24 | bmpbuf[j+2]<<16 | bmpbuf[j+1]<<8 | bmpbuf[j];
	}
	//上下180度颠倒 
	for(j=0; j<480; j++)
	{
		for(i=0; i<800; i++)
		{
			lcd_p[j*800+i] = tempbuf[(479-j)*800+i];
		}
	}
	
	close(bmpfd);
	
	return 0;
}

//在(0,0)的位置上显示一张800*480切割4倍后的200*120的图片
int showBmp_solv(char *bmpPath)
{
	int i,j;
	int tempbuf[800*480];
	int lcdbuf[800*480];
	int minbuf[200*120];
	
	//2、打开bmp图片文件  
	int bmpfd = open(bmpPath,O_RDONLY);
	if(bmpfd == -1)
	{
		XPRINTF("open bmpfile error");//perror将错误的原因打印出来
		return -1;
	}
	
	//读取bmp图片的文件头 + 信息头数据
	BITMAPFILEHEADER fileHead;
	BITMAPINFOHEADER infoHead;
	
	read(bmpfd,&fileHead,14);//读取14个字节
	read(bmpfd,&infoHead,40);//读取40个字节
	
	//判断是否宽度等于 800 
	if(BMP_WIDTH != getBmpWidth(&infoHead))
	{
		XPRINTF("你要打印的图片宽度 不等于 800 请重新修改图片 error\n");
		//5、bmp图片文件	
		close(bmpfd);
		return -1;
	}
	//判断是否高度等于 480
	if(BMP_HEIGHT != getBmpHeight(&infoHead))
	{
		XPRINTF("你要打印的图片高度 不等于 480 请重新修改图片 error\n");
		//5、bmp图片文件	
		close(bmpfd);
		return -1;
	}
	
	//3、读取bmp图片的数据
	char bmpbuf[800*480*3]={0};
	read(bmpfd,bmpbuf,800*480*3);
	//将bmp图片每个像素点的 B G R -->A R G  B
	for(i=0,j=0; i<800*480;i++,j+=3)
	{
		tempbuf[i] = 0x00<<24 | bmpbuf[j+2]<<16 | bmpbuf[j+1]<<8 | bmpbuf[j];
	}
	//上下180度颠倒 
	for(j=0; j<480; j++)
	{
		for(i=0; i<800; i++)
		{
			lcdbuf[j*800+i] = tempbuf[(479-j)*800+i];
		}
	}
	//切割算法 
	//思路:每隔4行取一行像素,在每一行中,每4个像素点取一个像素点
	//将lcdbuf --> 800*480  切割成  200*120 存储到 minbuf
	for(j=0; j<120; j++)
	{
		for(i=0; i<200; i++)
		{
			minbuf[j*200+i] = lcdbuf[j*4*800+i*4]; //i == 0 4 8 12 16
		}
	}
	//切割之后的数据存储在 minbuf ---200*120
	//显示 ,赋值到 lcd_p
	for(j=0; j<120; j++)
	{
		for(i=0; i<200; i++)
		{
			lcd_p[j*800+i] = minbuf[j*200+i];
		}
	}
	
	close(bmpfd);
}
//在(posX,posY)的位置上显示一张800*480切割4倍后的200*120的图片
//
int showBmp_solv_xy(char *bmpPath,int posX,int posY)
{
	int i,j;
	int tempbuf[800*480];
	int lcdbuf[800*480];
	int minbuf[200*120];
	
	//2、打开bmp图片文件  
	int bmpfd = open(bmpPath,O_RDONLY);
	if(bmpfd == -1)
	{
		XPRINTF("open bmpfile error");//perror将错误的原因打印出来
		return -1;
	}
	
	//读取bmp图片的文件头 + 信息头数据
	BITMAPFILEHEADER fileHead;
	BITMAPINFOHEADER infoHead;
	
	read(bmpfd,&fileHead,14);//读取14个字节
	read(bmpfd,&infoHead,40);//读取40个字节
	
	//判断是否宽度等于 800 
	if(BMP_WIDTH != getBmpWidth(&infoHead))
	{
		XPRINTF("你要打印的图片宽度 不等于 800 请重新修改图片 error\n");
		//5、bmp图片文件	
		close(bmpfd);
		return -1;
	}
	//判断是否高度等于 480
	if(BMP_HEIGHT != getBmpHeight(&infoHead))
	{
		XPRINTF("你要打印的图片高度 不等于 480 请重新修改图片 error\n");
		//5、bmp图片文件	
		close(bmpfd);
		return -1;
	}
	
	//3、读取bmp图片的数据
	char bmpbuf[800*480*3]={0};
	read(bmpfd,bmpbuf,800*480*3);
	//将bmp图片每个像素点的 B G R -->A R G  B
	for(i=0,j=0; i<800*480;i++,j+=3)
	{
		tempbuf[i] = 0x00<<24 | bmpbuf[j+2]<<16 | bmpbuf[j+1]<<8 | bmpbuf[j];
	}
	//上下180度颠倒 
	for(j=0; j<480; j++)
	{
		for(i=0; i<800; i++)
		{
			lcdbuf[j*800+i] = tempbuf[(479-j)*800+i];
		}
	}
	//切割算法 
	//思路:每隔4行取一行像素,在每一行中,每4个像素点取一个像素点
	//将lcdbuf --> 800*480  切割成  200*120 存储到 minbuf
	for(j=0; j<120; j++)
	{
		for(i=0; i<200; i++)
		{
			minbuf[j*200+i] = lcdbuf[j*4*800+i*4]; //i == 0 4 8 12 16
		}
	}
	//切割之后的数据存储在 minbuf ---200*120
	//显示 ,赋值到 lcd_p
	//在指定的位置(posX,posY)上显示
	for(j=0; j<120; j++)
	{
		for(i=0; i<200; i++)
		{
			//lcd_p[posY*800+posX+j*800+i] = minbuf[j*200+i];
			lcd_p[(posY+j)*800+i+posX] = minbuf[j*200+i];
		}
	}
	
	close(bmpfd);
}

(6)showbmp.h文件

#ifndef __SHOWBMP_H_
#define __SHOWBMP_H_

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

#include <sys/mman.h>
#include <stdbool.h>

#define UINT  unsigned short
#define DWORD unsigned  int
#define LONG unsigned  int
#define WORD unsigned short

#define BMP_WIDTH 	800
#define BMP_HEIGHT 	480


//前面14个字节 文件信息头
typedef struct tagBITMAPFILEHEADER{
	UINT bfType;  //2
	DWORD bfSize; //DWORD 4
	UINT bfReserved1; //2
	UINT bfReserved2; //2
	DWORD bfOffBits; //DWORD 4
}BITMAPFILEHEADER;

//40个字节 位图信息头
typedef struct tagBITMAPINFOHEADER{ /* bmih */
	DWORD biSize; //DWORD 4
	LONG biWidth; //4  图像的宽度
	LONG biHeight;//4  图像的高度
	WORD biPlanes; //2
	WORD biBitCount;//2 
	DWORD biCompression; //DWORD 4
	DWORD biSizeImage; //DWORD 4
	LONG biXPelsPerMeter;//4
	LONG biYPelsPerMeter;//4
	DWORD biClrUsed; //DWORD 4
	DWORD biClrImportant; //DWORD 4
}BITMAPINFOHEADER;

extern int lcdfd;
extern int *lcd_p;


int getBmpWidth(BITMAPINFOHEADER *head);
int getBmpHeight(BITMAPINFOHEADER *head);
int getBmpSize(BITMAPINFOHEADER *head);
bool initLcdAndMmap();
void uinitLcd();
int showBmp(char *bmpPath);
int showBmp_solv(char *bmpPath);
int showBmp_solv_xy(char *bmpPath,int posX,int posY);


#endif 

(7)ts.c文件

#include "ts.h"
#include "debug.h"


extern char text[1024];

/*触摸屏代码*/
int ts_func(int *x,int *y)
{
	XPRINTF("ts_func 请用手触摸屏幕.......\n");
	//1)打开触摸屏设备文件 ---
	int tsfd = open("/dev/input/event0",O_RDWR);
	if(tsfd == -1)
	{
		XPRINTF("open /dev/input/event0 error\n");
		return -1;
	}
	
	while(1)
	{
		//2)分析 触摸屏的数据是什么数据类型???
		//输入子系统计算完结果之后会将这个结果存储在结构体中
		struct input_event info;
		
		//3)读取触摸屏数据 --如果你没有用手触摸屏幕,当前会阻塞在这里
		read(tsfd,&info,sizeof(struct input_event));
		
		//判断当前发生的是触摸屏事件,接着判断触发的是X轴事件
		if(info.type == EV_ABS && info.code == ABS_X)
			*x = info.value;
		//判断当前发生的是触摸屏事件,接着判断触发的是Y轴事件
		if(info.type == EV_ABS && info.code == ABS_Y)
			*y = info.value;
		
		//松开的时候,才进行打印  type:1 code:330 value:0
		if(info.type == EV_KEY && info.code == BTN_TOUCH &&  info.value == 0){
			
			//如果你的板子是黑色的,那么需要进行坐标转换(1024,600) ---(800,480)
			//*x = (*x *1.0)/1024 * 800 ;
			//*y = (*y *1.0)/600  * 480 ;
			bzero(text,1024);
			sprintf(text,"(%d,%d)\n",*x,*y);
			XPRINTF(text);
			break;
		}
	}
	
	//5)关闭触摸屏文件
	close(tsfd);
}

(8)ts.h文件

#ifndef __TS_H_
#define __TS_H_

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

#include <sys/mman.h>
#include <stdbool.h>
#include <linux/input.h>//触摸屏头文件

extern int ts_func(int *x,int *y);

#endif 

4、编译下载到开发板即可

  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值