`

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.lib在c++Builder中的使用

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

    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压缩。在这样的系统...

    android ndk使用libjpeg

    将视频数据直接保存成jpeg图片, 也就是*.jpg图片上, 生成4K图片大约耗时200ms,效率比较高

    golibjpegturbo:Go 的 libjpeg-turbo cgo 绑定

    这个库是在 Go 中解码和编码 JPEG 图像的最快方法。 我们通过 cgo 绑定到库来实现这一点。 确切的速度取决于图像和 CPU。 在 Mac Book Pro 上,与image/jpeg标准库相比,golibjpegturbo 是: 解码速度提高 6 倍 ...

    node-jpeg-turbo-scaler:适用于Node.js的快速JPEG解码器和缩放器模块

    安装顺序: 安装libjpeg-turbo brew install jpeg-turbo 使用npm安装模块npm install jpeg-turbo-scaler用法函数解压缩( path , targetWidth , targetHeight , callback ) 从本地文件系统读取path引用的JPEG...

    antivcode:由标准 cpp 使用 boost 和 libjpeg 库实现的特定识别代码识别器

    CMake 构建系统使得编译和运行非常容易,最简单的方法是使用 cmake 的默认选项: cmake ./ make ./antivcode -h 用法 首先你应该让程序学习并生成属性代码数据库。 获取帮助信息: &gt;&gt; antivcode -h Or &gt;&gt; ...

    Python库 | pylibjpeg_rle-1.0.0-pp37-pypy37_pp73-win32.whl

    资源分类:Python库 所属语言:Python 使用前提:需要解压 资源全名:pylibjpeg_rle-1.0.0-pp37-pypy37_pp73-win32.whl 资源来源:官方 安装方法:https://lanzao.blog.csdn.net/article/details/101784059

    jpegtran-bin-gfw:gfw的jpegtran-bin

    libjpeg-turbo是libjpeg的派生产品,它使用SIMD指令(MMX,SSE2,NEON)在x86,x86-64和ARM系统上加速基线JPEG压缩和解压缩。 在这样的系统上,libjpeg-turbo的速度通常是未修改版本的libjpeg的2-4倍,其他所有条件...

    exifyay:Python模块,用于读取和写入Exif数据,并由经过时间考验的C库提供支持

    证明 是的, ! 该模块提供了在Python中读取和写入Exif数据的例程,并由经过时间... libexif和libjpeg使用自动工具,我们使用因为Simon无法找出如何干净地构建在OS X和Linux上均可使用的静态库的方法。 建造 cmake . ma

    nx-hbmenu:Nintendo Switch自制菜单

    用法 有关SD布局和应用程序等信息,请参见 。有关hbmenu文档,请参阅 。 下载 最新版本可从页面获得。 建造 使用make nx为Nintendo Switch以及使用make pc的PC进行make pc 。 为两个系统运行make build。 需要使用...

    android-vnc-server:kitkat 的 android-vnc-server

    android-vnc-服务器 android-vnc-server for kitkat 这是一个 vnc 服务器,它将移动设备的帧缓冲区推送到 vnc 客户端。 该服务器接受鼠标拖动作为触摸事件和按键输入。...用法 在移动设备上运行./android-vnc-ser

    mozjpeg.net:在.NET和Xamarin的Mozillas mozjpeg周围调用包装器

    包装器可以与任何与libjpeg ABI 6.2版兼容的版本一起使用,例如libjpeg本身或 。 为了将项目与 (C#中libjpeg的托管实现)区分开来,我决定将此项目称为mozjpeg.net。 这也反映了以下事实:mozjpeg附带了适用于...

    sdump:Sixel 图像转储器

    用法 $ sdump [-h] [-f] [-r 角度] 图像 $ 猫图片| 转储 $ wget -q -O - url | 转储 选项 -h:显示帮助 -f:使图像适合显示大小(仅缩小) -r:旋转图像(90 或 180 或 270) 支持的图像格式 jpeg 由 libjpeg png ...

    ubuntu iNode安装教程(有软件,带所需的库)

    下面是安装方法: 将inodeclient客户端文件夹解压到你喜欢的位置,在inodeclient文件夹中右击--“在终端中打开”--“sudo ./install.sh” 直到看到服务启动 拷贝文件 libtiff.so.4.3.2 libtiff.so.4 libjpeg.so...

    jpeg压缩的matlab代码-dct-extraction:用于直接从JPEG压缩文件中提取DCT系数的C代码。旨在与Java结合

    AC库(libExportDCT),它访问libjpeg并以序列化(且非常简单)的形式获取感兴趣的数据,然后Java可以使用JNA对其进行读取。 它要求libjpeg在系统中已经可用。 我建议使用版本8d,而不是版本9。 一个访问...

    树莓派极简安装OpenCv的方法步骤

    因为最近在开发使用树莓派+usb摄像头识别模块,打算用OpenCv,发现网上的树莓派OpenCv安装教程都过于繁琐占用内存大,我经过自己的实验,发现出了一种非常简易快捷的方式,网速OK的话,十分钟能安装完成。...

    f5ar:使用F5隐写算法压缩数据

    F5存档器该存储库以库和命令行... 如果您的机器上没有东西,则可以使用make libjpeg和make pcre命令从本地的官方存储库中构建和pcre的静态版本。 请注意,您将需要wget , git和cmake 。 树中包含所有必需的标头。用法

    jpegtran-bin:jpegtran bin-wrapper,使其可以作为本地依赖项无缝使用

    jpegtran-bin 是的派生产品,它使用SIMD指令(MMX,SSE2,NEON)在x86,x86-64和ARM系统上加速基线JPEG压缩和解压缩。 在这样的系统上,libjpeg-turbo的速度通常是未修改版本的libjpeg的2-4倍,其他所有条件都相同。...

    iOS Minicap提供了一个套接字接口,用于从iOS设备中流式传输实时屏幕捕获数据。-Swift开发

    ios-minicap iOS Minicap提供了一个套接字接口,用于从iOS设备中流式传输实时屏幕捕获数据。 它具有AVFoundation和iOS屏幕镜像功能。 要求brew install libjpeg-t ios...用法minicap协议是一个简单的基于推送的双向协议

Global site tag (gtag.js) - Google Analytics