`` 在上次的帖子中,我已经成功使用FrameBuffer外设输出一张1920*1080大小的BMP图片了,这次我对算法优化一下,使之可以输出任意大小的BMP图片,并引入LIBJPEG图片解码库,也输出任意大小的JPG图片。
使用JPG图片解码库,需要引入jpeglib.h驱动文件,这个在Ubuntu18.04版本的虚拟机里面是肯定有的,并且需要在编译的最后面添加-ljpeg指令以链接LIBJPEG动态链接库,并且需要在NanoPi K1+板子上安装64位的libjpeg62-dev库。
使用LIBJPEG解码库的相关结构体和API函数如下:
- struct jpeg_decompress_struct cinfo;
复制代码
//JPEG图像在解码过程中,使用jpeg_decompress_struct类型的结构体来表示,图像的所有信息都存储在结构体中
- struct jpeg_error_mgr jerr;
复制代码
//定义一个标准的错误结构体,一旦程序出现错误就会调用exit()函数退出进程
- <div>cinfo.err = jpeg_std_error(&jerr);</div>
复制代码
//绑定错误处理结构对象
- <div>jpeg_create_decompress(&cinfo);</div>
复制代码
//初始化cinfo结构
- <div>jpeg_stdio_src(&cinfo,input_file);</div>
复制代码
//指定解压缩数据源
- jpeg_read_header(&cinfo,TRUE);
复制代码
//获取文件信息
- jpeg_start_decompress(&cinfo);
复制代码
//开始解压缩
- <div>
- </div><div>buffer=(*cinfo.mem->alloc_sarray((j_common_ptr)&cinfo,JPOOL_IMAGE,width*depth,1);</div>
复制代码
//分配一行数据空间
- jpeg_read_scanlines(&cinfo,buffer,1);
复制代码
//读取一行jpg图像数据到buffer
- memcpy(point,*buffer,width*depth);
复制代码
//将buffer中的数据逐行给src_buff
其中jpeg_decompress_struct结构体对象是非常重要的,只要是使用该解码库都必须由引用此对象;jpeg_error_mgr结构体对象只是用于错误判断的,可加可不加,我这里保险起见就按官方要求加上去了。
我们先来生成一个标准的1920*1080分辨率JPG图片,是我的游戏截图,使用与FrameBuffer分辨率相同的图片分辨率,就不用做任何的修改直接显示,全屏显示JPG图片(/home/fa/2.jpg):
显示一张与FrameBuffer分辨率相同的图片是很简单的,难点在于显示不同分辨率的图片,除了要进行用户可选的移位操作以外,还需要注意BMP图像的对齐问题,BMP图像每一行都是4字节对齐的(不管图像位色是8、16、32位等),不足4字节的数据用0补,程序中在读取BMP图像的时候要考虑对齐的问题。显示代码如下:
- int LCD_Show_BMP_File(int xpos,int ypos,char* filename)
- {
- int i,j,fbmp,fd,width,width_mod,height;
- fd=open("/dev/fb0",O_RDWR);
- if(fd == -1)
- {
- printf("open LCD failed!
- ");
- return -1;
- }
- fbmp=open(filename,O_RDONLY);
- read(fbmp,bmp_buf,54);
- width=bmp_buf[21]<<24|bmp_buf[20]<<16|bmp_buf[19]<<8|bmp_buf[18];
- height=bmp_buf[25]<<24|bmp_buf[24]<<16|bmp_buf[23]<<8|bmp_buf[22];
- fbmp=open(filename,O_RDONLY);
- read(fbmp,bmp_buf,width*height*3+54);
- width_mod=width%4;
- for(i=0;i<LCD_HEIGHT;i++)
- {
- for(j=0;j<LCD_WIDTH;j++)
- if(i<=height&&j<=width)
- {
- lcd_buf[i*LCD_WIDTH+j]=
- bmp_buf[(i*width+j)*3+54+i*width_mod]|
- bmp_buf[(i*width+j)*3+55+i*width_mod]<<8|
- bmp_buf[(i*width+j)*3+56+i*width_mod]<<16;
- }
- else lcd_buf[i*LCD_WIDTH+j]=0;
- }
- for(i=0;i<LCD_HEIGHT;i++)
- for(j=0;j<LCD_WIDTH;j++)
- lcd_buff[i][j]=lcd_buf[i*LCD_WIDTH+j];
- for(i=0;i<LCD_HEIGHT;i++)
- for(j=0;j<LCD_WIDTH;j++)
- lcd_buff_2[height-i+ypos][j+xpos]=lcd_buff[i][j];
- for(i=0;i<LCD_HEIGHT;i++)
- for(j=0;j<LCD_WIDTH;j++)
- lcd_buf[i*LCD_WIDTH+j]=lcd_buff_2[i][j];
- //ret = write(fd,lcd_buf,LCD_WIDTH*LCD_HEIGHT*4);
- if(ret == -1)
- {
- printf("fill frame failed!
- ");
- return -1;
- }
- close(fd);
- }
- void LCD_Show_JPG_File(int xpos,int ypos,char *filename)
- {
- int fd,fjpg,i,j;
- FILE *input_file=fopen(filename,"rb");
- struct jpeg_decompress_struct cinfo;
- //JPEG图像在解码过程中,使用jpeg_decompress_struct类型的结构体来表示,图像的所有信息都存储在结构体中
- struct jpeg_error_mgr jerr;
- //定义一个标准的错误结构体,一旦程序出现错误就会调用exit()函数退出进程
- JSAMPARRAY buffer;
- //用于存取一行数据
- fjpg=open((char *)"/home/fa/1.jpg",O_RDONLY);
- cinfo.err = jpeg_std_error(&jerr);//绑定错误处理结构对象
- jpeg_create_decompress(&cinfo);//初始化cinfo结构
- jpeg_stdio_src(&cinfo,input_file);//指定解压缩数据源
- jpeg_read_header(&cinfo,TRUE);//获取文件信息
- jpeg_start_decompress(&cinfo);//开始解压缩
- int width = cinfo.output_width;//图像宽度
- int height = cinfo.output_height;//图像高度
- int depth = cinfo.output_components;//图像深度
- memset(bmp_buf,0,sizeof(unsigned char)*width*height*depth);
- buffer=(*cinfo.mem->alloc_sarray)((j_common_ptr)&cinfo,JPOOL_IMAGE,width*depth,1);
- //分配一行数据空间
- while(cinfo.output_scanline<height)//逐行读取位图数据
- {
- jpeg_read_scanlines(&cinfo,buffer,1);
- //读取一行jpg图像数据到buffer
- memcpy(point,*buffer,width*depth);
- //将buffer中的数据逐行给src_buff
- point+=width*3;
- //指针偏移一行
- }
- jpeg_finish_decompress(&cinfo);//解压缩完毕
- fd=open("/dev/fb0",O_RDWR); // O_RDONLY, O_WRONLY, or O_RDWR
- for(i=0;i<LCD_HEIGHT;i++)
- {
- for(j=0;j<LCD_WIDTH;j++)
- if(i<=height&&j<=width)
- lcd_buf[(i+ypos)*(LCD_WIDTH)+j+xpos]=bmp_buf[(i*width+j)*3]<<16|bmp_buf[(i*width+j)*3+1]<<8|bmp_buf[(i*width+j)*3+2];
- else lcd_buf[(i+ypos)*(LCD_WIDTH)+j+xpos]=0;
- }
- write(fd,lcd_buf,LCD_WIDTH*LCD_HEIGHT*4);
- }
复制代码
然后,我们可以根据图片显存的位移算法,显示一些分辨率与FrameBuffer不匹配,小于FrameBuffer分辨率但与FrameBuffer分辨率比例相同的JPG图片(/home/fa/6.jpg,1600*900分辨率):
BMP文件也同理(/home/fa/4.bmp,1600*900分辨率):
|