jpg解码库移植过程详解
Posted 正在起飞的蜗牛
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了jpg解码库移植过程详解相关的知识,希望对你有一定的参考价值。
1、jpg解码库的源码获取
(1)可以从网站下载:http://www.photopost.com/jpegsrc.v6b.tar.gz;
(2)我下面的移植过程是根据jpegsrc.v6b.tar.gz版本的jpg解码库移植的,如果是其他版本的jpg解码库,配置编译过程可能会有所差异,需要自行解决,如果没什么特别的需求,v6b版本的jpg解码库完全是 够用的;
(3)如果想直接要源码,可以私信我;
2、jpg解码库的编译
解压源码:
tar -zxvf jpegsrc.v6b.tar.gz
第一步:
./configure --prefix=/opt/libdecode --exec-prefix=/opt/libdecode --enable-shared --enable-static -build=i386 -host=arm
--prefix=/opt/libdecode:指定生成的jpg库的安装目录
--exec-prefix=/opt/libdecode:指定生成的二进制文件的存放目录,一般和"--prefix"选项一致
--enable-shared:要生成动态库
--enable-static:要生成静态库
-build=i386:编译源码所在的环境是i386体系的机器
-host=arm:编译得到的库要在arm架构的机器上运行
第二步:
CC=gcc 改为 CC=arm-linux-gcc
AR=ar rc 改为 AR=arm-linux-ar rc
AR2=ranlib 改为 AR2=arm-linux-ranlib
第三步:
mkdir /opt/libdecode/lib
mkdir /opt/libdecode/include
第四步:
make
第五步:
make install-lib
(1)jpg解码库源码的配置文件是configure,Makefile刚解压时是没有的,需要调用configure文件去生成Makefile,会根据调用configure文件时指定的参数去生成特定的Makefile,比如Makefile中可以找到你传入的安装路径;
(2)嵌入式开发要根据平台去选择适配的交叉编译工具链,所以对生成的Makefile要修改编译工具;
(3)在指定的安装目录中,需要提前创建lib和include目录,其中lib是用来存放生成的动态库、静态库的,include是用来存放头文件的;
(4)最后就是编译和安装,在指定的安装目录的lib中有生成的动态库,在include目录下生成头文件;
3、jpg解码库编译后的产物
(1)在指定的安装目录中,include目录下是头文件,lib目录下是生成的动态库;
(2)在lib目录下有动态库和链接文件,真正的jpg解码库是libjpeg.so.62;
4、jpg解码库的移植
(1)将编译得到的include目录下的头文件,和lib目录下动态库添加到你的代码工程中,并且动态库还需要部署到可执行程序的运行环境中;
(2)编写调用jpg解码库去编解码jpg图片的函数,
5、jpg解码库的API调用
(1)想要使用编译得到的libjpg.so库去编解码jpg文件,需要去结合include目录下得到的头文件的jpg解码库里的example.c文件;
(2)examle.c文件里是示例代码,里面有jpg图片的各种操作函数,结合include目录下的头文件对API接口描述去理解;
(3)还想了解更仔细可以去阅读jpg源码目录下的libjpg.doc文件,里面有对jpg解码库更详细的介绍,不过都是英文,英文不是很6就别去看了;
6、jpg解码库的使用示例
// 结构体用来封装一个图片的各种信息
typedef struct pic_info
char *pathname; // 图片在文件系统中的路径名+文件名
unsigned int width; // 图片分辨率之宽
unsigned int height; // 图片分辨率之高
unsigned int bpp; // 图片bpp
char *pData; // 指向图片有效数据存储的buf数据
pic_info;
typedef struct my_error_mgr
struct jpeg_error_mgr pub; /* "public" fields */
// jmp_buf setjmp_buffer; /* for return to caller */
*my_error_ptr;
// 函数功能: 判断一个图片文件是不是jpg图片
// 函数参数: path是图片文件的pathname
// 返回值: 如果是jpg则返回0,不是则返回1,错误返回-1
int is_jpg(const char *path)
FILE *file = NULL;
char buf[2] = 0;
// 打开文件
file = fopen(path, "rb");
if (NULL == file)
fprintf(stderr, "fopen %s error.\\n", path);
fclose(file);
return -1;
// 读出前2个字节
fread(buf, 1, 2, file);
debug("read: 0x%x%x\\n", buf[0], buf[1]);
// 判断是不是0xffd8
if (!((buf[0] == 0xff) && (buf[1] == 0xd8)))
fclose(file);
return 1; // 不是jpg图片
// 是0xffd8开头,就继续
// 文件指针移动到倒数2个字符的位置
fseek(file, -2, SEEK_END);
// 读出2个字节
fread(buf, 1, 2, file);
debug("read: 0x%x%x\\n", buf[0], buf[1]);
// 判断是不是0xffd9
if (!((buf[0] == 0xff) && (buf[1] == 0xd9)))
fclose(file);
return 1; // 不是jpg图片
fclose(file);
return 0;
// 自己定义的错误处理函数
METHODDEF(void)my_error_exit (j_common_ptr cinfo)
//my_error_ptr myerr = (my_error_ptr) cinfo->err;
//(*cinfo->err->output_message) (cinfo);
fprintf(stderr, "my_error_exit\\n");
//longjmp(myerr->setjmp_buffer, 1);
/*
* 函数功能: 解码jpg图片,并将解码出来的数据存储
* 函数参数: pPIC,记录源jpg图片,解码出来的图片宽高、图片数据缓冲区等信息
* 返回值 : 成功解码则返回0,失败则返回-1
*/
int jpg_analyze(struct pic_info *pPic)
struct jpeg_decompress_struct cinfo; // cinfo贯穿整个解码过程的信息记录和传递的数据结构
struct my_error_mgr jerr; // 错误处理的
//JSAMPARRAY buffer = NULL; // 指向解码行数据的指针
char * buffer = NULL;
FILE * infile; // 指向fopen打开源jpg图片文件的指针
int row_stride, ret; // 解码出来的一行图片信息的字节数
// 第一步: 检测给的图片是不是jpg图片
ret = is_jpg(pPic->pathname);
if (ret != 0)
debug("%s not jpg picture!\\n", pPic->pathname);
return -1;
if ((infile = fopen(pPic->pathname, "rb")) == NULL)
fprintf(stderr, "can't open %s\\n", pPic->pathname);
return -1;
// 第1步: 错误处理函数部分的绑定
cinfo.err = jpeg_std_error(&jerr.pub);
jerr.pub.error_exit = my_error_exit;
// 给解码器做必要的内存分配和数据结构的初始化
jpeg_create_decompress(&cinfo);
// 第2步: 将fopen打开的源jpg图片和解码器相关联
jpeg_stdio_src(&cinfo, infile);
// 第3步: 读jpg文件头
jpeg_read_header(&cinfo, TRUE);
// 第4步: 启动解码器
jpeg_start_decompress(&cinfo);
debug("image resolution: %d * %d, bpp/8=%d.\\n",
cinfo.output_width, cinfo.output_height, cinfo.output_components);
// 解码出来的数据一行的字节数
row_stride = cinfo.output_width * cinfo.output_components;
//buffer = (*cinfo.mem->alloc_sarray)((j_common_ptr) &cinfo, JPOOL_IMAGE, row_stride, 1);
buffer = (char *)malloc(row_stride);
if (NULL == buffer)
fprintf(stderr, "cinfo.mem->alloc_sarray error.\\n");
return -1;
// 第5步: 逐行解码,并将解码出的数据丢到事先准备好的缓冲区去
while (cinfo.output_scanline < cinfo.output_height)
// 解码一行信息,并且丢到buffer中
//jpeg_read_scanlines(&cinfo, buffer, 1);
jpeg_read_scanlines(&cinfo, &buffer, 1);
// 将buffer中这一行数据移走到别的地方去暂存或者使用,总之是要腾出buffer空间
// 来给循环的下一次解码一行来使用
memcpy(pPic->pData + (cinfo.output_scanline-1) * row_stride, buffer, row_stride);
// 第6步: 解码完了,做各种清理工作
jpeg_finish_decompress(&cinfo);
jpeg_destroy_decompress(&cinfo);
fclose(infile);
// jpg图片的数据记录下来
pPic->width = cinfo.output_width;
pPic->height = cinfo.output_height;
pPic->bpp = cinfo.output_components * 8;
return 0;
(1)上面的代码是从jpg图片中提取RGB数据的函数,也是参考example.c文件修改得到,可以直接移植;
(2)想要学习jpg解码库在实际项目中的应用,参考博客:;
7、参考资源
《朱友鹏——嵌入式核心课程》
以上是关于jpg解码库移植过程详解的主要内容,如果未能解决你的问题,请参考以下文章