12 个版本 (重大变更)

0.11.0 2021 年 10 月 21 日
0.7.1 2020 年 12 月 31 日
0.7.0 2019 年 7 月 21 日
0.6.0 2018 年 6 月 15 日
0.5.0 2017 年 5 月 28 日

#37 in 渲染

Download history 2/week @ 2024-03-07 43/week @ 2024-03-28 22/week @ 2024-04-04

每月 83 次下载

BSD-3-Clause

4MB
14K SLoC

OpenEXR

绑定版本:3.0.5

openexr crate 提供了对 ASWF OpenEXR 库 的高级绑定,允许读取和写入 OpenEXR 格式(EXR 代表 EXtended Range)的文件。OpenEXR 格式是电影行业的实际图像存储格式。

EXR 格式的目的是准确地高效地表示高动态范围场景线性图像数据和相关的元数据,并强烈支持多部分、多通道的使用案例。

OpenEXR 在需要高精度的主机应用程序软件中得到广泛应用,如真实感渲染、纹理访问、图像合成、深度合成和 DI。OpenEXR 是 Academy Software Foundation 的一个项目。该格式和库最初由工业光魔公司开发,并于 2003 年首次发布。Weta Digital、华特迪士尼动画工作室、索尼影业数字制作公司、皮克斯动画工作室、梦工厂和其他工作室、公司和个人都对代码库做出了贡献。

OpenEXR 包含在 VFX 参考平台 中。

openexr crate 由 vfx-rs 项目 维护。

快速入门

使用包含的 C++ OpenEXR 源代码

cargo add openexr
cargo build

虽然此方法得到支持并且是最容易开始的方法,但强烈建议您单独构建和安装 C++ 库,并像这样针对它构建 crate

cargo add openexr
CMAKE_PREFIX_PATH=/path/to/cmake/configs cargo build

请注意,您必须确保您指向的OpenEXR版本与crate的此版本相同,否则由于所有OpenEXR符号都有版本号,您将遇到链接错误。

prelude 汇入了您进行基本RGBA和任意通道图像文件I/O所需的一组类型

use openexr::prelude::*;

fn write_rgba1(filename: &str, pixels: &[Rgba], width: i32, height: i32)
-> Result<(), Box<dyn std::error::Error>> {
    let header = Header::from_dimensions(width, height);
    let mut file = RgbaOutputFile::new(
        filename,
        &header,
        RgbaChannels::WriteRgba,
        1,
    )?;

    file.set_frame_buffer(&pixels, 1, width as usize)?;
    file.write_pixels(height)?;

    Ok(())
}

fn read_rgba1(path: &str) -> Result<(), Box<dyn std::error::Error>> {
    use imath_traits::Zero;

    let mut file = RgbaInputFile::new(path, 1).unwrap();
    // Note that windows in OpenEXR are ***inclusive*** bounds, so a
    // 1920x1080 image has window [0, 0, 1919, 1079].
    let data_window: [i32; 4] = *file.header().data_window();
    let width = data_window.width() + 1;
    let height = data_window.height() + 1;

    let mut pixels = vec![Rgba::zero(); (width * height) as usize];
    file.set_frame_buffer(&mut pixels, 1, width as usize)?;
    file.read_pixels(0, height - 1)?;

    Ok(())
}

除此之外,与深度图像相关的类型位于 deep 模块中,而分块图像位于 tiled 模块中。

阅读和写入OpenEXR图像文件 文档是探索crate完整功能的好起点。它包含了几乎所有内容的示例用法。

Math Crate互操作性

OpenEXR(以及VFX生态系统的很大一部分)依赖于Imath来处理基本数学原语,如向量和边界框。

Rust已经拥有几个针对图形等线性代数的成熟crate,例如 cgmathnalgebranalgebra-glmglam。我们不是在这个拥挤的领域添加另一个竞争者,而是提供一组特质,允许这些crate中的任何一个以 imath-traits 的形式与openexr一起使用。默认情况下,这些特质为数组和切片实现,因此您会发现本文档中的示例倾向于使用例如 [i32; 4] 来表示边界框

use openexr::prelude::*;
fn read_rgba1(path: &str) -> Result<(), Box<dyn std::error::Error>> {
    use imath_traits::Zero;
    let mut file = RgbaInputFile::new(path, 1).unwrap();
    let data_window = file.header().data_window::<[i32; 4]>().clone();
    let width = data_window.width() + 1;
    let height = data_window.height() + 1;
    Ok(())
}

要使用您首选的数学crate,只需在openexr中启用相应的功能,这将是一个 imath_<name>,例如

cargo build --features=imath_cgmath

现在您可以使用该crate中的类型与openexr无缝配合。如果数学crate不提供边界框类型,则将作为 imath_traits::Box2iimath_traits::Box3i 提供

use openexr::prelude::*;
#[cfg(feature = "imath_cgmath")]
fn read_rgba1(path: &str) -> Result<(), Box<dyn std::error::Error>> {
   use imath_traits::Zero;
    use imath_traits::Box2i;

    let mut file = RgbaInputFile::new(path, 1).unwrap();
    let data_window: Box2i = *file.header().data_window();
    let width = data_window.width() + 1;
    let height = data_window.height() + 1;
    Ok(())
}

安全性

OpenEXR API的一些部分在安全Rust中不容易表示。值得注意的是,SliceFrameBuffer 和各种文件类型之间的交互本质上在像素数据背后的内存和文件之间创建了一个(可变的)引用链。

用生命周期表示以使Rust编译器能够跟踪它,会使使用这些类型的工作变得非常难以管理,因此,实际上使用切片和帧缓冲区中的指针的方法被标记为不安全。调用者的责任是确保在读取或写入图像时,插入到帧缓冲区中的指针仍然有效

// set_frame_buffer internally stores a slice in a frame buffer on the file
// struct. pixels must live until the write_pixels call below has completed.
file.set_frame_buffer(&pixels, 1, width as usize)?;
unsafe {
    file.write_pixels(height)?;
}

特性

  • 高动态范围和颜色精度。
  • 支持16位浮点、32位浮点和32位整数像素。
  • 多种图像压缩算法,包括无损和有损。一些包含的编解码器可以在有噪点的图像上实现2:1的无损压缩比率。有损编解码器已被调整以优化视觉质量和解码性能。
  • 可扩展性。可以添加新的图像属性(字符串、向量、整数等)到OpenEXR图像头中,而不会影响现有OpenEXR应用程序的向后兼容性。
  • 支持立体图像工作流程和到多视图的推广。
  • 对深度数据的灵活支持:像素可以存储可变长度的样本列表,因此,每个像素可以在不同深度存储多个值。同时支持硬表面和体积数据表示。
  • 多部分:能够在单个文件中编码相互关联但独立的图像。这允许访问单个部分,而无需读取文件中的其他部分。

依赖项

~5–7.5MB
~180K SLoC