#color-space #rgb #xyz #color #graphics #rec709

srgb

提供 sRGB 原语和常量 — 轻量级 crate,包含在操作 sRGB 颜色时需要的函数和常量

11 个版本

0.3.3 2024年1月31日
0.3.2 2022年9月20日
0.3.1 2022年6月19日
0.3.0 2022年1月3日
0.1.4 2021年4月30日

#152图像


用于 2 crate

LGPL-3.0-or-later

2MB
1.5K SLoC

包含 (ELF exe/lib, 3.5MB) gamma8, (ELF exe/lib, 3.5MB) tmp

提供 sRGB 原语和常量

该 crate 提供了在 sRGB 颜色空间中操作颜色的原语。

具体来说,它提供了在 sRGB、线性 sRGB 和 XYZ 颜色空间之间进行转换的函数;公开了 D65 标准白点的定义以及 XYZ 转换矩阵;最后提供了处理 Rec.709 组件编码的函数。

它提供了与 sRGB 标准一起工作的低级原语。这些原语可以由其他需要将 sRGB 和其他颜色空间之间进行转换或混合 sRGB 颜色的库使用。

主模块提供的函数实现了 sRGB 和 XYZ 颜色空间之间的转换。在 gamma 子模块中,提供了 gamma 压缩和扩展函数,这些函数操作单个颜色分量。最后,[xyz] 子模块提供了在线性 sRGB 和 XYZ 颜色空间之间转换的函数以及公开这些函数使用的矩阵常量。

The crate includes highly-optimised 8-bit gamma functions both when converting from an 8-bit compressed value to a floating point linear value as well as conversion in the opposite direction. The latter is over two and a half times faster than naïve implementation of the gamma compression formula.

用法

使用此包与 Cargo 项目一起时,需要在 Cargo.toml 中添加单个依赖项

[dependencies]
srgb = "0.3"

添加依赖项后,现在可以编写将 sRGB 颜色转换为其他颜色空间的程序

#[derive(Debug)]
struct RGBColour(u8, u8, u8);

impl RGBColour {
    fn parse(value: &str) -> Option<Self> {
        value.strip_prefix('#')
            .and_then(|v| (v.len() == 6 && !v.starts_with('+')).then(|| v))
            .and_then(|v| u32::from_str_radix(v, 16).ok())
            .map(|v| Self((v >> 16) as u8, (v >> 8) as u8, v as u8))
    }

    fn normalise(&self) -> (f32, f32, f32) {
        let [r, g, b] = srgb::normalised_from_u8([self.0, self.1, self.2]);
        (r, g, b)
        // Alternatively divide each component by 255 manually
    }

    fn expand_gamma(&self) -> (f32, f32, f32) {
        (
            srgb::gamma::expand_u8(self.0),
            srgb::gamma::expand_u8(self.1),
            srgb::gamma::expand_u8(self.2),
        )
        // Alternatively a convenience function is provided as well:
        // let [r, g, b] = srgb::gamma::linear_from_u8([self.0, self.1, self.2]);
        // (r, g, b)
    }

    fn to_xyz(&self) -> (f32, f32, f32) {
        let linear = srgb::gamma::linear_from_u8([self.0, self.1, self.2]);
        let [r, g, b] = srgb::xyz::xyz_from_linear(linear);
        (r, g, b)
        // Alternatively, if a custom matrix multiplication is available:
        // let [r, g, b] = matrix_product(
        //     srgb::xyz::XYZ_FROM_SRGB_MATRIX, linear);
    }
}

fn main() {
    for arg in std::env::args().into_iter().skip(1) {
        if let Some(rgb) = RGBColour::parse(&arg[..]) {
            println!("sRGB:       {:?}", rgb);
            println!("Normalised: {:?}", rgb.normalise());
            println!("Linear:     {:?}", rgb.expand_gamma());
            println!("XYZ:        {:?}", rgb.to_xyz());
        } else {
            eprintln!("expected ‘#rrggbb’ but got {}", arg);
        }
    }
}

rgb crate 支持

这个crate没有显式支持rgb crate。然而,由于所有接受(s)RGB颜色作为参数的函数都接受impl Into<[f32; 3]>impl Into<[u8; 3]>,因此可以将RGB结构体传递给它们。类似地,这些函数返回[f32; 3][u8; 3],这些可以转换为RGB结构体。

extern crate rgb;
use rgb::ComponentMap;

fn parse(value: &str) -> Option<rgb::RGB8> {
    value.strip_prefix('#')
        .and_then(|v| (v.len() == 6 && !v.starts_with('+')).then(|| v))
        .and_then(|v| u32::from_str_radix(v, 16).ok())
        .map(|v| (rgb::RGB::new((v >> 16) as u8, (v >> 8) as u8, v as u8)))
}

fn normalise(colour: rgb::RGB8) -> rgb::RGB<f32> {
    srgb::normalised_from_u8(colour).into()
}

fn expand_gamma(colour: rgb::RGB8) -> rgb::RGB<f32> {
    colour.map(srgb::gamma::expand_u8)
}

fn to_xyz(colour: rgb::RGB8) -> (f32, f32, f32) {
    let linear = srgb::gamma::linear_from_u8(colour);
    let [r, g, b] = srgb::xyz::xyz_from_linear(linear);
    (r, g, b)
}

fn main() {
    for arg in std::env::args().into_iter().skip(1) {
        if let Some(colour) = parse(&arg[..]) {
            println!("sRGB:       {:?}", colour);
            println!("Normalised: {:?}", normalise(colour));
            println!("Linear:     {:?}", expand_gamma(colour));
            println!("XYZ:        {:?}", to_xyz(colour));
        } else {
            eprintln!("expected ‘#rrggbb’ but got {}", arg);
        }
    }
}

没有运行时依赖