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 在 算法 中排名
189 每月下载量
用于 ratio-dsm
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