[ 工具 ] ___ Library : Jpeg

一、引言


欢迎阅读本文,本文将介绍 libjpeg 库的使用和图像压缩解压缩技术。随着数字图像的广泛应用,图像处理和压缩成为了重要的技术需求。libjpeg 库作为一个开源的图像压缩解压缩库,提供了丰富的功能和灵活的接口,被广泛应用于图像处理领域。

本文旨在向读者介绍 libjpeg 库的基本用法、原理和高级功能,并提供实际应用示例和性能优化建议。通过阅读本文,您将了解如何使用 libjpeg 库对图像进行压缩和解压缩,并掌握一些高级功能和技巧,以优化图像处理的性能和效率。

在阅读本文之前,建议您具备一些 C/C++ 编程的基础知识,并了解图像处理的基本概念。本文将从安装和配置 libjpeg 库开始,逐步介绍其基本用法和原理,然后深入探讨高级功能和性能优化技巧。最后,我们将提供一些实际应用场景和常见问题的解决方法,以帮助您更好地应用和理解 libjpeg 库。

希望本文能够为您提供有关 libjpeg 库的全面指导,并激发您对图像处理和压缩技术的兴趣。让我们一起开始探索 libjpeg 库的奇妙世界吧!

请注意,本文基于 libjpeg 库的最新版本,并且假设您具备基本的编程和图像处理知识。如有任何疑问或困惑,请随时参考本文提供的参考资料或向相关论坛和社区寻求帮助。

祝您阅读愉快!

二、概述


libjpeg 库是一个开源的图像压缩解压缩库,被广泛应用于图像处理和图像压缩领域。它提供了一系列功能强大的 API,使开发人员能够轻松地对图像进行压缩和解压缩操作。

(一)功能


  1. 图像压缩:libjpeg 库提供了多种图像压缩算法和选项,可以将图像数据压缩为 JPEG 格式,实现高效的图像存储和传输。
  2. 图像解压缩:libjpeg 库支持将 JPEG 格式的图像数据解压缩为原始的像素数据,以便进行后续的图像处理和显示。
  3. 图像质量控制:libjpeg库允许开发人员通过调整压缩参数来控制图像的压缩质量。可以指定压缩质量的级别,从而在图像质量和压缩比之间进行权衡。较高的压缩质量级别会产生较大的文件大小,而较低的压缩质量级别则会导致图像细节的损失。
  4. 颜色空间转换:libjpeg 库支持将图像数据从一种颜色空间转换为另一种颜色空间。它可以处理常见的颜色空间,如 RGB、CMYK、YCbCr 等,并提供了相应的函数和选项来执行颜色空间转换操作。这对于图像处理和显示系统中的颜色空间转换非常有用。
  5. 图像采样和重采样:libjpeg 库提供了图像采样和重采样的功能,用于调整图像的分辨率和采样率。通过改变图像的采样率,可以降低图像的分辨率和文件大小,或者提高图像的质量和细节。libjpeg 库支持多种采样和重采样算法,可以根据需求选择合适的算法。
  6. 渐进式压缩:libjpeg 库支持渐进式压缩,这意味着图像可以逐渐加载和显示。在渐进式压缩中,图像的粗略版本首先显示,然后逐渐细化,直到达到完整的图像。这对于网络传输和图像浏览器等应用场景非常有用,可以提供更好的用户体验和逐步加载的效果。
  7. 自定义压缩和解压缩过程:libjpeg 库允许开发人员通过自定义函数来控制压缩和解压缩过程中的各个阶段。可以注册自定义的回调函数,在压缩和解压缩过程中执行特定的操作,如数据预处理、特殊算法处理等。这为开发人员提供了更大的灵活性和定制化能力。
  8. 多线程支持:libjpeg 库在某些版本中提供了多线程支持,可以在多个线程中并行地进行图像压缩和解压缩操作。这可以提高处理大量图像数据时的效率和性能。

(二)特点


  1. 跨平台性:libjpeg库可以在多个操作系统和平台上运行,包括 Windows、Linux、macOS 等。这使得开发人员可以在不同的环境中使用相同的库来处理图像数据。

  2. 灵活性:libjpeg 库提供了丰富的配置选项和参数,允许开发人员根据具体需求进行定制和优化。开发人员可以根据图像处理任务的要求,调整压缩质量、颜色空间转换算法、采样和重采样方法等参数,以达到最佳的图像处理效果。

  3. 高效性:libjpeg 库采用了优化的压缩算法和数据结构,具有较高的压缩比和解压缩速度。它能够在保持较高图像质量的同时,有效地减小图像的文件大小,节省存储空间和传输带宽。

  4. 易于使用:libjpeg 库的 API 设计简洁明了,文档详尽,使得开发人员能够快速上手并集成到自己的项目中。它提供了一组简单而功能强大的函数,使图像压缩和解压缩变得简单而直观。

(三)应用


  1. 数字图像处理:libjpeg 库广泛应用于图像处理软件、图像编辑器、图像浏览器等领域。它可以对图像进行高效的压缩和解压缩操作,以及其他高级图像处理任务,如颜色空间转换、图像采样和重采样等。
  2. 图像传输和存储:由于 JPEG 格式的高压缩比和广泛支持,libjpeg 库常被用于图像的传输和存储。它可以减小图像在网络传输中的带宽占用,或在磁盘上节省存储空间。因此,它在图像传输、图像分享、在线图库等应用中得到广泛应用。
  3. 嵌入式系统:libjpeg 库的高效性和跨平台性使其成为嵌入式系统中处理图像数据的理想选择。它被广泛应用于数字相机、智能手机、嵌入式图像处理器等设备中,用于图像的压缩、解压缩和显示。
  4. 图像压缩研究:libjpeg 库作为一个开源的图像压缩解压缩库,经常被用于图像压缩算法的研究和开发。研究人员可以利用 libjpeg 库的功能和源代码,对图像压缩算法进行实验和改进。

总之,libjpeg 库具有跨平台性、灵活性、高效性和易用性等特点,被广泛应用于数字图像处理、图像传输和存储、嵌入式系统等领域。通过利用 libjpeg 库的功能和 API,开发人员可以实现高效的图像压缩和解压缩,以及其他图像处理任务。无论是在个人项目还是商业应用中,libjpeg 库都是一个强大而实用的工具。

三、安装配置


libjpeg 库的安装配置通常包括以下步骤:

  1. 获取 libjpeg 源代码官网或其他可靠的源获取 libjpeg 的源代码;

  2. 解压源代码包:将下载的源代码包解压到本地计算机上;

    linux@localhost:~$ tar zxvf jpegsrc.v9e.tar.gz
    
  3. 进入源码目录:使用终端或命令行进入解压后的源码目录;

    linux@localhost:~$ cd jpeg-9e
    
  4. 配置编译选项:使用命令行输入配置选项;

    linux@localhost:~/jpeg-9e$ ./configure --host=arm-none-linux-gnueabi --prefix=${HOME}/libjpeg
    
  5. 编译源代码:使用命令行进行编译,生成可执行文件;

    linux@localhost:~/jpeg-9e$ make
    
  6. 安装库文件:将生成的库文件和头文件打包上传到目标平台的库文件和头文件目录中;

    linux@localhost:~/libjpeg$ tar zcvf libjpeg.tar.gz bin lib
    root@arm:~$ tftp -g -r libjpeg.tar.gz 
    root@arm:~$ tar zxvf libjpeg.tar.gz -C /usr/local/
    
  7. 配置环境变量:将库文件路径添加到系统环境变量中,以便其他程序可以找到并使用该库;

    root@arm:~$ cat >> /etc/profile << EOF
    > PATH=$PATH:/usr/local/bin
    > LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/lib
    > EOF
    

需要注意的是,不同操作系统和编译环境可能有所不同,具体的安装配置步骤可能会有所差异。

四、基础知识


(一)数据结构


libjpeg 库是一个用于处理 JPEG 图像的开源库,它提供了一系列的数据结构来表示压缩图像数据。以下是 libjpeg 中用于表示图像数据主要的数据结构。这些数据结构提供了灵活的接口,使开发者能够自由地处理 JPEG 图像的压缩和解压缩过程。

  1. 用于表示 JPEG 压缩的主要参数和状态

以下是 jpeg_compress_struct 中的一些关键字段及其含义。通过设置这些字段,可以灵活地控制JPEG压缩过程中的各种参数和选项。

typedef struct jpeg_compress_struct {
    /* 输入图像的颜色分量数。对于RGB图像,通常为3(红、绿、蓝),对于灰度图像,通常为1 */
    int input_components;
    /* 输入图像的颜色空间。常见的取值有 JCS_RGB(RGB颜色空间)和 JCS_GRAYSCALE(灰度颜色空间)*/
    J_COLOR_SPACE in_color_space;
    // 输入图像的宽度
    JDIMENSION image_width;
    // 输入图像的高度
    JDIMENSION image_height;
    /* 输入图像的伽马值。如果不知道输入图像的伽马值,可以将其设置为0.0,libjpeg 会自动进行伽马校正 */
    double input_gamma;
    /* 输入图像数据的精度。通常为8位(每个颜色分量占8个比特),但也可以是12位等其他值 */
    int data_precision;
    /* 压缩后的JPEG图像的颜色空间。常见的取值有 JCS_YCbCr(YCbCr颜色空间)和 JCS_GRAYSCALE(灰度颜色空间) */
    J_COLOR_SPACE jpeg_color_space;
    /* 压缩后的JPEG图像的颜色分量数。对于YCbCr颜色空间,通常为3(亮度、蓝色差、红色差),对于灰度图像,通常为1 */
    int num_components;
    /* JPEG压缩的质量因子。取值范围为0-100,值越大表示质量越好但文件大小越大 */
    int jpeg_quality;
    /* 使用的离散余弦变换(DCT)的方法。常见的取值有JDCT_ISLOW(慢速DCT)和JDCT_IFAST(快速DCT)*/
    J_DCT_METHOD dct_method;
    /* 是否进行优化编码。如果设置为TRUE,libjpeg会尝试优化编码以减小文件大小 */
    boolean optimize_coding;
    /* 平滑因子。取值范围为0-100,值越大表示平滑程度越高 */
    int smoothing_factor;
    /* 是否写入JFIF头部。如果设置为TRUE,libjpeg会在压缩图像中包含这些信息 */
    boolean write_JFIF_header;
    /* 是否写入Adobe标记。如果设置为TRUE,libjpeg会在压缩图像中包含这些信息 */
    boolean write_Adobe_marker;
    /* ... 其他成员变量 */
} jpeg_compress_struct;
  1. 用于表示 JPEG 解压缩的主要参数和状态

以下是 jpeg_decompress_struct 中的一些关键字段及其含义。用于存储 JPEG 图像文件的解压缩参数和相关数据。它提供方式来处理 JPEG 图像文件,使得用户可以读取和解压缩 JPEG 图像数据,并将其转换为可用的像素数据,以供后续处理和显示。

typedef struct jpeg_decompress_struct {
	/* 用于处理JPEG解压缩过程中的错误。该结构体包含了错误处理函数的指针,以及一个错误消息缓冲区,用于存储错误消息 */
	struct jpeg_error_mgr *err;
	
	/* 表示 JPEG 解压缩会话的全局状态。它可以有多个不同的取值,如JPEG_HEADER_OK、JPEG_HEADER_TABLES_ONLY、JPEG_HEADER_SUSPENDED等,用于表示解压缩过程中的不同状态 */
	int global_state;
	
	/* 用于指定输出图像的尺寸 */
	
	/* 解压缩后的 JPEG 图像的宽度 */
	JDIMENSION output_width;
	
	/* 解压缩后的 JPEG 图像的高度 */
	JDIMENSION output_height;
	
	/* 输出图像的颜色空间。它可以有不同的取值,如JCS_GRAYSCALE、JCS_RGB、JCS_YCbCr等,用于表示不同的颜色空间 */
	J_COLOR_SPACE out_color_space;
	
	/* 输出图像的颜色分量数量。它用于指定输出图像每个像素的颜色分量数量,如灰度图像为1,RGB图像为3 */
	int output_components;
	
	/* 表示解压缩时的缩放比例。以下这两个字段用于指定解压缩时图像的缩放比例,可以将图像放大或缩小 */ 
	
	/* 解压缩时的缩放比例的分子 */
	unsigned int scale_num;
	
	/* 解压缩时的缩放比例的分母 */
	unsigned int scale_denom;
	
	/* 使用的离散余弦变换(DCT)算法。它可以有不同的取值,如JDCT_ISLOW、JDCT_IFAST等,用于指定不同的DCT算法 */
	J_DCT_METHOD dct_method;
	
	/* 是否对颜色进行量化。该字段用于指定是否对颜色进行量化处理,以减少颜色的数量 */
	boolean quantize_colors;
	
	/* 是否输出解压缩后的原始数据。如果该字段为真,则解压缩后的数据将以原始格式输出,否则将进行颜色空间转换和格式转换,输出可用的像素数据  */
	boolean raw_data_out;
	
	// 其他字段...

} jpeg_decompress_struct;

通过设置这些字段的值,可以对 JPEG 图像进行解压缩,并获取解压缩后的图像数据。

  1. 用于处理 JPEG 压缩和解压缩过程中的错误

以下是一些关键字段及其含义。通过这些字段,可以在 JPEG 压缩和解压缩过程中有效地处理错误和输出错误消息。

typedef struct jpeg_error_mgr {
    /* 在发生错误时终止压缩或解压缩过程并输出错误消息的函数指针。于在发生错误时终止压缩或解压缩过程并输出错误消息 */
    void (*error_exit) (j_common_ptr cinfo);
    /* 输出一般性的错误消息的函数指针 */
    void (*emit_message) (j_common_ptr cinfo, int msg_level);
    /* 输出详细的错误消息的函数指针 */
    void (*output_message) (j_common_ptr cinfo);
    /* 格式化错误消息的函数指针 */
    void (*format_message) (j_common_ptr cinfo, char *buffer);
    /* 重置错误管理器的状态的函数指针 */
    void (*reset_error_mgr) (j_common_ptr cinfo);
    
    /* 最近一次错误的消息代码 */
    int msg_code;
    /* 最近一次错误的消息参数 */
    union {
        int i[8];
        char c[80];
    } msg_parm;
    
    /* 错误跟踪的级别 */
    int trace_level;
    /* 记录发生的警告数量 */
    long num_warnings;
    
    /* JPEG库内部的错误消息表 */
    const char *jpeg_message_table;
    /* 最后一个错误消息的索引 */
    int last_jpeg_message;
    
    /* ... 其他成员变量 */
} jpeg_error_mgr;

开发者可以根据需要,通过设置适当的函数指针和跟踪级别来自定义错误处理和错误消息的输出方式。

  1. 用于指定压缩前的原始图像数据的来源位置

通过设置这些字段的值和相应的函数指针,可以在解压缩过程中从指定位置读取原始图像数据,并填充到输入缓冲区中供解压缩使用。

typedef struct jpeg_source_mgr {
	/* 初始化源管理器。在解压缩过程开始前调用 */
	void (*init_source) (j_decompress_ptr cinfo);
	
	/* 指向一个函数的指针,用于填充输入缓冲区。当输入缓冲区中的数据被消耗完时,调用此函数以填充新的数据 */
	boolean (*fill_input_buffer) (j_decompress_ptr cinfo);
	
	/* 指向一个函数的指针,用于跳过指定数量的输入字节。在解压缩过程中可能需要跳过一些无效的数据 */
	void (*skip_input_data) (j_decompress_ptr cinfo, long num_bytes);
	
	/* 指向一个函数的指针,用于检查是否需要重新填充输入缓冲区。当解压缩过程中发生错误时,可能需要重新同步到起始点 */
	boolean (*resync_to_restart) (j_decompress_ptr cinfo, int desired);
	
	/* 指向一个函数的指针,用于终止源管理器。在解压缩过程结束后调用 */
	void (*term_source) (j_decompress_ptr cinfo);
	
	/* 指向输入缓冲区中下一个要读取的字节的指针 */
	const JOCTET *next_input_byte;
	
	/* 输入缓冲区中剩余的字节数 */
	size_t bytes_in_buffer;
	
	// 其他字段...
  
} jpeg_source_mgr;
  1. 用于指定压缩后的数据输出的目标位置

以下是一些关键字段及含义,用于管理输出数据的写入和完成操作。通过这些字段,可以指定压缩后的数据输出的目标位置,并管理输出数据的写入和完成操作。

typedef struct jpeg_destination_mgr {
	/* 初始化输出目标位置的函数指针,用于初始化输出目标位置,在开始写入数据之前调用 */
	void (*init_destination) (j_compress_ptr cinfo);
	/* 写入输出缓冲区中的数据的函数指针,用于写入输出缓冲区中的数据,当输出缓冲区已满时调用  */
	boolean (*empty_output_buffer) (j_compress_ptr cinfo);
	/* 完成输出操作的函数指针,用于完成输出操作。在所有数据写入完成后调用 */
	void (*term_destination) (j_compress_ptr cinfo);
	
	/* 指向输出缓冲区的下一个字节的指针 */
	JOCTET *next_output_byte;
	/* 输出缓冲区中剩余的可用字节数 */
	size_t free_in_buffer;
	
	/* ... 其他成员变量 */
} jpeg_destination_mgr;

开发者可以根据需要,通过设置适当的函数指针和操作字段来自定义数据的输出方式和位置。

  1. 用于表示JPEG图像中的标记

用于表示JPEG图像中的标记的数据结构体是 JFIF(JPEG File Interchange Format)标记数据结构体。

JFIF 标记数据结构体的声明形式如下:

typedef struct {
    uint8_t marker;     // 标记类型
    uint16_t length;    // 标记数据长度
    uint8_t *data;      // 标记数据
} JFIFMarker;

JFIF 标记数据结构体用于存储 JPEG 图像中的标记信息。JPEG 图像文件中的每个标记都以标记类型和标记数据长度的形式存在,JFIF 标记数据结构体的关键字段如下:

  • marker:表示标记类型的字段,用于标识不同类型的标记,如APP0、APP1等。
  • length:表示标记数据长度的字段,用于记录标记数据的长度。
  • data:指向标记数据的指针,用于存储标记的具体数据内容。

JFIF 标记数据结构体的作用是方便对 JPEG 图像中的标记进行解析和处理。通过使用该数据结构体,可以提取出 JPEG 图像中的各个标记,进而对图像进行相关操作,如读取、修改或删除特定的标记。

  1. 用于表示共同的参数和状态

用于表示共同的参数和状态数据结构体是 jpeg_common_struct,是 jpeg_compress_struct 和 jpeg_decompress_struct 的父结构。

jpeg_common_struct 的声明形式如下:

typedef struct jpeg_common_struct {
    struct jpeg_error_mgr *err;         // 错误处理结构体
    struct jpeg_memory_mgr *mem;        // 内存管理结构体
    struct jpeg_progress_mgr *progress; // 进度监控结构体
    struct jpeg_common_fields *fields;  // 公共字段
} jpeg_common_struct;

它包含了以下关键字段的含义:

  • err:指向错误处理结构体的指针,用于处理JPEG压缩和解压过程中的错误。
  • mem:指向内存管理结构体的指针,用于管理JPEG压缩和解压过程中的内存分配和释放。
  • progress:指向进度监控结构体的指针,用于监控JPEG压缩和解压过程中的进度。
  • fields:指向公共字段结构体的指针,用于存储和访问JPEG压缩和解压过程中的公共参数和状态数据。

jpeg_common_struct 的作用是提供了一个共享的数据结构,用于存储 JPEG 压缩和解压过程中的公共参数和状态数据。这样可以避免在 jpeg_compress_struct 和 jpeg_decompress_struct 中重复定义相同的字段,提高了代码的复用性和可维护性。

(二)关键函数


1. 创建对象


函数原型:

void jpeg_create_compress(j_compress_ptr cinfo);
void jpeg_create_decompress(j_decompress_ptr cinfo);
void jpeg_std_error(jpeg_error_mgr *err);

详细说明:

函数名称函数作用
jpeg_create_compress创建一个压缩对象,该对象将在压缩过程中保存参数和状态信息。通过该函数创建的压缩对象将用于后续的压缩操作
jpeg_create_decompress创建一个解压缩对象,该对象将在解压缩过程中保存参数和状态信息。通过该函数创建的解压缩对象将用于后续的解压缩操作
jpeg_std_error设置 JPEG 库中的错误处理器,该处理器用于处理在 JPEG 图像压缩和解压缩过程中出现的错误。通过该函数设置错误处理器后,当 JPEG 库发生错误时,将调用错误处理器中定义的错误处理函数进行处理

参数列表:

参数说明
j_compress_ptr cinfo指向 jpeg_compress_struct 结构体的指针,用于保存压缩过程中的参数和状态信息,通过该指针,可以对压缩对象进行操作和设置相应的参数
j_decompress_ptr cinfo指向 jpeg_decompress_struct 结构体的指针,用于保存解压缩过程中的参数和状态信息,通过该指针,可以对解压缩对象进行操作和设置相应的参数
jpeg_error_mgr *err指向 jpeg_error_mgr 结构体的指针,用于保存错误处理器的信息,通过该指针,可以对错误处理器进行操作和设置相应的参数

函数说明:

jpeg_compress_struct结构体包含了许多成员变量,用于保存与压缩相关的参数和状态信息。

一些重要的成员变量包括:

  • image_width:图像的宽度。
  • image_height:图像的高度。
  • input_components:输入图像的颜色分量数。
  • in_color_space:输入图像的颜色空间。
  • err:错误处理器。
  • dest:输出数据的目标位置。

jpeg_decompress_struct结构体包含了许多成员变量,用于保存与解压缩相关的参数和状态信息。

一些重要的成员变量包括:

  • image_width:图像的宽度。
  • image_height:图像的高度。
  • output_components:输出图像的颜色分量数。
  • out_color_space:输出图像的颜色空间。
  • err:错误处理器。
  • src:输入数据的源位置。

jpeg_error_mgr结构体包含了许多成员变量和函数指针,用于保存和处理错误相关的信息。

一些重要的成员变量和函数指针包括:

  • error_exit:错误处理函数,用于处理致命错误并退出。
  • emit_message:消息输出函数,用于输出错误和警告消息。
  • output_message:消息输出函数,用于输出一般消息。
  • trace_level:跟踪级别,用于控制错误消息的详细程度。

在调用jpeg_create_compress函数之后,必须对压缩对象进行进一步的设置,如设置压缩参数、关联输出流等。只有在完成这些设置后,才能开始实际的压缩过程。

示例代码:

jpeg_compress_struct cinfo;
jpeg_create_compress(&cinfo);
// 对压缩对象进行进一步的设置
// ...

jpeg_decompress_struct cinfo;
jpeg_create_decompress(&cinfo);
// 对解压缩对象进行进一步的设置
// ...

jpeg_error_mgr err;
jpeg_std_error(&err);
// 对错误处理器进行进一步的设置
// ...

通过调用jpeg_create_compress函数,可以创建一个用于JPEG图像压缩的压缩对象,并对其进行配置和设置,以便后续进行压缩操作。

通过调用jpeg_create_decompress函数,可以创建一个用于JPEG图像解压缩的解压缩对象,并对其进行配置和设置,以便后续进行解压缩操作。

在调用jpeg_create_decompress函数之后,必须对解压缩对象进行进一步的设置,如设置解压缩参数、关联输入流等。只有在完成这些设置后,才能开始实际的解压缩过程。

在调用jpeg_std_error函数之后,可以对错误处理器进行进一步的设置,如自定义错误处理函数、设置跟踪级别等。通过自定义错误处理函数,可以根据实际需求对JPEG库中的错误进行处理和记录。

通过调用jpeg_std_error函数,可以设置JPEG库中的错误处理器,并对其进行配置和设置,以便在JPEG图像压缩和解压缩过程中进行错误处理。

2. 关联对象


  • jpeg_stdio_dest:这个函数通常用于将 JPEG 压缩数据写入到标准 I/O 流(例如文件)中。
void jpeg_stdio_dest(j_compress_ptr cinfo, FILE * outfile);
  • jpeg_stdio_src:这个函数通常用于从标准 I/O 流(例如文件)中读取 JPEG 压缩数据。
void jpeg_stdio_src(j_decompress_ptr cinfo, FILE * infile);
  • jpeg_mem_dest:这个函数通常用于将 JPEG 压缩数据写入到内存缓冲区中。
void jpeg_mem_dest(j_compress_ptr cinfo, unsigned char ** outbuffer, unsigned long * outsize);
  • jpeg_mem_src:这个函数通常用于从内存缓冲区中读取 JPEG 压缩数据。
void jpeg_mem_src(j_decompress_ptr cinfo, unsigned char * inbuffer, unsigned long insize);

这些函数原型是 libjpeg 库中的标准函数,用于在 JPEG 图像处理过程中设置压缩和解压缩的目标和源。提供了将 JPEG 数据写入文件或内存,以及从文件或内存中读取 JPEG 数据的功能

  • 参数说明
参数描述
FILE * outfile指向要写入的目标文件的指针
FILE * infile指向要读取的源文件的指针
unsigned char ** outbuffer指向指针的指针,用于存储压缩后的数据
unsigned char * inbuffer指向包含压缩数据的内存缓冲区的指针
unsigned long * outsize指向存储压缩数据大小的变量的指针
unsigned long insize压缩数据的大小

3. 设置参数


  • 设置 libjpeg 库中 JPEG 压缩的默认参数
void jpeg_set_defaults(j_compress_ptr cinfo);
  • 设置 libjpeg 库中 JPEG 压缩的压缩质量
void jpeg_set_quality(j_compress_ptr cinfo, int quality, boolean force_baseline);
  • 参数说明
参数描述
int quality表示压缩质量的整数值,通常在 0 到 100 之间
boolean force_baseline一个布尔值,用于指示是否强制生成 baseline JPEG 格式

这些函数提供了设置 libjpeg 库中 JPEG 压缩的默认参数和质量的方法,允许用户根据需要进行定制化设置。

4. 开始过程


  • jpeg_start_compress 函数通常用于 libjpeg 库中,在压缩 JPEG 图像数据之前执行一些初始化操作。以下是该函数的典型原型和参数说明:
boolean jpeg_start_compress(j_compress_ptr cinfo, boolean write_all_tables);

这个函数返回一个布尔值,表示压缩是否成功开始。在调用该函数后,libjpeg 将准备开始压缩 JPEG 图像数据。

  • jpeg_start_decompress 函数的作用是在解压缩JPEG图像数据之前执行一些初始化操作。具体来说,它会进行以下几项工作:
    • 分配并初始化解压缩所需的数据结构和内存空间。
    • 设置解压缩过程中需要的一些参数和状态信息。
    • 执行预处理步骤,为接下来的解压缩做准备。
boolean jpeg_start_decompress(j_decompress_ptr cinfo);

这个函数返回一个布尔值,表示解压缩是否成功开始。在调用该函数后,libjpeg 将准备开始解压缩 JPEG 图像数据。在调用 jpeg_start_decompress 函数之后,libjpeg库将准备开始解压缩 JPEG 图像数据。这个函数是解压缩过程中的一个重要步骤,它为后续的解压缩操作奠定了基础,确保解压缩过程能够顺利进行。

  • 参数说明
参数描述
boolean write_all_tables一个布尔值,指示是否写入所有的 JPEG 表格数据。如果为 TRUE,表示要写入所有表格数据;如果为 FALSE,表示只写入必需的表格数据

5. 数据处理


  • jpeg_write_scanlines 函数用于将一系列扫描行的图像数据写入 JPEG 压缩器,这是 JPEG 图像压缩过程中的关键步骤之一。通过多次调用这个函数,可以逐行地将图像数据写入压缩器,从而完成整个图像的压缩过程。
JDIMENSION jpeg_write_scanlines(j_compress_ptr cinfo, JSAMPARRAY scanlines, JDIMENSION num_lines);
  • jpeg_read_scanlines 函数用于从 JPEG 解压缩器中读取一系列扫描行的图像数据,这是 JPEG 图像解压缩过程中的关键步骤之一。通过多次调用这个函数,可以逐行地从解压缩器中读取图像数据,从而完成整个图像的解压缩过程。
JDIMENSION jpeg_read_scanlines(j_decompress_ptr cinfo, JSAMPARRAY scanlines, JDIMENSION max_lines);

以上这两个函数在 JPEG 图像处理中起着非常重要的作用,分别用于压缩和解压缩过程中的数据处理。

  • 参数说明
参数描述
JSAMPARRAY scanlines指向包含要写入的扫描行数据的数组的指针
JSAMPARRAY scanlines指向存储读取的扫描行数据的数组的指针
JDIMENSION num_lines要写入的扫描行数量
JDIMENSION max_lines要读取的最大扫描行数量

6. 结束过程


void jpeg_finish_compress(j_compress_ptr cinfo);

函数作用jpeg_finish_compress 函数用于完成 JPEG 图像的压缩过程。在调用此函数之后,压缩对象将被清理,并且可以释放相关资源。

boolean jpeg_finish_decompress(j_decompress_ptr cinfo);

函数作用jpeg_finish_decompress 函数用于完成 JPEG 图像的解压缩过程。在调用此函数之后,解压缩对象将被清理,并且可以释放相关资源。

这两个函数都用于完成 JPEG 图像处理过程中的压缩或解压缩阶段。在调用它们之后,相关的压缩或解压缩对象将会被清理,资源也将被释放。

7. 销毁对象

  • 销毁压缩对象
void jpeg_destroy_compress(j_compress_ptr cinfo);

j_compress_ptr cinfo:指向压缩对象结构的指针,其中包含了压缩过程中所需的各种参数和状态信息。

函数作用:jpeg_destroy_compress 函数用于销毁 JPEG 压缩对象,并释放与之相关的资源。在完成了 JPEG 图像的压缩过程之后,应当调用这个函数来清理压缩对象。

  • 销毁解压缩对象
void jpeg_destroy_decompress(j_decompress_ptr cinfo);

j_decompress_ptr cinfo:指向解压缩对象结构的指针,其中包含了解压缩过程中所需的各种参数和状态信息。

函数作用:jpeg_destroy_decompress 函数用于销毁 JPEG 解压缩对象,并释放与之相关的资源。在完成了 JPEG 图像的解压缩过程之后,应当调用这个函数来清理解压缩对象。

这两个函数在完成了 JPEG 图像的压缩或解压缩过程后起到了清理资源的作用。调用它们可以释放相关的内存和资源,以防止内存泄漏和资源浪费。

五、实践应用


(一)解压文件数据


以下这段代码演示了如何使用 libjpeg 库来读取 JPEG 图像文件并解压缩图像数据。通过调用 read_data_from_jpeg_file 函数,你可以获取 JPEG 图像的原始像素数据,并可以根据需要进一步处理和使用这些数据。

unsigned char *read_data_from_jpeg_file(const char *filename, int *width, int *height) 
{
    struct jpeg_decompress_struct cinfo;
    
    /* 我们使用我们的私有扩展 JPEG 错误处理程序 */
    //struct jpeg_error_mgr jerr;
	struct my_error_mgr jerr;
    
    FILE *infile;
    JSAMPARRAY buffer;
    
    int row_stride;
    unsigned char *data;

	/* 打开文件 */

    if ((infile = fopen(filename, "rb")) == NULL) {
        fprintf(stderr, "can't open %s\n", filename);
        return NULL;
    }
	
	/* 分配并初始化解压缩对象和错误处理对象 */
	
	// 必须设置错误处理程序,以防初始化步骤失败
	
	//cinfo.err = jpeg_std_error(&jerr);
	cinfo.err = jpeg_std_error(&jerr.pub); 
    jerr.pub.error_exit = my_error_exit; 
    
    jpeg_create_decompress(&cinfo);

	/* 指定解压数据源:将JPEG文件作为输入源,并将文件指针传递给JPEG解压缩对象 */

    jpeg_stdio_src(&cinfo, infile);

	/* 读取文件头的信息:读取JPEG文件头,并将文件头信息存储在JPEG解压缩对象中 */
    
    (void) jpeg_read_header(&cinfo, TRUE);
    
    /* 开始解压:可以设置解压参数,包括图像宽度、高度、颜色空间等,当前为默认解压参数 */
    
    (void) jpeg_start_decompress(&cinfo);
    
    *width = cinfo.output_width;
    *height = cinfo.output_height;

    data = (unsigned char *)calloc(1, (*width) * (*height) * cinfo.num_components);
    
    buffer = (*cinfo.mem->alloc_sarray)((j_common_ptr) &cinfo, JPOOL_IMAGE, *width * cinfo.num_components, 1);
    
    row_stride = *width * cinfo.num_components;

	/* 循环取出数据:将图像数据存储在内存中。 */
    while (cinfo.output_scanline < cinfo.output_height) {
        (void) jpeg_read_scanlines(&cinfo, buffer, 1);
        memcpy(data + (cinfo.output_scanline - 1) * row_stride, buffer[0], row_stride);
    }

	/* 解压完毕 */
    (void) jpeg_finish_decompress(&cinfo);
    
    /* 释放资源并关闭文件 */
	jpeg_destroy_decompress(&cinfo);
    fclose(infile);

    return data;
}

(二)压缩文件数据


以下这段代码演示了如何使用 libjpeg 库将图像数据压缩为 JPEG 格式,并将压缩后的数据写入文件。通过调用 write_data_to_jpeg_file 函数,你可以将原始像素数据压缩为 JPEG 格式,并保存为文件。可以根据需要调整压缩参数和质量设置来控制压缩效果。

int write_data_to_jpeg_file(const char *filename, unsigned char *raw_data, int width, int height)
{
    // jpeg压缩对象
    struct jpeg_compress_struct cinfo;
    
    //struct jpeg_error_mgr jerr;
	/* 我们使用我们的私有扩展 JPEG 错误处理程序 */
	struct my_error_mgr jerr;

    JSAMPROW row_pointer[1];
    int row_stride;

	/* 分配并初始化压缩对象和错误处理对象 */

    //cinfo.err = jpeg_std_error(&jerr);
	cinfo.err = jpeg_std_error(&jerr.pub); 
	jerr.pub.error_exit = my_error_exit; 
	
    jpeg_create_compress(&cinfo);

    // 设置压缩参数
    cinfo.image_width = width;
    cinfo.image_height = height;
    cinfo.input_components = 3;
    cinfo.in_color_space = JCS_RGB;
	/* 设置压缩属性 */
    jpeg_set_defaults(&cinfo);
    jpeg_set_quality(&cinfo, 80, TRUE);

	// 分配内存用于存储压缩后的jpeg图片数据
    unsigned char *jpeg_data = NULL;
    unsigned long jpeg_size = 0;
    jpeg_mem_dest(&cinfo, &jpeg_data, &jpeg_size);

    row_stride = width * 3;
    
	 /* 开始压缩 */
	jpeg_start_compress(&cinfo, TRUE);
	/* 循环压缩并写入 */

    while (cinfo.next_scanline < cinfo.image_height) {
        row_pointer[0] = &raw_data[cinfo.next_scanline * row_stride];
        jpeg_write_scanlines(&cinfo, row_pointer, 1);
    }

	/* 压缩完毕 */
	jpeg_finish_compress(&cinfo);

    // 将压缩后的jpeg图片数据写入文件
    FILE *outfile = fopen(filename, "wb");
    fwrite(jpeg_data, jpeg_size, 1, outfile);
    fclose(outfile);

    // 释放内存
    free(jpeg_data);
    jpeg_destroy_compress(&cinfo);

    return 0;
}

(三)压缩内存数据


以下这段代码演示了如何使用 libjpeg 库将图像数据压缩为 JPEG 格式。通过调用 compress_image_to_jpeg 函数,你可以将原始像素数据压缩为 JPEG 格式,并获取压缩后的图像数据和数据大小。可以根据需要调整压缩质量来控制压缩效果。

int compress_image_to_jpeg(unsigned char *raw_image, int width, int height, int quality, unsigned char **compressed_image, unsigned long *compressed_size)
{
    struct jpeg_compress_struct cinfo;
    struct jpeg_error_mgr jerr;
    JSAMPROW row_pointer[1];
    int row_stride;
    unsigned char *outbuffer = NULL;
    unsigned long outsize = 0;

    // 为JPEG对象分配空间并初始化
    cinfo.err = jpeg_std_error(&jerr);
    jpeg_create_compress(&cinfo);

    // 设置JPEG参数
    cinfo.image_width = width;
    cinfo.image_height = height;
    cinfo.input_components = 3;
    cinfo.in_color_space = JCS_RGB;
    
    jpeg_set_defaults(&cinfo);
    jpeg_set_quality(&cinfo, quality, TRUE);

    // 分配内存
    jpeg_mem_dest(&cinfo, &outbuffer, &outsize);

    // 开始压缩
    jpeg_start_compress(&cinfo, TRUE);
    row_stride = width * 3;

    while (cinfo.next_scanline < cinfo.image_height) {
        row_pointer[0] = &raw_image[cinfo.next_scanline * row_stride];
        jpeg_write_scanlines(&cinfo, row_pointer, 1);
    }

    // 结束压缩
    jpeg_finish_compress(&cinfo);
    jpeg_destroy_compress(&cinfo);

    // 返回压缩后的图像数据
    *compressed_image = outbuffer;
    *compressed_size = outsize;

    return 0;
}

(四)解压内存数据


这段代码演示了如何使用 libjpeg 库将 JPEG 图像数据解压缩为原始图像数据。通过调用 decompress_jpeg_data 函数,你可以将 JPEG 图像数据解压缩,并获取解压缩后的原始图像数据、图像的宽度和高度。解压缩后的数据可以用于进一步处理或显示原始图像。

int decompress_jpeg_data(unsigned char *jpeg_data, int jpeg_data_size, unsigned char **raw_data, int *width, int *height) 
{
    struct jpeg_decompress_struct cinfo;
    struct jpeg_error_mgr jerr;
    JSAMPROW row_pointer[1];
    int row_stride;

    /* 设置错误处理程序 */
    cinfo.err = jpeg_std_error(&jerr);

    /* 初始化解压缩对象 */
    jpeg_create_decompress(&cinfo);

    /* 指定压缩数据的源 */
    jpeg_mem_src(&cinfo, jpeg_data, jpeg_data_size);

    /* 读取头信息 */
    jpeg_read_header(&cinfo, TRUE);

    /* 开始解压缩 */
    jpeg_start_decompress(&cinfo);

    /* 获取图像宽度和高度 */
    *width = cinfo.output_width;
    *height = cinfo.output_height;

    /* 为原始数据分配内存 */
    *raw_data = (unsigned char*)calloc(1, cinfo.output_width*cinfo.output_height*cinfo.num_components);

    /* 设置一行缓冲区 */
    row_stride = cinfo.output_width * cinfo.output_components;
    row_pointer[0] = (unsigned char *)malloc(row_stride);

    /* 逐行解压缩图像 */
    while (cinfo.output_scanline < cinfo.output_height) {
        jpeg_read_scanlines(&cinfo, row_pointer, 1);
        for (int i=0; i<row_stride; i++)
            (*raw_data)[cinfo.output_scanline * row_stride + i] = row_pointer[0][i];
    }

    /* 完成解压缩 */
    jpeg_finish_decompress(&cinfo);

    /* 释放解压缩对象 */
    jpeg_destroy_decompress(&cinfo);

    /* 释放一行缓冲区 */
    free(row_pointer[0]);

	return 0;
}

六、参考


JPEG规范

  • 2
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值