—>Linux常见标准函数接口见这篇<—

—>Linux常见系统IO函数接口见这篇<—

—>Linux简单硬件控制之LCD见这篇<—

—>Linux简单硬件控制之LCD见这篇<—

—>Linux图像处理之BMP格式图片见这篇<—

1.JPG格式基本介绍

  JPEG(Joint Photographic Experts Group)全称为联合图像专家组,是同名专家小组开发的一种图像压缩技术标准。与我们前面提到的BMP图像格式最大的不同就是BMP存储的图像数据是未压缩的,而JPEG采用压缩算法对图像数据进行处理,所以BMP的文件一般较大,而JPEG格式文件较小。JPEG与JPG都是同一种图像格式,采用的压缩算法是一种,只是某些标准有些变动,本质上是同一种。由于较小的图像文件更适合视频图像传输,而其中的图像数据已经经过压缩,我们不能像对BMP一样直接将图像信息和图像数据读取出来后直接写入LCD屏的fb0文件来实现在LCD屏显示图像,我们就需要学习一下JPEG编码解码。

2.JPEG编码解码库

  网上有一款开源JPEG编解码库——libjpeg,这个库是由UG小组维护开发的,完全使用C语言编写,但是由于是第三方库,标准库并没有相关函数接口,要想使用这个库需要我们自己完成libjpeg库的移植。一般库移植步骤为配置——编译——安装三步。

2.1源文件下载

  首先就是从网上下载源文件。一般库都是libxxx或xxxlib的命名习惯,我们想找jpeg相关的库可以在搜索引擎搜libjpeg,记住这种库由于是国外的不要看那些带中文的网站,一般都是广告。一般推荐代码托管网站有三个:sourceforge,github,gitee(github要科学上网)。
搜索输入libjpeg,我这里选择sourceforge。
在这里插入图片描述
  点击DOWNLOAD(这是zip压缩包,适用于Windos系统)Linux系统的伙伴点击libjpeg Website,最后选择一个tar.gz文件下载即可。
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
  我这里两种都下了,现在在windows系统下解压完成看一下README文件。这里有一个使用者文档,看一下它要我们读什么主要文档,这里我们主要读一下install.doc。libjpeg.doc和example.c在写程序时要用到,在它基础上改就可以了。
在这里插入图片描述
  打开install.doc看看,这里我是用UBUNTU的Linux系统,可以看到配置——编译——安装三步,与一般库移植思路一样。
在这里插入图片描述

2.1配置

  打开Ubuntu,打开MobaXterm,点击session选择SSH连接虚拟机,将刚刚下载的.tar.gz压缩包放到Linux系统文件夹(不能直接在共享文件夹里解压,否则会丢失;链接文件),可以在~目录创建一个文件夹来存放解压的文件。

  • 切换路径至压缩包所在目录:
    cd ~(假设在用户目录下)
  • 新建一个文件夹可以放安装得到的文件:
    mkdir libjpeg
  • 解压.tar.gz文件——终端输入命令:tar zxf jpegsrc.v9f.tar.gz
  • 切换到解压出来的jpeg-9f文件目录下,使用配置命令./configure,该命令有两个重要选项–prefix(用于指定安装路径)和–host(用于指定程序运行平台,比如我现在是Linux系统但是我要在Arm平台的板子上跑程序,即交叉编译):
    ./configure --prefix ~/libjpeg --host=arm-linux
  • 配置显示无错误即成功

2.2编译

  终端输入make执行编译,显示不报错即成功

2.3安装

  终端输入make install进行安装,显示不报错即成功。输入tree查看文件结构如下:其中我们待会写程序要用到的是库和头文件,可以把include和lib两个文件夹拖到windows系统,我们在windows系统使用VSCODE进行程序编写。
在这里插入图片描述

3.程序设计(以JPEG解码为例)

  新建main.c文件和README自述文件,打开example.c文件将示例代码复制到main.c文件里,接下来我们看libjpeg.doc文档,可以看到jpeg解压过程一共有8步:

  1. Allocate and initialize a JPEG decompression object.(创建一个解码对象并进行初始化,创建一个错误处理对象并与解码对象进行绑定)
  2. Specify the source of the compressed data (eg, a file).(打开待解码JPG图片,rb)
  3. Call jpeg_read_header() to obtain image info.(读取待解码JPG图片信息,即文件头)
  4. Set parameters for decompression.(设置解码参数(可选))
  5. jpeg_start_decompress(…)(开始解码)
  6. while (scan lines remain to be read)(循环读取解码对像颜色分量)
    jpeg_read_scanlines(…);
  7. jpeg_finish_decompress(…);(解码完成)
  8. Release the JPEG decompression object(释放解码对象)
    其中主要是第6步需要自己设计其他基本不变,而且JPEG存储颜色分量的方式是自上而下,与BMP相反。改动地方示例如下:
 int data=0;
    while (cinfo.output_scanline < cinfo.output_height) {
      /* jpeg_read_scanlines expects an array of pointers to scanlines.
       * Here the array is only one element long, but you could ask for
       * more than one scanline at a time if that's more convenient.
       */
      (void) jpeg_read_scanlines(&cinfo, buffer, 1);
      /* Assume put_scanline_someplace wants a pointer and sample count. */
      for(int i=0;i<cinfo.output_width;i++){
        data|=buffer[3*i]<<16;//R
        data|=buffer[3*i+1]<<8;//G
        data|=buffer[3*i+2];//B
        lcd_mp[800*starty+startx+800*(cinfo.output_scanline-1)+i]=data;
        data=0;
      }
      

    }
  int main(int argc,const char* argv[]){
    int lcd_fd=open("/dev/fb0",O_RDWR);
    lcd_mp=(int*)mmap(NULL,800*480*4,PROT_READ|PROT_WRITE,MAP_SHARED,lcd_fd,0);
    read_JPEG_file("demo.jpg",100,100);
    return 0;
  }

注意:在编译过程如果报错找不到头文件或库可以用-I指定头文件路径-L指定库路径-l指定库名字,这是因为系统是先在当前路径下找再去/usr/include路径下找,如果这两个路径都没有找到就报错了。

Logo

智能硬件社区聚焦AI智能硬件技术生态,汇聚嵌入式AI、物联网硬件开发者,打造交流分享平台,同步全国赛事资讯、开展 OPC 核心人才招募,助力技术落地与开发者成长。

更多推荐