| Crates.io | tjpgdec-rs |
| lib.rs | tjpgdec-rs |
| version | 0.4.0 |
| created_at | 2026-01-09 18:37:19.254172+00 |
| updated_at | 2026-01-09 18:37:19.254172+00 |
| description | Tiny JPEG Decompressor - A lightweight JPEG decoder optimized for embedded systems |
| homepage | https://github.com/planet0104/tjpgdec-rs |
| repository | https://github.com/planet0104/tjpgdec-rs |
| max_upload_size | |
| id | 2032593 |
| size | 143,534 |
ChaN 的 TJpgDec 库的 Rust 实现 - 专为嵌入式系统设计的轻量级 JPEG 解码器。
三种优化级别:
| Level | Feature | 描述 | 工作区大小 | 适用平台 |
|---|---|---|---|---|
| 0 | fast-decode-0 |
基础优化 | 3100 bytes | 8/16 位 MCU |
| 1 | fast-decode-1 |
+ 32 位桶移位器 | 3500 bytes | 32 位 MCU(推荐 ESP32) |
| 2 | fast-decode-2 |
+ Huffman 快速查找表 | 9644 bytes | 最快,需要更多内存 |
use tjpgdec_rs::{JpegDecoder, MemoryPool, RECOMMENDED_POOL_SIZE, Result};
fn decode_jpeg(jpeg_data: &[u8]) -> Result<()> {
// 分配内存池
let mut pool_buffer = vec![0u8; RECOMMENDED_POOL_SIZE];
let mut pool = MemoryPool::new(&mut pool_buffer);
// 创建解码器
let mut decoder = JpegDecoder::new();
// 准备解码
decoder.prepare(jpeg_data, &mut pool)?;
// 获取图像信息
let width = decoder.width();
let height = decoder.height();
println!("图像尺寸: {}x{}", width, height);
// 计算所需缓冲区大小
let mcu_size = decoder.mcu_buffer_size();
let work_size = decoder.work_buffer_size();
// 分配工作缓冲区
let mut mcu_buffer = vec![0i16; mcu_size];
let mut work_buffer = vec![0u8; work_size];
// 分配输出帧缓冲区
let mut framebuffer = vec![0u8; (width as usize * height as usize * 3)];
let fb_width = width as usize;
// 解压缩
decoder.decompress(
jpeg_data,
0, // scale: 0=1/1, 1=1/2, 2=1/4, 3=1/8
&mut mcu_buffer,
&mut work_buffer,
&mut |_decoder, bitmap, rect| {
// bitmap 是 RGB888 格式,每像素 3 字节
let rect_width = (rect.right - rect.left + 1) as usize;
let bytes_per_row = rect_width * 3;
for y in rect.top..=rect.bottom {
let src_offset = ((y - rect.top) as usize) * bytes_per_row;
let dst_offset = (y as usize) * fb_width * 3 + (rect.left as usize) * 3;
if src_offset + bytes_per_row <= bitmap.len()
&& dst_offset + bytes_per_row <= framebuffer.len() {
framebuffer[dst_offset..dst_offset + bytes_per_row]
.copy_from_slice(&bitmap[src_offset..src_offset + bytes_per_row]);
}
}
Ok(true) // 继续解码
}
)?;
Ok(())
}
use tjpgdec_rs::{JpegDecoder, MemoryPool, RECOMMENDED_POOL_SIZE, Result};
pub fn decode_jpeg_to_rgb565(jpeg_data: &[u8]) -> Result<(u16, u16, Vec<u16>)> {
// 分配内存池
let mut pool_buffer = vec![0u8; RECOMMENDED_POOL_SIZE];
let mut pool = MemoryPool::new(&mut pool_buffer);
let mut decoder = JpegDecoder::new();
decoder.prepare(jpeg_data, &mut pool)?;
let width = decoder.width();
let height = decoder.height();
let mut mcu_buffer = vec![0i16; decoder.mcu_buffer_size()];
let mut work_buffer = vec![0u8; decoder.work_buffer_size()];
let mut output = vec![0u16; width as usize * height as usize];
let fb_width = width as usize;
decoder.decompress(
jpeg_data, 0,
&mut mcu_buffer, &mut work_buffer,
&mut |_decoder, bitmap, rect| {
let rect_width = (rect.right - rect.left + 1) as usize;
let bytes_per_row = rect_width * 3;
for y in rect.top..=rect.bottom {
let y_offset = (y - rect.top) as usize;
let src_offset = y_offset * bytes_per_row;
let dst_row = y as usize * fb_width + rect.left as usize;
for x in 0..rect_width {
let byte_idx = src_offset + x * 3;
if byte_idx + 2 < bitmap.len() {
let r = bitmap[byte_idx];
let g = bitmap[byte_idx + 1];
let b = bitmap[byte_idx + 2];
// RGB888 转 RGB565
let pixel = ((r as u16 & 0xF8) << 8)
| ((g as u16 & 0xFC) << 3)
| ((b as u16) >> 3);
output[dst_row + x] = pixel.swap_bytes();
}
}
}
Ok(true)
}
)?;
Ok((width, height, output))
}
在你的 Cargo.toml 中添加:
[dependencies]
tjpgdec-rs = "0.4.0"
或使用特定的特性标志:
[dependencies]
tjpgdec-rs = { version = "0.4.0", features = ["fast-decode-2"] }
| Feature | 描述 |
|---|---|
std(默认) |
启用标准库支持 |
fast-decode-0 |
JD_FASTDECODE=0:基础优化,适合 8/16 位 MCU |
fast-decode-1 |
JD_FASTDECODE=1:32 位桶移位器(推荐 ESP32) |
fast-decode-2 |
JD_FASTDECODE=2:+ Huffman 快速查找表(最快) |
fast-decode |
fast-decode-2 的别名 |
table-clip |
使用查找表进行值剪裁(增加 ~1KB 代码) |
use-scale |
启用输出缩放支持 |
debug-huffman |
启用 Huffman 解码调试输出 |
ESP32(推荐配置):
[dependencies]
tjpgdec-rs = { version = "0.4.0", default-features = false, features = ["fast-decode-2"] }
内存受限的 32 位 MCU:
[dependencies]
tjpgdec-rs = { version = "0.4.0", default-features = false, features = ["fast-decode-1"] }
8/16 位 MCU(实验性):
[dependencies]
tjpgdec-rs = { version = "0.4.0", default-features = false, features = ["fast-decode-0"] }
| 优化级别 | 解码器结构 | 工作区 | 说明 |
|---|---|---|---|
| Level 0 | ~120 bytes | 3100 bytes | 基础模式 |
| Level 1 | ~120 bytes | 3500 bytes | + 32 位寄存器 |
| Level 2 | ~120 bytes | 9644 bytes | + Huffman LUT |
use tjpgdec_rs::{JpegDecoder, MemoryPool, RECOMMENDED_POOL_SIZE};
// 创建内存池
let mut pool_buffer = vec![0u8; RECOMMENDED_POOL_SIZE];
let mut pool = MemoryPool::new(&mut pool_buffer);
// 创建解码器
let mut decoder = JpegDecoder::new();
// 准备解码
// decoder.prepare(jpeg_data, &mut pool)?;
// 获取图像信息
let width = decoder.width(); // 输出宽度(已应用缩放)
let height = decoder.height(); // 输出高度(已应用缩放)
let raw_width = decoder.raw_width(); // 原始宽度
let raw_height = decoder.raw_height(); // 原始高度
let components = decoder.components(); // 颜色分量数 (1=灰度, 3=彩色)
// 计算缓冲区大小
let mcu_size = decoder.mcu_buffer_size();
let work_size = decoder.work_buffer_size();
// 解压缩
// decoder.decompress(jpeg_data, scale, &mut mcu_buf, &mut work_buf, callback)?;
use tjpgdec_rs::fastdecode_level;
let level = fastdecode_level();
println!("当前 JD_FASTDECODE 级别: {}", level);
| C 函数/类型 | Rust 对应 |
|---|---|
jd_prepare() |
decoder.prepare() |
jd_decomp() |
decoder.decompress() |
JDEC |
JpegDecoder |
JRESULT |
Result<T> |
JRECT |
Rectangle |
alloc_pool() |
MemoryPool |
JD_FASTDECODE |
fast-decode-0/1/2 features |
tjpgdec-rs/
├── Cargo.toml
├── README.md / README.en.md
├── CHANGELOG.md
├── LICENSE
├── src/
│ ├── lib.rs # 库入口
│ ├── types.rs # 类型定义
│ ├── tables.rs # 常量表
│ ├── huffman.rs # Huffman 解码
│ ├── idct.rs # IDCT 和颜色转换
│ ├── decoder.rs # 主解码器
│ └── pool.rs # 内存池实现
└── examples/
├── basic.rs # 基本使用示例
├── jpg2bmp.rs # JPEG 转 BMP 工具
├── jpg2bmp_pool.rs # 使用内存池的 JPEG 转 BMP
├── test_info.rs # 测试图像信息
├── test_suite.rs # 测试套件
├── memory_comparison.rs # 内存使用对比
├── size_check.rs # 缓冲区大小检查
└── compare_outputs.ps1 # C/Rust 输出对比脚本
# 运行测试
cargo test
# 运行示例(使用 Level 2)
cargo run --example jpg2bmp -- input.jpg output.bmp
# 使用特定优化级别
cargo run --example jpg2bmp --no-default-features --features fast-decode-1 -- input.jpg
# 对比 C 和 Rust 输出(测试所有模式)
cd examples
powershell -ExecutionPolicy Bypass -File compare_outputs.ps1 -Mode all
# 只测试特定模式
powershell -ExecutionPolicy Bypass -File compare_outputs.ps1 -Mode 2
A: 确保使用 MemoryPool 分配内存。解码器本身只有 ~120 bytes,不会导致栈溢出。工作缓冲区应该在堆上分配(使用 vec![])。
A:
fast-decode-2(最快)或 fast-decode-1(节省内存)fast-decode-1,工作区只需 3500 bytesfast-decode-0(实验性)A:
fast-decode-1 替代 fast-decode-2(节省 ~6KB)本项目基于 TJpg_Decoder(原始作者:ChaN)
Rust 实现:MIT License
TJpgDec 模块是免费软件,没有任何担保。
无使用限制。您可以使用、修改和重新分发它用于
个人、非营利或商业产品,风险自负。
感谢 ChaN 创建了原始的 TJpgDec 库。