17个版本
0.7.6 | 2024年4月28日 |
---|---|
0.7.5 | 2024年2月25日 |
0.7.4 | 2024年1月28日 |
0.7.3 | 2023年8月10日 |
0.2.1 | 2016年2月23日 |
#4 in 图像
119,131 每月下载量
用于 430 个crate(182直接使用)
1.5MB
27K SLoC
调色板
一个专注于保持正确性、灵活性和易用性的颜色管理和转换库。它利用类型系统来防止错误,支持广泛的颜色空间(包括用户定义的变体)并提供与其他库集成的不同方式。
功能摘要
- 颜色空间的类型系统表示,包括RGB、HSL、HSV、HWB、L*a*b*、L*C*h°、XYZ和xyY。
- 从和到颜色缓冲区的无拷贝转换允许简单地与其他crate和系统集成。
- 作为特质实现的颜色操作,如算术、加亮/变暗、色调偏移、混合/插值和SVG混合函数。
- 可以通过类型参数自定义颜色空间,以支持不同的精度、线性度、白点、RGB标准等。
- 支持
#[no_std]
。 - 可选的
serde
、rand
和bytemuck
集成。
最小支持的Rust版本 (MSRV)
此版本的Palette已与Rust版本 1.60.0
及 stable
、beta
和 nightly
频道进行自动测试。库的将来版本可能会提高最小支持的版本以利用新的语言特性,但这通常会被视为破坏性更改。可能会对安全补丁、依赖项在次要或补丁版本中提高MSRV以及类似更改做出例外。
入门指南
将以下行添加到您的 Cargo.toml
文件中
[dependencies]
palette = "0.7.6"
或者如果您想排除 std
[dependencies.palette]
version = "0.7.6"
default-features = false
features = ["libm"] # Uses libm instead of std for floating point math
Cargo功能
以下功能默认启用
"named"
- 启用颜色常量,位于named
模块。"named_from_str"
- 启用named::from_str
,将名称字符串映射到颜色。"std"
- 启用标准库的使用。同时启用"alloc"
。"alloc"
- 启用分配类型的实现,如Vec
或Box
。"approx"
- 启用使用approx
进行近似比较。
这些功能默认禁用
"serializing"
- 启用使用serde
进行颜色序列化和反序列化。"random"
- 启用使用rand
生成随机颜色。"libm"
- 使用libm
浮点数学库(当禁用std
功能时)。"bytemuck"
- 启用使用bytemuck
在普通数据类型之间进行转换。"wide"
- 启用使用wide
的 SIMD 类型支持。"find-crate"
- 启用 derive 以在Cargo.toml
中重命名palette
crate 时找到palette
crate。
在嵌入式环境中使用 palette
Palette 通过禁用 "std"
功能支持 #![no_std]
环境。它通过 "libm"
功能使用 libm
,以提供通常在 std
中的浮点运算,并通过 "alloc"
功能提供使用分配类型的特性。然而,没有标准库,无法使用 serde
进行序列化。
示例
这些是特征摘要中列出的某些功能的示例。
转换
可以使用 FromColor
和 IntoColor
特性将一种色彩空间转换为另一种。它们类似于 From
和 Into
,但专为色彩定制。
use palette::{FromColor, Hsl, IntoColor, Lch, Srgb};
let my_rgb = Srgb::new(0.8, 0.3, 0.3);
let mut my_lch = Lch::from_color(my_rgb);
my_lch.hue += 180.0;
let mut my_hsl: Hsl = my_lch.into_color();
my_hsl.lightness *= 0.6;
let my_new_rgb = Srgb::from_color(my_hsl);
此图展示了原始色彩以及两次变换的结果。
大多数常见的色彩空间已在 Palette 中实现,但在某些情况下可能需要更定制的功能。转换特性使得将自定义色彩类型集成到系统中成为可能。例如,这可以用于添加新的色彩空间或创建更简单的用户界面 API。
下面将提供一个更长的、更高级的示例,展示如何为自定义色彩类型实现转换特性。
像素和缓冲区
当处理图像或像素缓冲区,或任何可以转换为组件切片(例如 &[u8]
)的色彩类型时,cast
模块提供了将它们转换为 Palette 色彩切片的特性,而无需克隆整个缓冲区。
use palette::{cast::ComponentsAsMut, Srgb};
// The input to this function could be data from an image file or
// maybe a texture in a game.
fn swap_red_and_blue(my_rgb_image: &mut [u8]) {
// Convert `my_rgb_image` into `&mut [Srgb<u8>]` without copying.
let my_rgb_image: &mut [Srgb<u8>] = my_rgb_image.components_as_mut();
for color in my_rgb_image {
std::mem::swap(&mut color.red, &mut color.blue);
}
}
之前 | 之后 |
---|---|
还可以从切片或数组创建单个色彩。假设我们使用的是实现了 AsMut<[u8; 3]>
的东西。
use palette::Srgb;
fn swap_red_and_blue(mut my_rgb: impl AsMut<[u8; 3]>) {
let my_rgb: &mut Srgb<u8> = my_rgb.as_mut().into();
std::mem::swap(&mut my_rgb.red, &mut my_rgb.blue);
}
这使得与任何可以将色彩类型转换为切片和数组的 crate(例如 Palette)一起使用成为可能,只需编写少量的粘合代码,几乎没有开销。也可以将 Palette 类型转换为切片和数组。
色彩操作
Palette 内置了许多色彩操作,如饱和度/非饱和度、色调偏移等,以操作符特性的形式存在。这意味着可以编写通用的函数,在支持这些操作的任何色彩空间上执行这些操作。输出将根据色彩空间的特性而变化。
use palette::{Hsl, Hsv, Lighten, Mix, ShiftHue};
fn transform_color<C>(color: C, amount: f32) -> C
where
C: ShiftHue<Scalar = f32> + Lighten<Scalar = f32> + Mix<Scalar = f32> + Copy,
{
let new_color = color.shift_hue(170.0).lighten(1.0);
// Interpolate between the old and new color.
color.mix(new_color, amount)
}
let new_hsl = transform_color(Hsl::new_srgb(0.00, 0.70, 0.20), 0.8);
let new_hsv = transform_color(Hsv::new_srgb(0.00, 0.82, 0.34), 0.8);
此图展示了从色彩到 new_color
在 HSL 和 HSV 中的过渡。
除了操作符特性之外,还实现了 SVG 混合和组合函数。
use palette::{
blend::Compose,
cast::{ComponentsAs, ComponentsAsMut},
Srgb, WithAlpha,
};
// The input to this function could be data from image files.
fn alpha_blend_images(image1: &mut [u8], image2: &[u8]) {
// Convert the images into `&mut [Srgb<u8>]` and `&[Srgb<u8>]` without copying.
let image1: &mut [Srgb<u8>] = image1.components_as_mut();
let image2: &[Srgb<u8>] = image2.components_as();
for (color1, color2) in image1.iter_mut().zip(image2) {
// Convert the colors to linear floating point format and give them transparency values.
let color1_alpha = color1.into_linear().opaque();
let color2_alpha = color2.into_linear().with_alpha(0.5);
// Alpha blend `color2_alpha` over `color1_alpha`.
let blended = color2_alpha.over(color1_alpha);
// Convert the color part back to `Srgb<u8>` and overwrite the value in image1.
*color1 = blended.color.into_encoding();
}
}
图片 1 | 图片 2 | 结果 |
---|---|---|
还有将显式转换为和从预乘 Alpha 转换的选项,以避免不必要的来回转换,使用 PreAlpha
类型。
渐变
大多数色彩类型与渐变和插值 crate(如 enterpolation
)直接兼容。
use enterpolation::{linear::ConstEquidistantLinear, Curve};
use palette::LinSrgb;
let gradient = ConstEquidistantLinear::<f32, _, 3>::equidistant_unchecked([
LinSrgb::new(0.00, 0.05, 0.20),
LinSrgb::new(0.70, 0.10, 0.20),
LinSrgb::new(0.95, 0.90, 0.30),
]);
let taken_colors: Vec<_> = gradient.take(10).collect();
以下是渐变的连续形式及其从 .take(10)
的 10 种颜色。
自定义色彩空间
为了应对尽可能多的变化,内置的色彩空间已被设置为可定制。更常见的变体已公开为类型别名(如上文的 Srgb
、Srgba
和 LinSrgb
),但完全可以创建自定义组合,包括全新的参数。例如,创建自己的 RGB 标准。
use palette::{
encoding,
white_point,
rgb::Rgb,
chromatic_adaptation::AdaptFrom,
Srgb
};
// RgbStandard and RgbSpace are implemented for 2 and 3 element tuples,
// allowing mixing and matching of existing types. In this case we are
// combining sRGB primaries, the CIE equal energy white point and the
// sRGB transfer function (a.k.a. encoding or gamma).
type EqualEnergyStandard = (encoding::Srgb, white_point::E, encoding::Srgb);
type EqualEnergySrgb<T> = Rgb<EqualEnergyStandard, T>;
let ee_rgb = EqualEnergySrgb::new(1.0, 0.5, 0.3);
// We need to use chromatic adaptation when going between white points.
let srgb = Srgb::adapt_from(ee_rgb);
还可以为自定义类型实现特性,当内置选项不足时。
转换自定义色彩类型
以下示例展示了 Palette 用户如何从自定义的 Color
类型进行转换。虽然不是一行代码,但可以节省大量的重复手动工作。
use palette::{
convert::FromColorUnclamped,
encoding,
rgb::Rgb,
IntoColor, WithAlpha, Clamp, Srgb, Lcha
};
// This implements conversion to and from all Palette colors.
#[derive(FromColorUnclamped, WithAlpha)]
// We have to tell Palette that we will take care of converting to/from sRGB.
#[palette(skip_derives(Rgb), rgb_standard = "encoding::Srgb")]
struct Color {
r: f32,
g: f32,
b: f32,
// Let Palette know this is our alpha channel.
#[palette(alpha)]
a: f32,
}
// There's no blanket implementation for Self -> Self, unlike the From trait.
// This is to better allow cases like Self<A> -> Self<B>.
impl FromColorUnclamped<Color> for Color {
fn from_color_unclamped(color: Color) -> Color {
color
}
}
// Convert from any kind of f32 sRGB.
impl<S> FromColorUnclamped<Rgb<S, f32>> for Color
where
Srgb: FromColorUnclamped<Rgb<S, f32>>,
{
fn from_color_unclamped(color: Rgb<S, f32>) -> Color {
let srgb = Srgb::from_color_unclamped(color);
Color { r: srgb.red, g: srgb.green, b: srgb.blue, a: 1.0 }
}
}
// Convert into any kind of f32 sRGB.
impl<S> FromColorUnclamped<Color> for Rgb<S, f32>
where
Rgb<S, f32>: FromColorUnclamped<Srgb>,
{
fn from_color_unclamped(color: Color) -> Self {
let srgb = Srgb::new(color.r, color.g, color.b);
Self::from_color_unclamped(srgb)
}
}
// Add the required clamping.
impl Clamp for Color {
fn clamp(self) -> Self {
Color {
r: self.r.min(1.0).max(0.0),
g: self.g.min(1.0).max(0.0),
b: self.b.min(1.0).max(0.0),
a: self.a.min(1.0).max(0.0),
}
}
}
// This function uses only our `Color`, but Palette users can convert to it.
fn do_something(color: Color) {
// ...
}
do_something(Color { r: 1.0, g: 0.0, b: 1.0, a: 0.5 });
do_something(Lcha::new(60.0, 116.0, 328.0, 0.5).into_color());
// This function has the conversion built in and takes any compatible
// color type as input.
fn generic_do_something(color: impl IntoColor<Color>) {
let color = color.into_color();
// ...
}
generic_do_something(Color { r: 1.0, g: 0.0, b: 1.0, a: 0.5 });
generic_do_something(Lcha::new(60.0, 116.0, 328.0, 0.5));
许可
许可协议为以下之一
- Apache许可证,版本2.0,(LICENSE-APACHE 或 http://www.apache.org/licenses/LICENSE-2.0)
- MIT许可证(LICENSE-MIT 或 http://opensource.org/licenses/MIT)
根据您的选择。
依赖项
~0.4–1.4MB
~31K SLoC