前言
由于从上篇博文 “荔枝派Zero(全志V3S)驱动开发之RGB LCD屏幕显示bmp图片” 中只实现了显示 bmp 图片,实际上我们很常用到的图片多数是 jpg 格式图片,因此我们需要折腾一下,实现 jpg 文件的显示。
一、jpeglib 库移植
1、jpeglib 库下载
这里我选择最新的一个版本,即 jpegsrc.v9e.tar.gz 这个 jpeglib 库
2、安装 jpeglib 库
源码的安装一般由3个步骤组成:配置(configure)、编译(make)、安装(make install)。
<1>、创建安装目录
在 Linux PC 机上新建一个文件夹,用于存放安装文件,并将 jpegsrc.v9e.tar.gz 拷贝到当前目录下:
mkdir /home/Gnep/licheepi_zero/tools cd tools/ cp /home/share/jpegsrc.v9e.tar.gz ./ ls
<2>、解压 jpegsrc.v9e.tar.gz 到安装目录
tar -xf jpegsrc.v9e.tar.gz ls
<3>、配置
进入其目录,执行:
cd jpeg-9e/ ./configure --prefix=/home/Gnep/licheepi_zero/tools CC=arm-linux-gnueabihf-gcc --host=arm-linux --enable-shared --enable-static
其中 --prefix 选项是配置安装的路径,如果不配置该选项,安装后可执行文件默认放在 /usr/local/bin,库文件默认放在 /usr/local/lib,配置文件默认放在/usr/local/etc,其它的资源文件放在/usr/local/share,比较凌乱。
用 --prefix 选项的另一个好处是卸载软件或移植软件。当某个安装的软件不再需要时,只须简单的删除该安装目录,就可以把软件卸载得干干净净;移植软件只需拷贝整个目录到另外一个机器即可(相同的操作系统)。
其中 CC 选项是用来选择你想使用的 C 编译器的绝对路径
其中 --host 选项指需要运行的位置,默认为 build,也就是本机编译出来的程序,由本机使用;当本机编译出来的程序要在 arm 板子上运行时,就要设置为 arm-linux
--enable-shared:生成动态链接库
--enable-static:生成静态链接库
<4>、编译
make
<5>、安装
make install
tools 目录下的文件为现在如下:
后面我们需要将 lib 目录下的 libjpeg.so.9 和 libjpeg.so.9.5.0 拷贝到开发板的 /usr/lib 目录中,将 include 目录下的头文件拷贝到我们需要编译的 C 代码的目录下
以上 jpeglib 库移植完成。
二、jpeg 图片解压缩过程和压缩过程
jpeg/jpg 格式图片显示,经过有损压缩的图片文件格式,文件较小,获取颜色数据需要解压
1、jpeg 解压缩过程
打开设备文件和图片文件
int lcd_fd = open(“/dev/fb0”, O_RDWR);
FILE *infile = fopen(argv[1], “r+”);
为jpeg对象分配空间并初始化
jpeg_create_decompress(&cinfo);
指定解压缩数据源
jpeg_stdio_src(&cinfo, infile);
为解压缩设定参数,包括图像大小,颜色空间
cinfo.scale_num = 1; //分子
cinfo.scale_denom = n; //分母
开始解压缩
jpeg_start_decompress(&cinfo);
取出数据(做相关的应用)
jpeg_read_scanlines(&cinfo, (JSAMPARRAY)&buffer, 1);
将每行数据显示到LCD
解压缩完毕
jpeg_finish_decompress(&cinfo);
释放资源
jpeg_destroy_decompress(&cinfo);
munmap(p, lcd_wlcd_hlcd_b);
close(lcd_fd);
fclose(infile);
free(buffer);
2、jpeg 压缩过程
为jpeg对象分配空间并初始化
指定图像输出目标
为压缩设定参数,包括图像大小,颜色空间
开始压缩
写入数据(做相关的应用)
压缩完毕
释放资源
三、编译 C 源码
1、源码展示
imageshow.c
#include <stdio.h> #include <errno.h> #include <string.h> #include <time.h> #include <sys/types.h> #include <sys/stat.h> #include <unistd.h> #include <pwd.h> #include <grp.h> #include <stdlib.h> #include <dirent.h> #include <fcntl.h> #include <sys/mman.h> #include <linux/fb.h> #include <sys/ioctl.h> #include <stdbool.h> #include "jpeglib.h" int main(int argc, char const *argv[]) { if (argc != 2) { printf("./可执行文件 <jpeg格式图片文件>\n"); return -1; } //打开液晶屏 int lcd_fd = open("/dev/fb0", O_RDWR); if (lcd_fd == -1) { perror("open"); return -1; } //获取液晶屏信息 struct fb_var_screeninfo vinfo; ioctl(lcd_fd, FBIOGET_VSCREENINFO, &vinfo); // 获取可变属性 int lcd_w = vinfo.xres; int lcd_h = vinfo.yres; int lcd_b = vinfo.bits_per_pixel/8; printf("该液晶屏宽:%d,高:%d, 每个像素点%d个字节\n", lcd_w, lcd_h, lcd_b); //进行内存映射 int *p = mmap(NULL, lcd_w * lcd_h * lcd_b, PROT_WRITE | PROT_READ, MAP_SHARED, lcd_fd, 0); if (p == (void *)-1) { perror("mmap"); return -2; } // 刷黑屏幕 memset(p, 0x00, 800 * 480 * 4); //(1)为jpeg对象分配空间并初始化 struct jpeg_decompress_struct cinfo; //解压jpeg的对象结构体 struct jpeg_error_mgr jerr; //定义错误结构体 cinfo.err = jpeg_std_error(&jerr); //错误处理结构体绑定 jpeg_create_decompress(&cinfo); //初始化jpeg的对象结构体 //(2)指定解压缩数据源 FILE *infile = fopen(argv[1], "r+"); if (infile == NULL) { perror("fopen jpeg"); return -3; } jpeg_stdio_src(&cinfo, infile);//指定解压缩数据源 //(3)获取文件信息 jpeg_read_header(&cinfo, true); //(4)为解压缩设定参数,包括图像大小,颜色空间 int n = 1; //缩小倍数 while(cinfo.image_width/n>lcd_w || cinfo.image_height/n>lcd_h) { n *= 2; } //设定的缩小倍数 cinfo.scale_num = 1; //分子 cinfo.scale_denom = n; //分母 // cinfo.out_color_space = JCS_GRAYSCALE; //颜色空间 printf("width1:%d height1:%d\n", cinfo.image_width, cinfo.image_height);//设定之前的宽高 //(5)开始解压缩 jpeg_start_decompress(&cinfo); printf("width:%d height:%d\n", cinfo.output_width, cinfo.output_height);//设定解压缩之后的宽高 //(6)取出数据(做相关的应用),安装一行一行去读取的 //output_components像素点大小 //申请能够存放一行数据的缓冲区 int row_size = cinfo.output_width*cinfo.output_components; char *buffer = (char *)malloc(row_size); //output_scanline当前读取行数 while(cinfo.output_scanline < cinfo.output_height) { //按行读取数据 jpeg_read_scanlines(&cinfo, (JSAMPARRAY)&buffer, 1); //将读取到的一行数据进行显示 int i = 0, j = 0; for (;j< cinfo.output_width; i+=3, j++) { //内存映射的方式 *(p+(cinfo.output_scanline-1)*lcd_w + j) = buffer[i+0]<<16| buffer[i+1]<<8| buffer[i+2]; } } //(7)解压缩完毕 jpeg_finish_decompress(&cinfo); //(8)释放资源 jpeg_destroy_decompress(&cinfo); munmap(p, lcd_w*lcd_h*lcd_b); close(lcd_fd); fclose(infile); free(buffer); return 0; }
2、拷贝需要用到的头文件
C 代码中包含了 jpeglib.h 头文件(#include “jpeglib.h”),因此我们需要拷贝库安装目录下的四个头文件(jconfig.h jerror.h jmorecfg.h jpeglib.h,路径:/home/Gnep/licheepi_zero/tools/include/),到自己应用程序的目录下。
cp /home/Gnep/licheepi_zero/tools/include/* ./
3、编译 C 代码
编译应用程序时,要增加动态库的链接和 -ljpeg 选项
arm-linux-gnueabihf-gcc imageshow.c -o imageshow -L /home/Gnep/licheepi_zero/tools/lib/ -ljpeg
四、验证测试
1、拷贝相关文件到开发板
①、将 imageshow、libjpeg.so.9、libjpeg.so.9.5.0拷贝到 tftpboot 目录中
cp imageshow /tftpboot/ cp /home/Gnep/licheepi_zero/tools/lib/*.so.* /tftpboot/
②、将 imageshow 、777.jpg、888.jpeg 拷贝到开发板上,将库安装目录下的 lib 目录下的 libjpeg.so.9 和 libjpeg.so.9.5.0 拷贝到开发板的 /usr/lib 目录中
tftp -g -l 777.jpg 192.168.25.25 tftp -g -l 888.jpeg 192.168.25.25 tftp -g -l imageshow 192.168.25.25 tftp -g -l libjpeg.so.9 192.168.25.25 tftp -g -l libjpeg.so.9.5.0 192.168.25.25 cp libjpeg.so.9 /usr/lib cp libjpeg.so.9.5.0 /usr/lib
2、显示图片
①、雪山照(800 * 480)
./imageshow 777.jpg
②、风景照(480* 272)
./imageshow 888.jpeg
五、资源自取
方式1:github 链接
https://github.com/Gnepuil79/licheepi.git
方式2:百度网盘
链接:https://pan.baidu.com/s/1GWuML5BpRJZ0MneXq9u2Gw
提取码:td2e