`

libjpeg用法

 
阅读更多

    libjpeg是一个完全用C语言编写的库,包含了被广泛使用的JPEG解码、JPEG编码和其他的JPEG功能的实现。这个库由独立JPEG工作组维护。最新版本号是6b,于1998年发布。可以参考维基百科关于libjpeg的介绍http://zh.wikipedia.org/wiki/Libjpeg

libjpeg库的数据结构
    用libjpeg库解码jpeg数据的时候,最重要的数据类型为struct jpeg_decompress_struct,一般变量定义成cinfo变量,该变量保存着jpeg数据的详细信息,也保存着解码之后输出数据的详细信息。一般情况下,每次调用libjpeg库API的时候都需要把这个变量作为第一个参数传入。另外用户也可以通过修改该变量来修改libjpeg行为,比如输出数据格式,libjpeg库可用的最大内存等等。

libjpeg库的使用
1、设置出错处理函数
    “天有不测风云”,我们使用libjpeg库的时候难免会产生错误,所以我们在使用libjpeg解码之前,首先要做好错误处理。在libjpeg库中,实现了默认错误处理函数,当错误发生时,比如如果内存不足(非常可能发生,后面会介绍)等,则默认错误处理函数将会调用exit函数结束整个进程,详细内容可以参考jerror.c文件。这个对于很多用户来说这样的特性是不合适的,不过libjpeg提供了接口让我们注册自定义错误处理函数。

    在C语言中没有C++的异常处理机制,但是提供了setjmp和longjmp机制来实现类似的功能,如果你对这个机制不熟悉的话,请查阅C语言手册。

struct my_error_mgr {
    struct jpeg_error_mgr pub;    /* "public" fields */
    jmp_buf setjmp_buffer;    /* for return to caller */
};
typedef struct my_error_mgr * my_error_ptr;
cinfo.err = jpeg_std_error(&jerr.pub);
jerr.pub.error_exit = my_error_exit;
if (setjmp(jerr.setjmp_buffer)) {
    jpeg_destroy_decompress(&cinfo);
    fclose(infile);
    return -1;
}

 

    上述代码中的重点在于我们向libjpeg注册了一个my_error_exit回调函数,当发生错误的时候,该回调函数将会被调用。然后我们调用setjmp函数,设置一个返回点。这样我们在my_error_exit回调函数处理完错误信息之后,就可以调用longjmp函数返回到这里,在这个返回点进行资源的释放(非常重要,否则将会内存泄漏)。我们再看看my_error_exit回调函数的实现:

METHODDEF(void) my_error_exit (j_common_ptr cinfo)
{
    my_error_ptr myerr = (my_error_ptr) cinfo->err;
    (*cinfo->err->output_message) (cinfo);
    longjmp(myerr->setjmp_buffer, 1);
}

 

    可以通过检查cinfo->err->msg_code的值来判断错误类型,进行相应的处理。本例中只是简单的打印一个错误信息。最后调用longjmp跳转到setjmp调用的地方。

2、初始化解码对象
    要使用libjpeg解码jpeg数据,这步是必须要做的。

FILE * infile;
if ((infile = fopen(filename, "rb")) == NULL) {
    fprintf(stderr, "can't open %s\n", filename);
    return -1;
}
jpeg_create_decompress(&cinfo);

 

    这步之后,如果结束解码或者出错之后,需要调用jpeg_destroy_decompress销毁解码对象,否则将会内存泄漏。
3、初始化源数据
    在libjpeg库中仅仅提供了文件作为输入数据的接口,在example.c中代码如下:
jpeg_stdio_src(&cinfo, infile);
    这个设计我个人觉得非常不合理,我觉得一个友好的库,需要能够接受各式各样的输入(内存数据,网络数据等等)。比较友好的做法是提供几种常用的输入数据支持(在libjpeg中如:文件输入等)。然后还要提供一个用户注册自定义输入函数(回调函数)的接口,这样库就可以适配现实生活中各式各样的输入数据类型了。Simon也在以前的博文中写过怎样修改libjpeg库,使之能够解码内存buffer中的jpeg数据,请参考《LibJpeg解码内存中的Jpeg数据》
http://my.unix-center.net/~Simon_fu/?p=565。当然Simon没有扩展libjpeg库让其支持用户注册自定义输入函数(回调函数),有兴趣的朋友可以自行实现。
4、读取jpeg文件的头信息
    这个和初始化解码对象一样,是必须要调用的,是约定,没什么好说的。

jpeg_read_header(&cinfo, TRUE);

 
5、设置解码参数
    很多情况下,这步非常重要。比如设置输出格式,设置scale(缩放)等等功能都是在这一步设置。参数设置通过修改上步得到cinfo的值来实现。这里简单介绍一下一些常用的字段。out_color_space:输出的颜色格式,libjpeg定义如下:

typedef enum {
    JCS_UNKNOWN,        /* error/unspecified */
    JCS_GRAYSCALE,        /* monochrome */
    JCS_RGB,        /* red/green/blue */
    JCS_YCbCr,        /* Y/Cb/Cr (also known as YUV) */
    JCS_CMYK,        /* C/M/Y/K */
    JCS_YCCK,        /* Y/Cb/Cr/K */
    #ifdef ANDROID_RGB
         JCS_RGBA_8888,  /* red/green/blue/alpha */
        JCS_RGB_565     /* red/green/blue in 565 format */
    #endif
 } J_COLOR_SPACE;

 
我们可以看出谷歌在Android扩展了几种输出格式,那么如果你需要的颜色格式输出格式libjpeg不支持(比如:YUYV等颜色格式),那么请参考Android对libjpeg的扩展自行修改,不用担心复杂性,实现起来比较easy。请重点研究jdcolor.c文件中的jinit_color_deconverter函数。

scale_num,scale_denom:因为实际的显示设备千变万化,我们可能需要根据实际情况对输出数据进行一些缩放才能够显示。libjpeg支持对输出数据进行缩放(scale),这个变量就是用来设置缩放的参数。目前libjpeg支持1/2,1/4,1/8三种缩放。

mem:可以指定内存管理相关的内容,比如分配和释放内存,指定libjpeg可以使用的最大内存。默认情况下不同的平台下面都有一个libjpeg默认最大可用内存值,比如Android平台上面该值为10000000L(10M),请参考jmemxxxx.c文件中的DEFAULT_MAX_MEM,了解不同平台的默认最大内存值。通过修改mem->pub.max_memory_to_use的值,库的使用者可以自定义libjpeg可以使用的最大内存值。

6、开始解码
    经过前面的参数设置,我们可以开始解码了,没有什么好说的。
jpeg_start_decompress(&cinfo);

7、读取解码数据(我们打印到终端看看)

    buffer = (unsigned char *) malloc(cinfo.output_width * cinfo.output_components);
    while (cinfo.output_scanline < cinfo.output_height) {
        jpeg_read_scanlines(&cinfo, &buffer, 1);
        for (i=0; i<cinfo.output_width; i++) {
            printf("%02X%02X%02X ", buffer[i*3], buffer[i*3+1], buffer[i*3+2]);
            if (0 == ((i+1) % 10) || i == cinfo.output_width-1) {
            printf("\n");
            }
        }
        printf("least:%d\n\n", cinfo.output_height-cinfo.output_scanline);
    }

  

    请注意虽然函数jpeg_read_scanlines可以指定一次读多少行,但是目前该函数还是只能支持一次只读1行。

8、结束解码

jpeg_finish_decompress(&cinfo);

 
9、释放解码对象

jpeg_destroy_decompress(&cinfo);

 
   至此一个jpeg数据已经解析完成了。虽然步骤不少但是对于常规的使用还是比较简单的。

总结
    libjpeg对于baseline的jpeg数据解码比较好,但是解码progressive的jpeg数据的时候,对内存的需求比较大(我测试过的progressive的图片曾经发现过消耗70M内存)。如果你的硬件能够有硬件解码jpeg的能力,请尽可能使用硬件解码jpeg数据。
    简单的说baseline   jpeg要全部下载后才能观看;progressive   jpeg采用了类似fgs的技术,可以先传个质量粗糙的,然后逐渐精细,直至全部传完。举个例子,浏览有些网页时,看到图片一行行的出现,但都很清晰,一般都是baseline的,而如果开始就是一大块,但就像有好多马赛克似的,看不清楚,然后慢慢就好了,这种一般就是progressive的了

 

 

备注:附件里test.rar里面是test.c文件,包含了示例代码,我测试通过了。内存不用设置的时候,也能处理1.68MB的图片,更大的没试过。jpegsrc.v6b.tar.gz是从官网http://sourceforge.net/projects/libjpeg下载的linux上编译通过了的库源码,如果在linux上用,请不要下载官网的.zip文件,那个在linux下面编译会出错。官网下载地址:http://sourceforge.net/projects/libjpeg/files/libjpeg/6b/jpegsrc.v6b.tar.gz/download 打开是个倒计时下载的。

分享到:
评论

相关推荐

    libjpeg库配置和使用

    ### libjpeg库配置与使用详解 #### 一、libjpeg简介 libjpeg 是一个广泛使用的开源库,主要用于处理 JPEG 图像格式。它支持 JPEG 图像的...掌握 libjpeg 的使用方法对于开发涉及到图像处理的应用程序来说非常重要。

    libjpeg9a_libjpeg-9a_

    标题中的"libjpeg9a_libjpeg-9a_"提及的是libjpeg库的9a版本,这是一个广泛使用的开源库,主要用于处理JPEG(Joint Photographic Experts Group)图像格式。JPEG是一种常用的有损压缩方法,广泛应用于数码照片和网页...

    libjpeg9a_libjpeg-9a_wechat_blowqme_

    本文将深入探讨libjpeg9a的核心特性、使用方法以及在微信BlowQme中的应用。 一、libjpeg9a库介绍 libjpeg9a是libjpeg库的一个重要升级,它支持JPEG标准的多种特性,包括基本的YCbCr颜色空间转换、DCT(离散余弦...

    图像解码之一——使用libjpeg解码jpeg图片1

    JPEG(Joint Photographic Experts Group)是一种广泛使用的图像压缩标准,libjpeg是一个用于处理JPEG图像的C语言库,提供了JPEG编码和解码功能。本文将详细介绍如何使用libjpeg库解码JPEG图片。 首先,要使用...

    在Linux控制台下使用libjpeg显示JPEG图像在framebuffer上

    ##### 3.2 libjpeg使用方法 **安装与集成** - 在Linux系统中,可以通过包管理器安装libjpeg库,例如使用`apt-get install libjpeg-dev`命令。 - 在项目中包含必要的头文件并链接libjpeg库。 **基本功能** - **解码...

    libjpeg.lib在c++Builder中的使用

    从网上下载的libjpeg.lib不能直接在C++Builder中使用,这个资源有用C++Builder生成bcb版本的libjpeg.lib的方法,同时还有C++Builder版本下jpeg编解码的函数示例,文件方式和流方式的rgb转jpg,jpg转rgb,jpeg转yv12...

    Libjpeg demo(AndroidStudio)

    Libjpeg是一个广泛使用的开源库,主要用于JPEG图像编码和解码。在Android开发中,特别是在处理图像相关的应用时,Libjpeg库的运用显得尤为重要。本篇将深入探讨Libjpeg在Android Studio中的集成与使用,帮助开发者更...

    libjpeg-turbo for android

    libjpeg-turbo是一个高性能的JPEG图像处理库,它是libjpeg的优化版本,特别针对现代处理器的特性进行了优化,尤其是在使用SSE2指令集的x86和x86_64平台上,其速度可以比原版libjpeg快4倍。在Android平台上,libjpeg-...

    android ndk 方式使用libjpeg

    本篇文章将深入探讨如何在Android NDK环境中使用libjpeg库来解码JPEG图像。 libjpeg是一个广泛使用的开源库,它提供了JPEG图像编码和解码的功能。这个库是用C语言编写的,可以跨平台使用,包括Android系统。在...

    libjpeg.so.8

    对于CV开发者来说,了解libjpeg.so.8的运行机制和报错处理方法至关重要,因为这直接影响到图像处理的效率和程序的稳定性。同时,随着技术的发展,更高版本的libjpeg(如libjpeg-turbo)提供了更好的性能优化,如硬件...

    libjpeg库压缩Bitmap

    1. **获取Bitmap数据**:使用Bitmap的getPixels()方法或ByteBuffer,提取Bitmap的RGB或ARGB像素数据。注意,Android Bitmap默认的像素存储格式可能不是libjpeg所期望的格式,因此可能需要进行颜色空间转换。 2. **...

    linux libjpeg对图像进行压缩

    在Linux环境中,libjpeg是一个非常重要的库,它用于处理JPEG(Joint Photographic Experts Group)图像格式,这是一种广泛使用的有损压缩方法,尤其适用于照片。libjpeg库提供了对JPEG图像进行编码和解码的功能,...

    libjpeg-turbo.rar

    4. **使用方法** 在Windows环境下,开发人员可以通过设置项目配置,将libjpeg-turbo的库文件路径添加到链接器的输入目录,并将相应的.lib文件加入到依赖库中。对于动态库,还需要确保运行时环境包含对应的.dll文件...

    libjpeg_8d

    libjpeg 是一个开源的、广泛使用的库,专门用于处理遵循JPEG(Joint Photographic Experts Group)标准的图像文件。 **描述详解:** 这个描述指出,libjpeg_8d 是由独立的JPEG工作组维护的,这意味着这是一个由专业...

    libjpeg静态库

    在本篇文章中,我们将深入探讨libjpeg库的特性、使用方法以及在Windows环境下与C++的结合。 ### 1. libjpeg库的基本概念 JPEG是一种广泛使用的有损图像压缩格式,主要用于照片和连续色调的图像。libjpeg库由...

    修改libjpeg源码实现解码/压缩内存中的图像(保留原有接口)无需另写接口直接调用即可

    在IT领域,图像处理是不可或缺的一部分,而libjpeg是一个广泛使用的开源库,专门用于JPEG(Joint Photographic Experts Group)图像编码和解码。这个库提供了高效且灵活的接口,允许开发者在C语言环境下处理JPEG格式...

    libjpeg-turbo编码、解码实例代码

    通过分析和理解这些代码,你可以学习到libjpeg-turbo库的使用方法,以及JPEG、DIB和BMP格式之间转换的基本原理。这对于进行图像处理、图形编程或开发相关软件都是非常有价值的。在实际应用中,可以根据需求进一步...

    libjpeg-turbo-2.1.0-gcc64 JPEG图片处理库 Windows x86 64位

    libjpeg-turbo是一个JPEG图像编解码器,它使用SIMD指令(MMX、SSE2、AVX2、Neon、AltiVec)来加速x86、x86-64、Arm和PowerPC系统上的基线JPEG压缩和解压缩,以及x86、x86-64和Arm系统上的渐进式JPEG压缩。在这样的系统...

    LibJpeg解码内存中的数据.pdf

    在探讨如何使用LibJPEG库解码内存中的JPEG数据之前,我们先简要回顾一下LibJPEG是什么以及它的主要功能。LibJPEG是一个广泛使用的开源库,用于处理JPEG图像格式。无论是解码(将JPEG文件转换成像素数据)还是编码...

Global site tag (gtag.js) - Google Analytics