10 个版本
使用旧的 Rust 2015
0.4.1 | 2024 年 4 月 26 日 |
---|---|
0.3.5 | 2021 年 4 月 22 日 |
0.3.4 | 2020 年 1 月 29 日 |
0.3.3 | 2019 年 11 月 25 日 |
0.1.1 | 2019 年 8 月 15 日 |
#162 在 图像
170 每月下载量
用于 2 crate
7.5MB
2.5K SLoC
mtpng
Rust 中的并行化 PNG 编码器
由 Brooke Vibber [email protected]
背景
在大型图像尺寸下压缩 PNG 文件是一种相对较慢的操作,4K 分辨率及以上可能需要从半秒到一秒以上。有关更多详细信息,请参阅 我的关于该主题的博客系列。
传统 libpng 中最大的 CPU 成本似乎是过滤,这很容易并行化,以及 deflate 压缩,这可以在块边界之间稍微损失压缩的情况下并行处理。
pigz 是一个著名的并行化 deflate/gzip 压缩的 C 实现,也是这里使用的分块方案的强大灵感来源。
我还受到了 Pascal Beyeler 的一个名为 png-parallel
的实验性 C++/OpenMP 项目的启发,该项目没有实现过滤,但证实了基本理论。
状态
在所有颜色格式中创建正确的文件(输入必须预先打包)。在大文件上表现良好,但需要在小文件和辅助块上做更多工作。计划很快稳定 API,但尚未完成——在 1.0 之前,事情将会发生变化。
目标
性能
- ☑️ 一定要在多线程中比 libpng 快
- ☑️ 应该与单线程的 libpng 一样快或更快
功能
- ☑️ 一定要支持所有标准颜色类型和深度
- ☑️ 一定要支持所有标准过滤模式
- ☑️ 一定要压缩得与 libpng 几乎一样好
- 可能比 libpng 实现更好的压缩,但不能以牺牲性能为代价
- ☑️ 应该支持流式输出
- 可能支持交错
兼容性
- ☑️ 一定要有一个好的 Rust API(进行中)
- ☑️ 一定要有一个好的 C API(进行中)
- ☑️ 一定要在 Linux x86、x86_64 上运行
- ☑️ 一定要在 Linux arm、arm64 上运行
- ☑️ 应该在 macOS x86_64 上运行
- ☑️ 应该在 iOS arm64 上运行
- ☑️ 应该在 Windows x86、x86_64 上运行
- ☑️️ 应该在 Windows arm64 上运行
压缩
压缩率比使用双-4K截图和结构照片的libpng略低,当前默认的256 KiB块大小,随着其增大而逐渐接近。
使用较小的块大小或启用流模式,可以在略微增加文件大小的同时,获得更高的并行性(小块)和更低的延迟(流式传输)。
在0.3.5版本中,对过滤器启发式算法进行了修正,以在某些与libpng不同的情境中匹配libpng;现在作为替换使用时,应提供与libpng非常相似的结果。后续的研究可能涉及更改启发式算法,因为它无法正确预测许多截图风格真彩色图像的“无”过滤器的良好性能。
性能
请注意,未优化的调试构建比优化后的发布构建慢约50倍。请始终使用--release
运行!
截至2018年9月26日,使用Rust 1.29.0,在Linux x86_64上的单线程性能比libpng快约30-40%,保存相同双-4K截图样本图像。使用多线程可以持续击败libpng,并且至少在8个物理核心上具有良好的扩展性。
有关各种设备的非正式基准测试,请参阅docs/perf.md。
在默认设置下,未压缩数据小于128 KiB的文件不会看到多线程带来的任何好处,但可能仍然比libpng运行得更快,因为过滤速度更快。
待办事项
有关详细信息,请参阅GitHub上的项目列表。
构建说明
使用Cargo构建过程;请注意,libz_sys被拉入,它可能在某些未提供标准库的平台(如Windows)上构建zlib C库。
有两个用户可见的功能标志
capi
构建并导出兼容C的API符号;仅在您计划将生成的库与调用它的C/C++代码链接时需要cli
构建用于测试/演示的命令行工具以及库
在纯Rust程序中使用mtpng或在混合C-Rust程序中仅使用Rust部分时,不需要使用任一标志。
用法
注意:Rust和C API尚不稳定,将在1.0之前发生变化。
Rust用法
有关详细信息,请参阅crate API文档。
可以mtpng CLI工具作为编写文件的示例。
简而言之,类似于以下内容
let mut writer = Vec::<u8>::new();
let mut header = Header::new();
header.set_size(640, 480)?;
header.set_color(ColorType::TruecolorAlpha, 8)?;
let mut options = Options::new();
let mut encoder = Encoder::new(writer, &options);
encoder.write_header(&header)?;
encoder.write_image_rows(&data)?;
encoder.finish()?;
C用法
有关C头文件的详细信息,请参阅c/mtpng.h,该头文件连接到mtpng::capi模块中的不安全Rust包装函数。
在Linux或macOS上构建C示例,请运行make
。在Windows上,运行build-win.bat x64
进行x86-64原生构建,或者传递x86
或arm64
以构建这些平台。
这将从sample.c构建一个sample
可执行文件,以及一个libmtpng.so
、libmtpng.dylib
或mtpng.dll
库,以便于链接。它会在out/csample.png
中产生输出文件。
数据流
编码可以分解为多个并行块
解码不能;它必须以流的形式运行,但可以实现管道(尚未实现)
依赖项
Rayon 用于其 ThreadPool 实现。您可以使用默认的 Rayon 全局池或自定义 ThreadPool 实例创建编码器。
crc 用于计算 PNG 块校验和。
libz-sys 用于封装 libz 以进行 deflate 压缩。我简要地看了看纯 Rust 实现,但找不到任何支持原始流输出、字典设置以及在不关闭流的情况下刷新到字节边界的实现。
itertools 用于在过滤器中管理迭代。
png 由 CLI 工具用于加载输入文件以进行测试重新压缩。
clap 由 CLI 工具用于处理选项解析和帮助显示。
time 由 CLI 工具用于计时压缩。
许可证
您可以在以下 MIT 风格许可证下使用此软件
版权 (c) 2018-2024 Brooke Vibber
特此授予任何获得此软件及其相关文档副本(以下简称“软件”)的人免费使用软件的权利,包括但不限于使用、复制、修改、合并、发布、分发、再许可和/或销售软件副本,以及允许向提供软件的人做上述行为,前提是遵守以下条件
上述版权声明和本许可声明应包含在软件的所有副本或主要部分中。
软件按“原样”提供,不提供任何形式的保证,无论是明示的还是暗示的,包括但不限于适销性、特定用途适用性和非侵权性保证。在任何情况下,作者或版权所有者均不对任何索赔、损害或其他责任承担责任,无论这些责任源于合同、侵权或其他原因,是否与软件或软件的使用或其他交易有关。
依赖项
~2.3–3.5MB
~65K SLoC