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

举报
DS小龙哥 发表于 2022/01/24 18:05:23 2022/01/24
【摘要】 在开发板上如果想要显示jpeg格式的图片,必须用到libjpeg库,不可能自己去编写jpg的解码代码。 libjpeg是一个完全用C语言编写的库,包含了被广泛使用的JPEG解码、JPEG编码和其他的JPEG功能的实现。这个库由独立JPEG工作组维护。

1. 前言

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

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

image-20220124161832316

**源码获取地址:**http://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 <jpeglib.h>头文件定义解压缩使用的数据结构信息。

4. 使用案例

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

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

#include <jpeglib.h>
#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 <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <sys/ioctl.h>
#include <linux/fb.h>
#include <sys/mman.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <stdlib.h>
#include <jpeglib.h>
#include <jerror.h>

// 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 <fbdev>  <bmpname> \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;
}
【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。