0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

Linux应用开发-libjpeg库交叉编译与使用

DS小龙哥-嵌入式技术 来源:DS小龙哥-嵌入式技术 作者:DS小龙哥-嵌入式技 2022-08-14 09:18 次阅读

1. 前言

在开发板上如果想要显示jpeg格式的图片,必须用到libjpeg库,不可能自己去编写jpg的解码代码。

libjpeg是一个完全用C语言编写的库,包含了被广泛使用的JPEG解码、JPEG编码和其他的JPEG功能的实现。这个库由独立JPEG工作组维护。

image-20220124161832316

源码获取地址: www.ijg.org/

image-20220124161130968

2. 安装编译步骤

下面介绍libjpeg库交叉编译器的详细步骤。

下载源码包,将源码包拷贝到linux系统下。比如:jpegsrc.v9b.tar.gz
​
②解码源码包
[root@xiaolong jpeg-9b]# tar xf jpegsrc.v9b.tar.gz 
​
③配置源码
[root@xiaolong jpeg-9b]# 
./configure --prefix=/usr/local/lib CC=arm-linux-gcc --host=arm-linux --enable-shared --enable-static
注意:
/usr/local/lib 表示指定源码最终安装的路径。
​
④编译源码
[root@xiaolong jpeg-9b]# make
​
⑤安装源码
[root@xiaolong jpeg-9b]# make install
​
安装好的目录如下:(/usr/local/lib)
[root@xiaolong lib]# ls
bin  include  lib  share
​
文件结构:
[root@xiaolong lib]# pwd
/usr/local/lib
[root@xiaolong lib]# tree ./
./
├── bin
│  ├── cjpeg
│  ├── djpeg
│  ├── jpegtran
│  ├── rdjpgcom
│  └── wrjpgcom
├── include
│  ├── jconfig.h
│  ├── jerror.h
│  ├── jmorecfg.h
│  └── jpeglib.h
├── lib
│  ├── libjpeg.a
│  ├── libjpeg.la
│  ├── libjpeg.so -> libjpeg.so.9.2.0
│  ├── libjpeg.so.9 -> libjpeg.so.9.2.0
│  └── libjpeg.so.9.2.0
└── share
   └── man
     └── man1
       ├── cjpeg.1
       ├── djpeg.1
       ├── jpegtran.1
       ├── rdjpgcom.1
       └── wrjpgcom.1
​
6 directories, 19 files
复制代码

3. 使用步骤

1.将以下几个头文件拷贝到需要编译的工程目录下:
jmorecfg.h、jpeglib.h、jerror.h、jconfig.h
​
2.将以下头文件加到工程中:
#include "jpeglib.h"
​
3./将usr/local/lib目录下的生成的库文件拷贝到开发板的lib目录下。
​
4.编译选择--任意一种:
arm-linux-gcc -o app show_jpeg.c -L/usr/local/lib
arm-linux-gcc -o app show_jpeg.c -l:libjpeg.so.9
arm-linux-gcc show_jpeg.c -ljpeg -static -o app
​
show_jpeg.c是要编译的源文件
app 是生成的目标文件。
 -static 表示静态生成
#include 头文件定义解压缩使用的数据结构信息。
复制代码

4. 使用案例

4.1 使用libjpg库编码-RGB数据保存为jpg图片

下面这个是利用libjpeg封装的一个方便函数,用于将传入的rgb数据压缩编码成jpg文件保存,一般用与屏幕截屏、相机拍照等地方。

#include 
#define JPEG_QUALITY 100 //图片质量
 
int savejpg(uchar *pdata, char *jpg_file, int width, int height)
{ //分别为RGB数据,要保存的jpg文件名,图片长宽
  int depth = 3;
  JSAMPROW row_pointer[1];//指向一行图像数据的指针
  struct jpeg_compress_struct cinfo;
  struct jpeg_error_mgr jerr;
  FILE *outfile;
 
  cinfo.err = jpeg_std_error(&jerr);//要首先初始化错误信息
  //* Now we can initialize the JPEG compression object.
  jpeg_create_compress(&cinfo);
 
  if ((outfile = fopen(jpg_file, "wb")) == NULL)
   {
    fprintf(stderr, "can't open %s\n", jpg_file);
    return -1;
   }
  jpeg_stdio_dest(&cinfo, outfile);
 
  cinfo.image_width = width;       //* image width and height, in pixels
  cinfo.image_height = height;
  cinfo.input_components = depth;  //* # of color components per pixel
  cinfo.in_color_space = JCS_RGB;   //* colorspace of input image
  jpeg_set_defaults(&cinfo);
 
  jpeg_set_quality(&cinfo, JPEG_QUALITY, TRUE ); //* limit to baseline-JPEG values
  jpeg_start_compress(&cinfo, TRUE);
 
  int row_stride = width * 3;
  while (cinfo.next_scanline < cinfo.image_height)
     {
             row_pointer[0] = (JSAMPROW)(pdata + cinfo.next_scanline * row_stride);//一行一行数据的传,jpeg为大端数据格式
             jpeg_write_scanlines(&cinfo, row_pointer, 1);
     }
  
     jpeg_finish_compress(&cinfo);
     jpeg_destroy_compress(&cinfo);//这几个函数都是固定流程
     fclose(outfile);
     return 0;
 }
复制代码

4.2 LCD显示jpg格式图片

下面代码利用libjpeg库解码传入的jpg文件,得到rgb数据,再绘制到LCD屏上显示。

image-20220124161712017
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
​
// 24位色和16位色转换宏
// by cheungmine
#define RGB888_TO_RGB565(r,g,b)  ((WORD)(((WORD(r)<<8)&0xF800)|((WORD(g)<<3)&0x7E0)|((WORD(b) >> 3))))
#define RGB_TO_RGB565(rgb)    ((WORD)(((((WORD)((rgb)>>3))&(0x1F))<<11)|((((WORD)((rgb)>>10))&(0x3F))<<5)|(((WORD)((rgb)>>19))&(0x1F))))
#define RGB888_TO_RGB555(r,g,b)  ((WORD)(((WORD(r)<<7)&0x7C00)|((WORD(g)<<2)&0x3E0)|((WORD(b)>>3))))
#define RGB_TO_RGB555(rgb)    ((WORD)(((((WORD)((rgb)>>3))&(0x1F))<<10)|((((WORD)((rgb)>>11))&(0x1F))<<5)|(((WORD)((rgb)>>19))&(0x1F))))
#define RGB555_TO_RGB(rgb555)   ((DWORD)(((BYTE)(((rgb555)>>7)&0xF8)|((WORD)((BYTE)(((rgb555)>>2)&0xF8))<<8))|(((DWORD)(BYTE)(((rgb555)<<3)&0xF8))<<16)))
 #define RGB565_TO_RGB(rgb565)    ((DWORD)(((BYTE)((((rgb565)&0xF800)>>11)<<3)|((WORD)((BYTE)((((rgb565)&0x07E0)>>5)<<2))<<8))|(((DWORD)(BYTE)(((rgb565)&0x001F)<<3))<<16)))
 unsigned short  rgb888_to_rgb555(unsigned char red,unsigned char green,unsigned char blue);
 unsigned short  rgb888_to_rgb565(unsigned char red,unsigned char green,unsigned char blue);
                        
                                  
 /*--------------------------------------------------------------
                         JPEG图片显示
 ---------------------------------------------------------------*/
 static unsigned char *fbmem = NULL;
 static struct fb_var_screeninfo var;//定义可变参数结构体来接收驱动传过来的可变参数结构体
 static struct fb_fix_screeninfo fix;//定义固定参数结构体来接收驱动传过来的固定参
 ​
 //显示JPEG
 int show_jpeg(unsigned char *file)
 {
     struct jpeg_decompress_struct cinfo; //存放图像的数据
     struct jpeg_error_mgr jerr; //存放错误信息
     FILE           *infile;
     unsigned int *dst=fbmem;
     unsigned char  *buffer;
     unsigned int    x;
     unsigned int    y;
     /*
     * 打开图像文件
     */
     if ((infile = fopen(file, "rb")) == NULL) {
         fprintf(stderr, "open %s failed\n", file);
         exit(-1);
     }
 ​
     /*
      * init jpeg压缩对象错误处理程序
      */
     cinfo.err = jpeg_std_error(&jerr); //初始化标准错误,用来存放错误信息
     jpeg_create_decompress(&cinfo);    //创建解压缩结构信息
      
      
     /*
      * 将jpeg压缩对象绑定到infile
      */
     jpeg_stdio_src(&cinfo, infile);
 ​
     /*
      * 读jpeg头
      */
     jpeg_read_header(&cinfo, TRUE);
    
     /*
         *开始解压
         */
     jpeg_start_decompress(&cinfo);
     
     printf("JPEG高度: %d\n",cinfo.output_height);
     printf("JPEG宽度: %d\n",cinfo.output_width);
     printf("JPEG颜色位数(字节单位): %d\n",cinfo.output_components);
     
     //为一条扫描线上的像素点分配存储空间
     buffer = (unsigned char *) malloc(cinfo.output_width *cinfo.output_components);
     y = 0;
 ​
     //将图片内容显示到framebuffer上
     while (cinfo.output_scanline < cinfo.output_height) 
     {
          
          //读取一行的数据    
         jpeg_read_scanlines(&cinfo, &buffer, 1);
         
         //判断LCD屏的映射空间像素位数
         if (var.bits_per_pixel == 32) 
         {
             unsigned int  color;
             for (x = 0; x < cinfo.output_width; x++) {
                 color = buffer[x * 3 + 0] << 16  |
                         buffer[x * 3 + 1] << 8   |
                         buffer[x * 3 + 2] << 0;
                 dst = ((unsigned int *) fbmem + y * var.xres + x);
                 *dst = color;
             }
         }
         y++;                                   // 显示下一个像素点
     }
     
     /*
      * 完成解压,摧毁解压对象
      */
     jpeg_finish_decompress(&cinfo); //结束解压
     jpeg_destroy_decompress(&cinfo); //释放结构体占用的空间
 ​
     /*
      * 释放内存缓冲区
      */
     free(buffer);
 ​
     /*
      * 释放内存缓冲区
      */
     fclose(infile);
     return 0;
 }
 ​
 /*映射LCD显示的内存空间*/
 unsigned char * fmem(unsigned char *fbname)
 {
     int fb;
     unsigned char *mem;
     fb = open(fbname,2);
     if(fb<0)
     {
         printf("open fbdev is error!!!\n");
         return NULL;
     }
     ioctl(fb,FBIOGET_VSCREENINFO,&var);//获取固定参数结构体放在var结构体中
     ioctl(fb,FBIOGET_FSCREENINFO,&fix);//获取固定参数,存放在fix结构体中
     mem = (unsigned char *)mmap(NULL,fix.smem_len,PROT_READ|PROT_WRITE,MAP_SHARED,fb,0);
     if(mem == (unsigned char *)-1)
     {
         printf("fbmmap is error!!!\n");
         munmap(mem,fix.smem_len);
         return NULL;
     }
     return mem;
 }
 ​
 ​
 int main (int argc,char** argv) //./a.out /dev/fb0 xxx.bmp
 {
     int fb ,i=4;
     char key;
     unsigned char * bmpmem;
     if(argc!=3)
     {
         printf("Usage: ./%s  \n",argv[0]);
         return -1;
     }
     fbmem =  fmem(argv[1]);        //将缓冲设备映射到内存进行写入 
     memset(fbmem,0x00,fix.smem_len);//清屏函数 往映射的地址填充fix.sem_len大小的0xff颜色进去
     show_jpeg(argv[2]);           //程序运行时显示主界面
     return 0;
 }

审核编辑:汤梓红

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • Linux
    +关注

    关注

    87

    文章

    10988

    浏览量

    206725
  • C语言
    +关注

    关注

    180

    文章

    7528

    浏览量

    128433
  • 编译
    +关注

    关注

    0

    文章

    614

    浏览量

    32374
收藏 人收藏

    评论

    相关推荐

    Linux系统下交叉编译工具链的安装方法

    今天主要和大家聊一聊,如何使用Linux系统下的交叉编译工具链的方法。
    发表于 11-21 09:30 2402次阅读

    【OK210试用体验】Arm交叉编译环境

    失败,因为没有linux的实现。通常用c开发,重新实现c往往不现实,需要交叉编译工具链已实现标准c
    发表于 11-01 01:36

    交叉编译器解析

    ,不知道C是什么 .五:安装交叉工具链实例1,将arm-cortex_a8-linux-gnueabi.tar.bz2交叉编译器压缩包复制
    发表于 12-21 16:57

    【芯灵思A83T试用体验】3、交叉编译OpenCV2.4.9

    opencv-unix到Linux宿主机上,利用交叉编译器arm-linux-gcc来将opencv编译成可以在ARM平台上运行的链接
    发表于 05-21 22:17

    【NanoPi NEO2试用体验】libjpeg编译和安装

    的是libjpegLibjpeg是一款常用的jpeg图像压缩和解压的函数,安装libjpeg可以直接使用apt-get等命令也可以下载libjp
    发表于 06-22 09:12

    嵌入式Linux开发板截屏工具gsnap移植PC机

    嵌入式Linux开发板截屏工具gsnap移植PC机:ubuntu16.04.2 LTS开发板:i.MX6UL交叉编译器:arm-
    发表于 11-04 07:27

    交叉编译linux内核(raspberry_3.6.y)

    一步一步教你交叉编译linux内核,RPI的内核编译教程,小众的东西了
    发表于 11-03 17:58 0次下载

    arm-linux交叉编译环境解析

    交叉编译环境介绍 交叉编译是嵌入式开发过程中的一项重要技术,它的主要特征是某机器中执行的程序代码不是在本机
    发表于 10-31 11:26 7次下载

    Linux】嵌入式Linux系统的移植(上篇:交叉编译器、连接方式)

    的移植要点搭建交叉开发环境bootloader的选择与移植kernel的设置、编译、移植和调试根文件系统的制作嵌入式Linux系统的移植基本步骤确定目标机、主机的连接方式安装
    发表于 11-01 16:57 14次下载
    【<b class='flag-5'>Linux</b>】嵌入式<b class='flag-5'>Linux</b>系统的移植(上篇:<b class='flag-5'>交叉</b><b class='flag-5'>编译</b>器、连接方式)

    嵌入式Linux开发环境搭建-(4)安装交叉编译工具链

    在ubuntu16.04.2中,安装交叉编译工具链在ubuntu中进行嵌入式应用程序开发,安装交叉编译工具链是不可缺少的一个环节。PC操作系
    发表于 11-02 11:06 18次下载
    嵌入式<b class='flag-5'>Linux</b><b class='flag-5'>开发</b>环境搭建-(4)安装<b class='flag-5'>交叉</b><b class='flag-5'>编译</b>工具链

    嵌入式Linux开发环境搭建-3-安装交叉编译工具链

    嵌入式Linux开发环境搭建-安装交叉编译工具链1、下载2、解压3、设置环境变量参考文档ubuntu下安装交叉
    发表于 11-02 13:21 12次下载
    嵌入式<b class='flag-5'>Linux</b><b class='flag-5'>开发</b>环境搭建-3-安装<b class='flag-5'>交叉</b><b class='flag-5'>编译</b>工具链

    Linux下播放器开发-交叉编译Mplayer

    如何将MplayerJ交叉编译移植到嵌入式开发板上运行,在命令行上正常的播放视频,LCD屏采用的帧缓冲驱动框架渲染图像。
    的头像 发表于 08-14 09:12 2310次阅读

    Linux应用开发-串口下载命令rzsz交叉编译

    rz/sz工具是通过Zmodem协议传输文件的命令,常用于Linux与windows之前的数据传输。 这篇文章就介绍如何在交叉编译rz/sz命令,并在Linux
    的头像 发表于 08-14 09:20 1790次阅读

    Linux交叉编译选项与源码与目标文件分离

    交叉编译选项 编译Linux,通常只需要运行 make menuconfig 配置要编译的模块,然后运行 make 。
    的头像 发表于 09-27 11:48 406次阅读

    linux4.1.15交叉编译链描述及使用方法

    飞凌嵌入式OKMX6ULL-C开发Linux4.1.15交叉编译链描述及使用方法
    发表于 03-22 11:18 3次下载