一、libjpeg 简介
libjpeg 是一个用于处理 JPEG(Joint Photographic Experts Group)图像文件的开源 C 库,主要功能包括 JPEG 图像的编码(压缩)与解码(解压缩)。它由 Independent JPEG Group (IJG) 开发,广泛用于嵌入式系统、图像编辑软件、浏览器等需要处理 JPEG 图像的场景。
IJG 是一个非正式组织,负责编写和分发广泛使用的免费 JPEG 图像压缩库。第一个版本于 1991 年 10 月 7 日发布。当前版本是 2024 年 1 月 14 日发布的 9f 版本。这为许多应用程序的 JPEG 支持奠定了稳定而坚实的基础。
二、JPEG 格式简介
JPEG 是一种有损压缩的图像格式,设计目的是在尽可能小的文件大小下保留尽可能高的视觉质量。JPEG 压缩的核心基于以下步骤:
- 颜色空间转换:从 RGB 转为 YCbCr 色彩空间,分离亮度(Y)与色度(Cb、Cr)信息。
- 采样率降采样:降低色度分量的分辨率,减少数据量。
- 离散余弦变换 (DCT):将图像块从空间域转换到频率域。
- 量化:通过对高频分量进行更强的压缩来减少不明显的细节。
- 熵编码:使用霍夫曼编码或算术编码进一步压缩数据。
三、libjpeg 的主要功能unsetunset
libjpeg 提供了一套功能丰富的接口,支持以下功能:
- JPEG 编码与解码:支持标准 JPEG 文件的读写。
- 多种图像格式支持:支持灰度、彩色、子采样等多种格式。
- 自定义压缩质量:允许用户调整压缩质量以控制文件大小与图像质量的平衡。
- 扩展性:支持插入自定义标记(metadata),并允许用户操作图像流。
四、libjpeg 的技术架构unsetunset
libjpeg 的核心架构分为以下几部分:
-
数据输入/输出处理器:
- 提供标准的输入流与输出流接口。
- 支持文件、内存缓冲区等多种数据来源。
-
压缩与解压模块:
- 压缩模块:将像素数据转换为 JPEG 数据流。
- 解压模块:解析 JPEG 数据流并恢复为像素数据。
-
色彩转换器:
- 提供从 RGB 到 YCbCr 的转换。
- 支持不同子采样率的配置。
-
DCT 和量化模块:
- 负责离散余弦变换和频域数据的量化。
- 使用标准或自定义量化表。
-
熵编码模块:
- 提供霍夫曼编码与解码功能。
- 可选择算术编码(需要启用)。
五、libjpeg 的使用方法
1. 编码(压缩)
以下是使用 libjpeg 将 RGB 图像编码为 JPEG 文件的基本流程:
#include
#include
void write_jpeg(const char *filename, unsigned char *image, int width, int height, int quality) {
struct jpeg_compress_struct cinfo;
struct jpeg_error_mgr jerr;
FILE *outfile = fopen(filename, "wb");
if (!outfile) {
fprintf(stderr, "Error: Cannot open file %s\n", filename);
return;
}
cinfo.err = jpeg_std_error(&jerr);
jpeg_create_compress(&cinfo);
jpeg_stdio_dest(&cinfo, outfile);
cinfo.image_width = width;
cinfo.image_height = height;
cinfo.input_components = 3; // RGB
cinfo.in_color_space = JCS_RGB;
jpeg_set_defaults(&cinfo);
jpeg_set_quality(&cinfo, quality, TRUE);
jpeg_start_compress(&cinfo, TRUE);
JSAMPROW row_pointer;
while (cinfo.next_scanline < cinfo.image_height) {
row_pointer = &image[cinfo.next_scanline * width * 3];
jpeg_write_scanlines(&cinfo, &row_pointer, 1);
}
jpeg_finish_compress(&cinfo);
fclose(outfile);
jpeg_destroy_compress(&cinfo);
}
2. 解码(解压缩)
解码 JPEG 文件到内存:
#include
#include
unsigned char* read_jpeg(const char *filename, int *width, int *height) {
struct jpeg_decompress_struct cinfo;
struct jpeg_error_mgr jerr;
FILE *infile = fopen(filename, "rb");
if (!infile) {
fprintf(stderr, "Error: Cannot open file %s\n", filename);
return NULL;
}
cinfo.err = jpeg_std_error(&jerr);
jpeg_create_decompress(&cinfo);
jpeg_stdio_src(&cinfo, infile);
jpeg_read_header(&cinfo, TRUE);
jpeg_start_decompress(&cinfo);
*width = cinfo.output_width;
*height = cinfo.output_height;
int row_stride = cinfo.output_width * cinfo.output_components;
unsigned char *image = malloc(cinfo.output_height * row_stride);
JSAMPROW row_pointer[1];
while (cinfo.output_scanline < cinfo.output_height) {
row_pointer[0] = &image[cinfo.output_scanline * row_stride];
jpeg_read_scanlines(&cinfo, row_pointer, 1);
}
jpeg_finish_decompress(&cinfo);
fclose(infile);
jpeg_destroy_decompress(&cinfo);
return image;
}
六、libjpeg 的优缺点
优点:
- 轻量级,适合嵌入式系统。
- 高性能,编码与解码效率高。
- 开源,跨平台支持良好。
缺点:
- 不支持 JPEG2000 等更现代的格式。
- 有限的扩展性,不支持复杂的图像处理功能。
七、ubuntu16.04下交叉编译libjpeg
官网 : https://www.ijg.org/
下载 jpegsrc.v9b.tar.gz : http://www.ijg.org/files/jpegsrc.v9b.tar.gz
编译步骤
1. 配置
./configure RANLIB=/opt/SDK/arm-linux-gnueabihf-ranlib
--prefix=/opt/libjpeg-9f
--exec-prefix=/opt/libjpeg-9f
--enable-shared
--enable-static
-host=arm-linux-gnueabihf
2. 编译
make -j4
make install
libjpeg 是图像处理领域的经典工具,凭借其高效、稳定的特性,成为 JPEG 图像压缩和解压的行业标准。尽管现代图像格式不断涌现(如 WebP、AVIF),libjpeg 仍然是许多系统的首选。对于开发者来说,掌握 libjpeg 的使用方法是高效处理 JPEG 图像的基础技能。