pub trait FromColor<Wp = D65, T = f32>: Sized{
// Required method
fn from_xyz(_: Xyz<Wp, T>) -> Self;
// Provided methods
fn from_yxy(inp: Yxy<Wp, T>) -> Self { ... }
fn from_lab(inp: Lab<Wp, T>) -> Self { ... }
fn from_lch(inp: Lch<Wp, T>) -> Self { ... }
fn from_rgb<S: RgbSpace<WhitePoint = Wp>>(inp: Rgb<Linear<S>, T>) -> Self { ... }
fn from_hsl<S: RgbSpace<WhitePoint = Wp>>(inp: Hsl<S, T>) -> Self { ... }
fn from_hsv<S: RgbSpace<WhitePoint = Wp>>(inp: Hsv<S, T>) -> Self { ... }
fn from_hwb<S: RgbSpace<WhitePoint = Wp>>(inp: Hwb<S, T>) -> Self { ... }
fn from_luma(inp: Luma<Linear<Wp>, T>) -> Self { ... }
}
Expand description
FromColor provides conversion from the colors.
It requires from_xyz, when implemented manually, and derives conversion to other colors as a default from this. These defaults must be overridden when direct conversion exists between colors. For example, Luma has direct conversion to LinRgb. So from_rgb conversion for Luma and from_luma for LinRgb is implemented directly. The from for the same color must override the default. For example, from_rgb for LinRgb will convert via Xyz which needs to be overridden with self to avoid the unnecessary conversion.
Deriving
FromColor
can be derived in a mostly automatic way. The strength of deriving it is that it
will also derive From
implementations for all of the palette
color types. The minimum
requirement is to implement From<Xyz>
, but it can also be customized to make use of generics
and have other manual implementations.
Item Attributes
-
#[palette_manual_from(Luma, Rgb = "from_rgb_internal")]
: Specifies the color types that the the custom color type already hasFrom
implementations for. Adding= "function_name"
tells it to use that function instead of aFrom
implementation. The default, when omitted, is to requireFrom<Xyz>
to be implemented. -
#[palette_white_point = "some::white_point::Type"]
: Sets the white point type that should be used when deriving. The default isD65
, but it may be any other type, including type parameters. -
#[palette_component = "some::component::Type"]
: Sets the color component type that should be used when deriving. The default isf32
, but it may be any other type, including type parameters. -
#[palette_rgb_space = "some::rgb_space::Type"]
: Sets the RGB space type that should be used when deriving. The default is to either useSrgb
or a best effort to convert between spaces, so sometimes it has to be set to a specific type. This does also accept type parameters.
Field Attributes
#[palette_alpha]
: Specifies that the field is the color’s transparency value.
Examples
Minimum requirements implementation:
#[macro_use]
extern crate palette;
use palette::{Srgb, Xyz};
/// A custom version of Xyz that stores integer values from 0 to 100.
#[derive(PartialEq, Debug, FromColor)]
struct Xyz100 {
x: u8,
y: u8,
z: u8,
}
// We have to at least implement conversion from Xyz if we don't
// specify anything else, using the `palette_manual_from` attribute.
impl From<Xyz> for Xyz100 {
fn from(color: Xyz) -> Self {
let scaled = color * 100.0;
Xyz100 {
x: scaled.x.max(0.0).min(100.0) as u8,
y: scaled.y.max(0.0).min(100.0) as u8,
z: scaled.z.max(0.0).min(100.0) as u8,
}
}
}
fn main() {
// Start with an sRGB color and convert it from u8 to f32,
// which is the default component type.
let rgb = Srgb::new(196u8, 238, 155).into_format();
// Convert the rgb color to our own format.
let xyz = Xyz100::from(rgb);
assert_eq!(
xyz,
Xyz100 {
x: 59,
y: 75,
z: 42,
}
);
}
With generic components:
#[macro_use]
extern crate palette;
#[macro_use]
extern crate approx;
use palette::{Component, FromColor, Hsv, Pixel, Srgb};
use palette::rgb::{Rgb, RgbSpace};
use palette::encoding::Linear;
use palette::white_point::D65;
use palette::float::Float;
/// sRGB, but with a reversed memory layout.
#[derive(PartialEq, Debug, FromColor, Pixel)]
#[palette_manual_from(Rgb = "from_rgb_internal")]
#[palette_component = "T"]
#[repr(C)] // Makes sure the memory layout is as we want it.
struct Bgr<T> {
blue: T,
green: T,
red: T,
}
// Rgb is a bit more complex than other colors, so we are
// implementing a private conversion function and letting it
// derive `From` automatically. It will take a round trip
// through linear format, but that's fine in this case.
impl<T: Component + Float> Bgr<T> {
// It converts from any linear Rgb type that has the D65
// white point, which is the default if we don't specify
// anything else with the `palette_white_point` attribute.
fn from_rgb_internal<S>(color: Rgb<Linear<S>, T>) -> Self
where
S: RgbSpace<WhitePoint = D65>,
{
let srgb = Srgb::from_rgb(color);
Bgr {
blue: srgb.blue,
green: srgb.green,
red: srgb.red,
}
}
}
fn main() {
let mut buffer = vec![0.0f64, 0.0, 0.0, 0.0, 0.0, 0.0];
{
let bgr_buffer = Bgr::from_raw_slice_mut(&mut buffer);
bgr_buffer[1] = Hsv::new(90.0, 1.0, 0.5).into();
}
assert_relative_eq!(buffer[3], 0.0);
assert_relative_eq!(buffer[4], 0.7353569830524495);
assert_relative_eq!(buffer[5], 0.5370987304831942);
}
With alpha component:
#[macro_use]
extern crate palette;
use palette::{FromColor, LinSrgba, Srgb};
use palette::rgb::{Rgb, RgbSpace};
use palette::encoding::Linear;
use palette::white_point::D65;
/// CSS style sRGB.
#[derive(PartialEq, Debug, FromColor)]
#[palette_manual_from(Rgb = "from_rgb_internal")]
struct CssRgb {
red: u8,
green: u8,
blue: u8,
#[palette_alpha]
alpha: f32,
}
// We will write a conversion function for opaque RGB and derive
// will take care of preserving the transparency for us.
impl CssRgb {
fn from_rgb_internal<S>(color: Rgb<Linear<S>, f32>) -> Self
where
S: RgbSpace<WhitePoint = D65>,
{
// Convert to u8 sRGB
let srgb = Srgb::from_rgb(color).into_format();
CssRgb {
red: srgb.red,
green: srgb.green,
blue: srgb.blue,
alpha: 1.0,
}
}
}
fn main() {
let color = LinSrgba::new(0.5, 0.0, 1.0, 0.3);
let css_color = CssRgb::from(color);
assert_eq!(
css_color,
CssRgb {
red: 188,
green: 0,
blue: 255,
alpha: 0.3,
}
);
}