arm板上通过内核实现可滑动的电子相册

通过内核打开驱动,编写的应用能通过触摸控制相册上一张下一张

我们实现这个功能就要分为:1,使用 LCD 设备,2链表3,获取触摸操作 这三小部分
直接下载我做好的直接使用

使用LCD
准备LCD

我们使用内核的LCD结构体 fb_var_screeninfo ,构造出我们的LCD
先建立一个空结构体
在这里插入图片描述

//	建立一个空结构体 
	struct fb_var_screeninfo vinfo;
	bzero(&vinfo, sizeof(vinfo));
	char *fbmem = init_lcd(&vinfo);

给结构体通过 ioctrl 获得相关参数

char *init_lcd(struct fb_var_screeninfo *vinfo)
{
	int lcd = open("/dev/fb0", O_RDWR);

	ioctl(lcd, FBIOGET_VSCREENINFO, vinfo);
	int bpp = vinfo->bits_per_pixel;
	int screensize = vinfo->xres * vinfo->yres * bpp/8;

	char *fbmem = mmap(NULL, screensize, PROT_READ|PROT_WRITE,
			   MAP_SHARED, lcd, 0);
	if(fbmem == MAP_FAILED)
	{
		perror("映射显存失败");
		exit(0);
	}
	return fbmem;
}

显示图片
void display(char *jpgfile, char *fbmem,
	     struct fb_var_screeninfo *vinfo,
	     int xoffset, int yoffset)
{
	// 读取图片文件属性信息
	// 并根据其大小分配内存缓冲区jpg_buffer
	struct stat file_info;
	Stat(jpgfile, &file_info);//获取图片信息
	int fd = Open(jpgfile, O_RDONLY);

	unsigned char *jpg_buffer;
	jpg_buffer = (unsigned char *)calloc(1, file_info.st_size);
	read_image_from_file(fd, jpg_buffer, file_info.st_size);


	// 声明解压缩结构体,以及错误管理结构体
	struct jpeg_decompress_struct cinfo;
	struct jpeg_error_mgr jerr;

	// 使用缺省的出错处理来初始化解压缩结构体
	cinfo.err = jpeg_std_error(&jerr);
	jpeg_create_decompress(&cinfo);

	// 配置该cinfo,使其从jpg_buffer中读取jpg_size个字节
	// 这些数据必须是完整的JPEG数据
	jpeg_mem_src(&cinfo, jpg_buffer, file_info.st_size);


	// 读取JPEG文件的头,并判断其格式是否合法
	int ret = jpeg_read_header(&cinfo, true);
	if(ret != 1)
	{
		fprintf(stderr, "[%d]: jpeg_read_header failed: "
			"%s\n", __LINE__, strerror(errno));
		exit(1);
	}

	// 开始解压
	jpeg_start_decompress(&cinfo);

	struct image_info imageinfo;
	imageinfo.width = cinfo.output_width;
	imageinfo.height = cinfo.output_height;
	imageinfo.pixel_size = cinfo.output_components;

	int row_stride = imageinfo.width * imageinfo.pixel_size;

	// 根据图片的尺寸大小,分配一块相应的内存rgb_buffer
	// 用来存放从jpg_buffer解压出来的图像数据
	unsigned long rgb_size;
	unsigned char *rgb_buffer;
	rgb_size = imageinfo.width *
			imageinfo.height * imageinfo.pixel_size;
	rgb_buffer = (unsigned char *)calloc(1, rgb_size);

	// 循环地将图片的每一行读出并解压到rgb_buffer中
	int line = 0;
	while(cinfo.output_scanline < cinfo.output_height)
	{
		unsigned char *buffer_array[1];
		buffer_array[0] = rgb_buffer +
				(cinfo.output_scanline) * row_stride;
		jpeg_read_scanlines(&cinfo, buffer_array, 1);
	}

	// 解压完了,将jpeg相关的资源释放掉
 	jpeg_finish_decompress(&cinfo);
	jpeg_destroy_decompress(&cinfo);
	free(jpg_buffer);
	
	
	
	

	// 清屏
	bzero(fbmem, vinfo->xres * vinfo->yres * 4);

	// 将rgb_buffer中的RGB图像数据,写入LCD的FRAMEBUFFER中
	char *tmp = fbmem;
	tmp += (yoffset*vinfo->xres + xoffset) * vinfo->bits_per_pixel/8;

	int lcd_w = vinfo->xres - xoffset;
	int lcd_h = vinfo->yres - yoffset;

	int row, column;
	for(row=0; row<lcd_h && row<imageinfo.height; row++)
	{
		for(column=0; column<lcd_w && column<imageinfo.width; column++)
		{
			unsigned long lcd_offset = (vinfo->xres*row + column) * 4;
			unsigned long rgb_offset = (imageinfo.width*row+column) *
						    imageinfo.pixel_size;

			memcpy(tmp + lcd_offset + vinfo->red.offset/8,
			       rgb_buffer + rgb_offset + 0, 1);
			memcpy(tmp + lcd_offset + vinfo->green.offset/8,
			       rgb_buffer + rgb_offset + 1, 1);
			memcpy(tmp + lcd_offset + vinfo->blue.offset/8,
			       rgb_buffer + rgb_offset + 2, 1);
		}
	}

	// 释放相关资源
	free(rgb_buffer);
	close(fd);
}
使用列表
构造链表

每个链表节点都会有上一个,和下一个,还有自己的名字,所以我们创建一个结构体

typedef struct linklist
{
	char image_name[100];
	struct linklist *next;
	struct linklist *prev;
}listnode,*linklist;


并且先给链表初始化,让上一个和下一个都先指一个空间

linklist init_list(void)
{
    linklist head = calloc(1,sizeof(listnode));//分配一个长度为listnode的空间
    head->next = head;
    head->prev = head;
    return head;	
}
拿取图片信息,放入列表
linklist open_dir(char *argv,linklist head)
{
	//打开目录
	DIR *dp = opendir(argv);
	if(dp == NULL)
	{
		perror("打开目录失败");
		exit(1);
	}
	
	//进入目录 
	chdir(argv);
	
	//获取目录项信息
	struct dirent *ep;
	
	//定义数组存放当前目录路径以及jpg名 
	char path[100] = {0};
	getcwd(path, 100);
	
	//保存jpg信息
	char imag_buf[200] = {0};
	
	
	//遍历目录内的jpg文件
	int n , i;

	
    while((ep = readdir(dp)) != NULL)
	{	
		//strstr找到一个包含“.jpg”名字的文件
		if(strstr(ep->d_name,".jpg"))
		{ 
	        //将其当前路径以及文件名存放在img_buf中
			sprintf(imag_buf , "%s/%s", path , ep->d_name);
			
			//创建链表新节点存放图片信息imag_buf
			linklist new = creat_node(imag_buf);
			
			//将新节点插入到链表末尾
			insert_add_tail(new , head);
		}
	}
    //释放资源
	closedir(dp);
	//返回链表头
	return 	head;
}
触摸板

这个比较简单,就是判断连续滑动,和单点触摸的比较

enum motion get_motion(void)
{
	// 1,打开触摸屏文件
	int tp = open("/dev/input/event0", O_RDONLY);
	

	// 2,读取触摸屏信息  input_event结构体在linux/input.h库中
	struct input_event buf; 
	   // int falg = 0;      //标记第一次按下的状态获取第一组x值
		//int falgy = 0;      //标记第一次按下的状态获取第一组y值
		//int touch = 0;     //标记用户屏幕无动作标志位
		int x1 = 0 , x2 = 0;       //x1为按下屏幕x的起始值 ,x2为松开屏幕x的结束值
		int y1 = 0 , y2 = 0;      //y1为按下屏幕x的起始值 ,y2为松开屏幕x的结束值
		
		int xdone = 0 ;
		int ydone = 0 ;
	while(1)
	{
		bzero(&buf, sizeof(buf));
		read(tp, &buf, sizeof(buf)); // 读取触摸屏数据,放到 buf 中
		
        
		// 读到按键事件(包括键盘、触摸屏的按压、鼠标的左右键……)
		if(buf.type == EV_KEY)
		{
			// 读到触摸屏的按压事件
			if(buf.code == BTN_TOUCH)
			{
				// 读到按下触摸屏
				if(buf.value > 0)
                      xdone = 0;
				      ydone = 0;

				// 读到松开触摸屏
				if(buf.value == 0)
					break;
			}
		}
		
		// 读到触摸屏的坐标事件
		if(buf.type == EV_ABS)
		{
	       if(xdone == 0 || ydone == 0)
		   {
			    if(buf.code == ABS_X )	
				{					
				   x1 = buf.value;//起始
			       xdone = 1;
				}
			    if(buf.code == ABS_Y)
				{
				   y1 = buf.value;//起始
				   ydone = 1;
				}
		   } 
		   if(xdone == 1 || ydone == 1)
		   {
			  if(buf.code == ABS_X )
				 x2 = buf.value;//结束
			  if(buf.code == ABS_Y)
				 y2 = buf.value; //结束  
		  } 
		
		}
		
	}

	printf("起始x1 = %d 结束x2 = %d\n",x1,x2);
	printf("起始y1 = %d 结束y2 = %d\n",y1,y2);
	
	
	int dif_x = x1 - x2 > 0 ? x1 - x2 : x2 - x1;
	int dif_y = y1 - y2 > 0 ? y1 - y2 : y2 - y1;
	
	
    if(x1 == 0 || x2 == 0)
	{
      return -1;
	}
	
	
	if (x1 > x2 && dif_x > dif_y)
	{
	   printf("向左滑动\n");
	   return left;
	}
    else if(x1 < x2 && dif_x > dif_y)
	{ 
       printf("向右滑动\n");
	   return right;
	}
	else if(y1 > y2 && dif_y > dif_x)
	{ 
       printf("向上滑动\n");
	   return up;
	}
	else if(y1 < y2 && dif_y > dif_x)
	{ 
       printf("向下滑动\n");
	   return down;
	}
	else 
	{

		return -1;
	}
	// 3,释放资源
	close(tp);
}
程序运行

对我们的程序进行交叉编译,上传自己想要的图片之后,调用动态库就能使用了

编译调用动态库

程序的启动需要 jpeg 库来解码图片,所以我们要交叉编译出 libjpeg.so.9

1,先从官网上下载jpeg的解码库文件
jpegsrc.v9d.tar.gz

2,拖到ubuntu的系统的桌面中

3,打开命令终端,进入到ubuntu的桌面路径
cd 桌面

4,解压jpeg的解码库文件
tar xzvf jpegsrc.v9d.tar.gz

5,解压完成后会变成一个文件夹jpeg-9d,进去这个文件夹里面
cd jpeg-9d

6,根据渣渣的引领,解读了README,install.txt的内容,进行了如下命令操作

./configure --host=arm-linux --prefix=/home/scholar/nfs_share/6818_work/lib
		上面的话的意思是:
			./configure:代表运行jpeg的配置程序
			--host=arm-linux:指定编译的命令前缀为arm-linux
			--prefix=/home/scenery/桌面/mylib:代表将编译出来的资源文件放到/home/scenery/桌面/mylib路径中
make

make install
然后你就可以在你的桌面上看到生成了一个文件夹mylib,里面放着四个文件夹
bin,include,lib,share
这几个文件就是我们即将引用的文件啦

在这里插入图片描述

编译出执行文件

进入我们的源码目录
在这里插入图片描述

arm-linux-gcc -o showphtot ./*.c

这时候再更改想显示的图片

上板

用nfs挂载我们的开发板

cd ./c_photo_yueqian/
export LD_LIBRARY_PATH=../lib/  #链接动态库
./showphoto ./jpg

在这里插入图片描述

  • 4
    点赞
  • 46
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值