#color-palette #palette #preset #interpolation #color-conversion #conversion #color

ratio-color

基于 'palette' 和 'interpolation' 的 Ratio 颜色调色板管理在 Rust 中实现

11个版本

0.4.5 2024年8月2日
0.4.4 2024年1月29日
0.4.3 2023年6月21日
0.4.1 2023年5月30日
0.1.0 2023年4月3日

555算法 中排名

Download history 1/week @ 2024-05-18 1/week @ 2024-05-25 47/week @ 2024-07-06 2/week @ 2024-07-13 71/week @ 2024-07-27 112/week @ 2024-08-03

189 每月下载量
用于 ratio-dsm

MIT/Apache

64KB
2K SLoC

Ratio Color

颜色调色板库。

变更日志

根据 Keep a Changelog 的建议,此仓库维护一个 CHANGELOG.md

贡献和许可证

要参与贡献,请随意fork,选择一个问题或提交您自己的问题,并开始合并!我们将非常乐意提供帮助。

您可能已经注意到,这个crate遵循“MIT-OR-Apache-2.0”许可证,而我们的其他一些crate遵循“GPL-3.0-or-later”许可证。这是故意的。我们认为某些crate是“仅仅是实用工具”,我们希望无条件的提供给整个Rust社区,而不问任何问题或提供任何保证。这是一个这样的实用工具crate。


lib.rs:

一个库,用于使绘图项目中的调色板管理更容易。它基于palette crate,该crate允许创建、混合以及通常使用颜色和像素。

一个使用粗体预设的简短分类示例

use ratio_color::{Categorical, Container, Palette, key_to_order};
use palette::Srgba;
let keys = ["foo", "bar", "baz", "quux"];
let categorical: Palette<&str, Srgba<u8>> = Palette::with_preset(
    &Categorical::Bold,
    key_to_order(keys)
);
assert_eq!(categorical.get("foo").expect("a color"), &Srgba::new(57, 105, 172, 255));

一个使用几个数值预设的简短数值示例

use ratio_color::{key_to_order, ColorAtFraction, Container, LinearGradient, Numerical, Palette};
use palette::Srgba;
let keys = ["foo", "bar", "baz", "quux"];
let numerical: Palette<&str, LinearGradient> = Palette::with_presets(
    &[Numerical::SeqMagma, Numerical::SeqViridis, Numerical::CycEdge, Numerical::DivSpectral],
    key_to_order(keys)
);

let gradient: &LinearGradient = numerical.get("bar").expect("a gradient");
assert_eq!(gradient, &LinearGradient::from(Numerical::SeqMagma));
let color: Srgba<u8> = gradient.color_at(0.5);
assert_eq!(color, Srgba::<u8>::new(183, 56, 120, 255));

此crate的关键结构是Palette,它实现了Container trait。容器是值切片(通常是一个向量)和键到它们的BTreeMap的混合,使用Selector枚举以多种方式访问它们,以获取适合值切片的索引或覆盖值。

在调色板方面,这相当于有一个固定数量的颜色或渐变可供选择(即值)。当将颜色绑定到键时,默认行为是使用映射中键的顺序来决定调色板中颜色使用的索引,使用 Selector::KeyOrder。但是,您可能希望使用 Selector::Index 或甚至一个完全覆盖的值(不在常规调色板中)Selector::Value 来为给定的键使用调色板中的特定颜色。

Palette 是一个泛型结构体,为任何可排序键和任何值实现了 Container

分类调色板

对于我们的示例调色板,我们将使用红色、绿色和蓝色作为我们的默认颜色或值。粉色将在稍后用作特殊案例。接下来,我们创建一组键,我们希望能够按需获取这些键的颜色。仅作为一个例子,我们将使用 "sun","trees","sky","ground","ditto" 和 "zzz"。请注意,我们拥有的键比默认颜色多!对于一些键,我们将使用索引分配固定颜色。其他键将根据其与其他键的顺序接收颜色。最后,对于 ditto 将进行例外处理。

use std::collections::BTreeMap;
use ratio_color::{Container, Palette, Selector};
use palette::Srgba;

// Create some categorical palette colors.
let red: Srgba<u8> = Srgba::new(255, 0, 0, 100);
let green: Srgba<u8> = Srgba::new(0, 255, 0, 200);
let blue: Srgba<u8> = Srgba::new(0, 0, 255, 255);

// Bundle them together in a vec to supply to the categorical palette later on.
let values = vec![red.clone(), green.clone(), blue.clone()];

// Initialize a BTreeMap to map from key to a selector.
let mut selectors = BTreeMap::new();
selectors.insert("sun", Selector::Index(0)); // red
selectors.insert("trees", Selector::Index(1)); // green
selectors.insert("sky", Selector::Index(2)); // blue
selectors.insert("ground", Selector::KeyOrder); // what will this be?
selectors.insert("zzz", Selector::KeyOrder); // I'm probably last.

// Ditto's are always pink, so they get a special value.
let pink: Srgba<u8> = Srgba::new(255, 125, 200, 255);
selectors.insert("ditto", Selector::Value(pink.clone()));

// Create the palette.
let palette = Palette::new(values, selectors);

// Let's check the contents!
assert_eq!(
    palette.get("sun").expect("a color"),
    &red,
    "our sun is red"
);
assert_eq!(
    palette.get("ditto").expect("a color"),
    &pink,
    "a ditto is pink"
);
assert_eq!(
    palette.get("ground").expect("a color"),
    &green,
    "the ground is green, because it's key is the second one by order (ditto, *ground*, sky, sun, trees, zzz)"
);
assert_eq!(
    palette.get("zzz").expect("a color"),
    &blue,
    "even though I'm sixth, I'll be 2 (blue) instead (index=5, per modulo 3 makes 2)"
)

因此,我们现在可以安全地为我们的给定键获取颜色。由于 Palette 的泛型性质,我们可以使用任何可排序键,也可以使用任何值。稍后添加或删除键是通过修改 Palette::selectors 属性或您决定连接到 Container::selectors 特性函数的任何属性来完成的。

为了不必然使您的错误堆栈拥挤,我们依赖于映射和向量的基本行为,通过返回值作为 Option 而不是抛出错误。

数值调色板

在存储和访问方面,数值调色板与分类调色板完全相同。由于 palette crate 不再直接提供连续的颜色刻度,我们引入了 ColorAtFraction 特性和 LinearGradient 结构体,它们使用 enterpolation crate 在线性化的颜色之间进行插值。

use palette::Srgba;
use ratio_color::{key_to_order, ColorAtFraction, LinearGradient, Palette, Container};

// Create basic colors.
let transparent: Srgba<u8> = Srgba::new(0, 0, 0, 0);
let red: Srgba<u8> = Srgba::new(255, 0, 0, 255);
let green: Srgba<u8> = Srgba::new(0, 255, 0, 255);
let blue: Srgba<u8> = Srgba::new(0, 0, 255, 255);

// Create three gradients.
let to_red =
    LinearGradient::new([transparent.clone(), red.clone()], None).expect("a gradient");
let to_green =
    LinearGradient::new([transparent.clone(), green.clone()], None).expect("a gradient");
let to_blue =
    LinearGradient::new([transparent.clone(), blue.clone()], None).expect("a gradient");

// Get a color from a linear gradient and convert it back into a regular Srgba.
// Note that blueness interpolation in the linear color space does not equal regular "mean"
// taking, but the alpha channel does.
let halfway_blue = Srgba::<u8>::from_linear(to_blue.color_at(0.5));
assert_eq!(halfway_blue, Srgba::<u8>::new(0, 0, 188, 128));

// Let's assert the endpoints for completeness' sake.
let start: Srgba<u8> = to_blue.color_at(0.0);
let end: Srgba<u8> = to_blue.color_at(1.0);
assert_eq!(&start, &transparent);
assert_eq!(&end, &blue);

// Store these in an palette for these keys.
let keys = ["foo", "bar", "baz", "quux"];
// Let keys resolve to their order in the BTreeMap.
// Actual palette creation.
let palette = Palette::new(
    [to_red.clone(), to_green.clone(), to_blue.clone()],
    key_to_order(keys)
);

// Test accessing and using a gradient.
let full_red: Srgba<u8> = palette.get("quux").expect("a gradient").color_at(1.0);
assert_eq!(&full_red, &red);
assert_eq!(
    <LinearGradient as ColorAtFraction<Srgba<u8>>>::color_at(
        palette.get("quux").expect("a gradient"),
        0.66
    ),
    Srgba::<u8>::new(212, 0, 0, 168),
        "Access quux at %66 using the fully qualified path to access the method."
);

依赖关系

~3MB
~61K SLoC