Remove Color struct from document-legacy (#1012)

This commit is contained in:
Keavon Chambers 2023-02-07 17:31:50 -08:00
parent 5462bf5f2f
commit 202b0ee6ed
28 changed files with 84 additions and 257 deletions

1
Cargo.lock generated
View file

@ -1706,6 +1706,7 @@ dependencies = [
"bezier-rs",
"glam",
"graph-craft",
"graphene-core",
"graphene-std",
"image",
"kurbo",

View file

@ -13,6 +13,7 @@ license = "Apache-2.0"
[dependencies]
graph-craft = { path = "../node-graph/graph-craft", features = ["serde"] }
graphene-std = { path = "../node-graph/gstd", features = ["serde"] }
graphene-core = { path = "../node-graph/gcore", features = ["serde"] }
image = { version = "0.24", default-features = false }
log = "0.4"

View file

@ -1,221 +0,0 @@
use serde::{Deserialize, Serialize};
/// Structure that represents a color.
/// Internally alpha is stored as `f32` that ranges from `0.0` (transparent) to `1.0` (opaque).
/// The other components (RGB) are stored as `f32` that range from `0.0` up to `f32::MAX`,
/// the values encode the brightness of each channel proportional to the light intensity in cd/m² (nits) in HDR, and `0.0` (black) to `1.0` (white) in SDR color.
#[repr(C)]
#[derive(Debug, Clone, Copy, PartialEq, Default, Serialize, Deserialize, specta::Type)]
pub struct Color {
red: f32,
green: f32,
blue: f32,
alpha: f32,
}
impl Color {
pub const BLACK: Color = Color::from_uchecked(0., 0., 0.);
pub const WHITE: Color = Color::from_uchecked(1., 1., 1.);
pub const RED: Color = Color::from_uchecked(1., 0., 0.);
pub const GREEN: Color = Color::from_uchecked(0., 1., 0.);
pub const BLUE: Color = Color::from_uchecked(0., 0., 1.);
pub const TRANSPARENT: Color = Self {
red: 0.,
green: 0.,
blue: 0.,
alpha: 0.,
};
/// Returns `Some(Color)` if `red`, `green`, `blue` and `alpha` have a valid value. Negative numbers (including `-0.0`), NaN, and infinity are not valid values and return `None`.
/// Alpha values greater than `1.0` are not valid.
///
/// # Examples
/// ```
/// use graphite_document_legacy::color::Color;
/// let color = Color::from_rgbaf32(0.3, 0.14, 0.15, 0.92).unwrap();
/// assert!(color.components() == (0.3, 0.14, 0.15, 0.92));
///
/// let color = Color::from_rgbaf32(1.0, 1.0, 1.0, f32::NAN);
/// assert!(color == None);
/// ```
pub fn from_rgbaf32(red: f32, green: f32, blue: f32, alpha: f32) -> Option<Color> {
if alpha > 1. || [red, green, blue, alpha].iter().any(|c| c.is_sign_negative() || !c.is_finite()) {
return None;
}
Some(Color { red, green, blue, alpha })
}
/// Return an opaque `Color` from given `f32` RGB channels.
pub const fn from_uchecked(red: f32, green: f32, blue: f32) -> Color {
Color { red, green, blue, alpha: 1. }
}
/// Return an opaque SDR `Color` given RGB channels from `0` to `255`.
///
/// # Examples
/// ```
/// use graphite_document_legacy::color::Color;
/// let color = Color::from_rgb8(0x72, 0x67, 0x62);
/// let color2 = Color::from_rgba8(0x72, 0x67, 0x62, 0xFF);
/// assert!(color == color2)
/// ```
pub fn from_rgb8(red: u8, green: u8, blue: u8) -> Color {
Color::from_rgba8(red, green, blue, 255)
}
/// Return an SDR `Color` given RGBA channels from `0` to `255`.
///
/// # Examples
/// ```
/// use graphite_document_legacy::color::Color;
/// let color = Color::from_rgba8(0x72, 0x67, 0x62, 0x61);
/// assert!("72676261" == color.rgba_hex())
/// ```
pub fn from_rgba8(red: u8, green: u8, blue: u8, alpha: u8) -> Color {
let map_range = |int_color| int_color as f32 / 255.0;
Color {
red: map_range(red),
green: map_range(green),
blue: map_range(blue),
alpha: map_range(alpha),
}
}
/// Return the `red` component.
///
/// # Examples
/// ```
/// use graphite_document_legacy::color::Color;
/// let color = Color::from_rgbaf32(0.114, 0.103, 0.98, 0.97).unwrap();
/// assert!(color.r() == 0.114);
/// ```
pub fn r(&self) -> f32 {
self.red
}
/// Return the `green` component.
///
/// # Examples
/// ```
/// use graphite_document_legacy::color::Color;
/// let color = Color::from_rgbaf32(0.114, 0.103, 0.98, 0.97).unwrap();
/// assert!(color.g() == 0.103);
/// ```
pub fn g(&self) -> f32 {
self.green
}
/// Return the `blue` component.
///
/// # Examples
/// ```
/// use graphite_document_legacy::color::Color;
/// let color = Color::from_rgbaf32(0.114, 0.103, 0.98, 0.97).unwrap();
/// assert!(color.b() == 0.98);
/// ```
pub fn b(&self) -> f32 {
self.blue
}
/// Return the `alpha` component without checking its expected `0.0` to `1.0` range.
///
/// # Examples
/// ```
/// use graphite_document_legacy::color::Color;
/// let color = Color::from_rgbaf32(0.114, 0.103, 0.98, 0.97).unwrap();
/// assert!(color.a() == 0.97);
/// ```
pub fn a(&self) -> f32 {
self.alpha
}
/// Return the all components as a tuple, first component is red, followed by green, followed by blue, followed by alpha.
///
/// # Examples
/// ```
/// use graphite_document_legacy::color::Color;
/// let color = Color::from_rgbaf32(0.114, 0.103, 0.98, 0.97).unwrap();
/// assert!(color.components() == (0.114, 0.103, 0.98, 0.97));
/// ```
pub fn components(&self) -> (f32, f32, f32, f32) {
(self.red, self.green, self.blue, self.alpha)
}
/// Return an 8-character RGBA hex string (without a # prefix).
///
/// # Examples
/// ```
/// use graphite_document_legacy::color::Color;
/// let color = Color::from_rgba8(0x7C, 0x67, 0xFA, 0x61);
/// assert!("7C67FA61" == color.rgba_hex())
/// ```
pub fn rgba_hex(&self) -> String {
format!(
"{:02X?}{:02X?}{:02X?}{:02X?}",
(self.r() * 255.) as u8,
(self.g() * 255.) as u8,
(self.b() * 255.) as u8,
(self.a() * 255.) as u8,
)
}
/// Return a 6-character RGB hex string (without a # prefix).
/// ```
/// use graphite_document_legacy::color::Color;
/// let color = Color::from_rgba8(0x7C, 0x67, 0xFA, 0x61);
/// assert!("7C67FA" == color.rgb_hex())
/// ```
pub fn rgb_hex(&self) -> String {
format!("{:02X?}{:02X?}{:02X?}", (self.r() * 255.) as u8, (self.g() * 255.) as u8, (self.b() * 255.) as u8,)
}
/// Creates a color from a 8-character RGBA hex string (without a # prefix).
///
/// # Examples
/// ```
/// use graphite_document_legacy::color::Color;
/// let color = Color::from_rgba_str("7C67FA61").unwrap();
/// assert!("7C67FA61" == color.rgba_hex())
/// ```
pub fn from_rgba_str(color_str: &str) -> Option<Color> {
if color_str.len() != 8 {
return None;
}
let r = u8::from_str_radix(&color_str[0..2], 16).ok()?;
let g = u8::from_str_radix(&color_str[2..4], 16).ok()?;
let b = u8::from_str_radix(&color_str[4..6], 16).ok()?;
let a = u8::from_str_radix(&color_str[6..8], 16).ok()?;
Some(Color::from_rgba8(r, g, b, a))
}
/// Creates a color from a 6-character RGB hex string (without a # prefix).
/// ```
/// use graphite_document_legacy::color::Color;
/// let color = Color::from_rgb_str("7C67FA").unwrap();
/// assert!("7C67FA" == color.rgb_hex())
/// ```
pub fn from_rgb_str(color_str: &str) -> Option<Color> {
if color_str.len() != 6 {
return None;
}
let r = u8::from_str_radix(&color_str[0..2], 16).ok()?;
let g = u8::from_str_radix(&color_str[2..4], 16).ok()?;
let b = u8::from_str_radix(&color_str[4..6], 16).ok()?;
Some(Color::from_rgb8(r, g, b))
}
/// Linearly interpolates between two colors based on t.
///
/// T must be between 0 and 1.
pub fn lerp(self, other: Color, t: f32) -> Option<Self> {
assert!((0. ..=1.).contains(&t));
Color::from_rgbaf32(
self.red + ((other.red - self.red) * t),
self.green + ((other.green - self.green) * t),
self.blue + ((other.blue - self.blue) * t),
self.alpha + ((other.alpha - self.alpha) * t),
)
}
}

View file

@ -1,4 +1,4 @@
use crate::color::Color;
use graphene_core::raster::color::Color;
// RENDERING
pub const LAYER_OUTLINE_STROKE_COLOR: Color = Color::BLACK;

View file

@ -1,9 +1,10 @@
//! Contains stylistic options for SVG elements.
use super::text_layer::FontCache;
use crate::color::Color;
use crate::consts::{LAYER_OUTLINE_STROKE_COLOR, LAYER_OUTLINE_STROKE_WEIGHT};
use graphene_core::raster::color::Color;
use glam::{DAffine2, DVec2};
use serde::{Deserialize, Serialize};
use std::fmt::{self, Display, Write};
@ -410,7 +411,7 @@ impl PathStyle {
/// # Example
/// ```
/// # use graphite_document_legacy::layers::style::{Fill, PathStyle};
/// # use graphite_document_legacy::color::Color;
/// # use graphene_core::raster::color::Color;
/// let fill = Fill::solid(Color::RED);
/// let style = PathStyle::new(None, fill.clone());
///
@ -425,7 +426,7 @@ impl PathStyle {
/// # Example
/// ```
/// # use graphite_document_legacy::layers::style::{Fill, Stroke, PathStyle};
/// # use graphite_document_legacy::color::Color;
/// # use graphene_core::raster::color::Color;
/// let stroke = Stroke::new(Color::GREEN, 42.);
/// let style = PathStyle::new(Some(stroke.clone()), Fill::None);
///
@ -440,7 +441,7 @@ impl PathStyle {
/// # Example
/// ```
/// # use graphite_document_legacy::layers::style::{Fill, PathStyle};
/// # use graphite_document_legacy::color::Color;
/// # use graphene_core::raster::color::Color;
/// let mut style = PathStyle::default();
///
/// assert_eq!(*style.fill(), Fill::None);
@ -459,7 +460,7 @@ impl PathStyle {
/// # Example
/// ```
/// # use graphite_document_legacy::layers::style::{Stroke, PathStyle};
/// # use graphite_document_legacy::color::Color;
/// # use graphene_core::raster::color::Color;
/// let mut style = PathStyle::default();
///
/// assert_eq!(style.stroke(), None);
@ -478,7 +479,7 @@ impl PathStyle {
/// # Example
/// ```
/// # use graphite_document_legacy::layers::style::{Fill, PathStyle};
/// # use graphite_document_legacy::color::Color;
/// # use graphene_core::raster::color::Color;
/// let mut style = PathStyle::new(None, Fill::Solid(Color::RED));
///
/// assert!(style.fill().is_some());
@ -496,7 +497,7 @@ impl PathStyle {
/// # Example
/// ```
/// # use graphite_document_legacy::layers::style::{Fill, Stroke, PathStyle};
/// # use graphite_document_legacy::color::Color;
/// # use graphene_core::raster::color::Color;
/// let mut style = PathStyle::new(Some(Stroke::new(Color::GREEN, 42.)), Fill::None);
///
/// assert!(style.stroke().is_some());

View file

@ -3,8 +3,6 @@
extern crate log;
pub mod boolean_ops;
/// Contains the [Color](color::Color) type.
pub mod color;
/// Contains constant values used by this crate.
pub mod consts;
pub mod document;

View file

@ -1,4 +1,4 @@
use document_legacy::color::Color;
use graphene_core::raster::color::Color;
// Viewport
pub const VIEWPORT_ZOOM_WHEEL_RATE: f64 = (1. / 600.) * 3.;
@ -68,7 +68,7 @@ pub const ASYMPTOTIC_EFFECT: f64 = 0.5;
pub const SCALE_EFFECT: f64 = 0.5;
// Colors
pub const COLOR_ACCENT: Color = Color::from_uchecked(0x00 as f32 / 255., 0xA8 as f32 / 255., 0xFF as f32 / 255.);
pub const COLOR_ACCENT: Color = Color::from_rgbf32_unchecked(0x00 as f32 / 255., 0xA8 as f32 / 255., 0xFF as f32 / 255.);
// Fonts
pub const DEFAULT_FONT_FAMILY: &str = "Merriweather";

View file

@ -255,9 +255,9 @@ mod test {
use crate::messages::prelude::*;
use crate::test_utils::EditorTestUtils;
use document_legacy::color::Color;
use document_legacy::LayerId;
use document_legacy::Operation;
use graphene_core::raster::color::Color;
fn init_logger() {
let _ = env_logger::builder().is_test(true).try_init();

View file

@ -7,11 +7,11 @@ use crate::messages::portfolio::document::utility_types::layer_panel::{JsRawBuff
use crate::messages::prelude::*;
use crate::messages::tool::utility_types::HintData;
use document_legacy::color::Color;
use document_legacy::layers::text_layer::Font;
use document_legacy::LayerId;
use graph_craft::document::NodeId;
use graph_craft::imaginate_input::*;
use graphene_core::raster::color::Color;
use serde::{Deserialize, Serialize};

View file

@ -5,9 +5,9 @@ use crate::messages::layout::utility_types::layout_widget::{DiffUpdate, Widget};
use crate::messages::layout::utility_types::layout_widget::{Layout, WidgetLayout};
use crate::messages::prelude::*;
use document_legacy::color::Color;
use document_legacy::layers::text_layer::Font;
use document_legacy::LayerId;
use graphene_core::raster::color::Color;
use serde_json::Value;
use std::ops::Not;

View file

@ -1,9 +1,9 @@
use crate::messages::input_mapper::utility_types::misc::ActionKeys;
use crate::messages::layout::utility_types::layout_widget::WidgetCallback;
use document_legacy::color::Color;
use document_legacy::layers::layer_info::LayerDataTypeDiscriminant;
use document_legacy::LayerId;
use graphene_core::raster::color::Color;
use graphite_proc_macros::WidgetBuilder;
use derivative::*;

View file

@ -2,12 +2,12 @@ use crate::application::generate_uuid;
use crate::messages::portfolio::utility_types::PersistentData;
use crate::messages::prelude::*;
use document_legacy::color::Color;
use document_legacy::document::Document as DocumentLegacy;
use document_legacy::layers::style::{self, Fill, RenderData, ViewMode};
use document_legacy::DocumentResponse;
use document_legacy::LayerId;
use document_legacy::Operation as DocumentOperation;
use graphene_core::raster::color::Color;
use glam::DAffine2;
use serde::{Deserialize, Serialize};

View file

@ -23,7 +23,6 @@ use crate::messages::prelude::*;
use crate::messages::tool::utility_types::ToolType;
use document_legacy::boolean_ops::BooleanOperationError;
use document_legacy::color::Color;
use document_legacy::document::Document as DocumentLegacy;
use document_legacy::layers::blend_mode::BlendMode;
use document_legacy::layers::folder_layer::FolderLayer;
@ -32,6 +31,7 @@ use document_legacy::layers::style::{Fill, RenderData, ViewMode};
use document_legacy::layers::text_layer::Font;
use document_legacy::{DocumentError, DocumentResponse, LayerId, Operation as DocumentOperation};
use graph_craft::document::NodeId;
use graphene_core::raster::color::Color;
use graphene_std::vector::subpath::Subpath;
use glam::{DAffine2, DVec2};

View file

@ -9,11 +9,11 @@ use crate::messages::layout::utility_types::widgets::label_widgets::{IconLabel,
use crate::messages::portfolio::utility_types::PersistentData;
use crate::messages::prelude::*;
use document_legacy::color::Color;
use document_legacy::document::Document;
use document_legacy::layers::layer_info::{Layer, LayerDataType, LayerDataTypeDiscriminant};
use document_legacy::layers::style::{Fill, Gradient, GradientType, LineCap, LineJoin, RenderData, Stroke, ViewMode};
use document_legacy::layers::text_layer::TextLayer;
use graphene_core::raster::color::Color;
use glam::{DAffine2, DVec2};
use std::f64::consts::PI;

View file

@ -1,5 +1,5 @@
use document_legacy::color::Color;
use document_legacy::DocumentError;
use graphene_core::raster::color::Color;
use thiserror::Error;

View file

@ -1,9 +1,9 @@
pub use super::layer_panel::{LayerMetadata, LayerPanelEntry};
use crate::messages::prelude::ArtboardMessageHandler;
use document_legacy::color::Color;
use document_legacy::document::Document as DocumentLegacy;
use document_legacy::LayerId;
use graphene_core::raster::color::Color;
use serde::{Deserialize, Serialize};
use std::collections::HashMap;

View file

@ -838,7 +838,7 @@ impl PortfolioMessageHandler {
let old_transforms = document.remove_document_transform();
let mask_is_some = mask_path.is_some();
let mask_image = mask_path.filter(|mask_layer_path| document.document_legacy.layer(mask_layer_path).is_ok()).map(|mask_layer_path| {
let render_mode = DocumentRenderMode::LayerCutout(&mask_layer_path, document_legacy::color::Color::WHITE);
let render_mode = DocumentRenderMode::LayerCutout(&mask_layer_path, graphene_core::raster::color::Color::WHITE);
let svg = document.render_document(size, transform.inverse(), &self.persistent_data, render_mode);
ImaginateMaskImage { svg, size }

View file

@ -3,10 +3,10 @@ use crate::consts::VIEWPORT_GRID_ROUNDING_BIAS;
use crate::consts::{COLOR_ACCENT, HIDE_HANDLE_DISTANCE, MANIPULATOR_GROUP_MARKER_SIZE, PATH_OUTLINE_WEIGHT};
use crate::messages::prelude::*;
use document_legacy::color::Color;
use document_legacy::document::Document;
use document_legacy::layers::style::{self, Fill, Stroke};
use document_legacy::{LayerId, Operation};
use graphene_core::raster::color::Color;
use graphene_std::vector::consts::ManipulatorType;
use graphene_std::vector::manipulator_group::ManipulatorGroup;
use graphene_std::vector::manipulator_point::ManipulatorPoint;

View file

@ -114,7 +114,7 @@ impl Pivot {
transform: DAffine2::IDENTITY.to_cols_array(),
style: style::PathStyle::new(
Some(style::Stroke::new(COLOR_ACCENT, PIVOT_OUTER_OUTLINE_THICKNESS)),
style::Fill::Solid(document_legacy::color::Color::WHITE),
style::Fill::Solid(graphene_core::raster::color::Color::WHITE),
),
insert_index: -1,
}

View file

@ -4,10 +4,10 @@ use crate::messages::frontend::utility_types::MouseCursorIcon;
use crate::messages::portfolio::document::utility_types::transformation::OriginalTransforms;
use crate::messages::prelude::*;
use document_legacy::color::Color;
use document_legacy::layers::style::{self, Fill, Stroke};
use document_legacy::LayerId;
use document_legacy::Operation;
use graphene_core::raster::color::Color;
use glam::{DAffine2, DVec2};

View file

@ -1,7 +1,7 @@
use super::utility_types::ToolType;
use crate::messages::prelude::*;
use document_legacy::color::Color;
use graphene_core::raster::color::Color;
use serde::{Deserialize, Serialize};

View file

@ -6,8 +6,8 @@ use crate::messages::portfolio::utility_types::PersistentData;
use crate::messages::prelude::*;
use crate::messages::tool::utility_types::ToolType;
use document_legacy::color::Color;
use document_legacy::layers::style::RenderData;
use graphene_core::raster::color::Color;
#[derive(Debug, Default)]
pub struct ToolMessageHandler {

View file

@ -9,12 +9,12 @@ use crate::messages::tool::common_functionality::snapping::SnapManager;
use crate::messages::tool::utility_types::{EventToMessageMap, Fsm, ToolActionHandlerData, ToolMetadata, ToolTransition, ToolType};
use crate::messages::tool::utility_types::{HintData, HintGroup, HintInfo};
use document_legacy::color::Color;
use document_legacy::intersection::Quad;
use document_legacy::layers::layer_info::Layer;
use document_legacy::layers::style::{Fill, Gradient, GradientType, PathStyle, RenderData, Stroke};
use document_legacy::LayerId;
use document_legacy::Operation;
use graphene_core::raster::color::Color;
use glam::{DAffine2, DVec2};
use serde::{Deserialize, Serialize};

View file

@ -9,8 +9,8 @@ use crate::messages::layout::utility_types::widgets::input_widgets::SwatchPairIn
use crate::messages::layout::utility_types::widgets::label_widgets::{Separator, SeparatorDirection, SeparatorType};
use crate::messages::prelude::*;
use document_legacy::color::Color;
use document_legacy::layers::style::RenderData;
use graphene_core::raster::color::Color;
use serde::{Deserialize, Serialize};
use std::fmt::{self, Debug};

View file

@ -6,7 +6,7 @@ use crate::messages::portfolio::utility_types::Platform;
use crate::messages::prelude::*;
use crate::messages::tool::utility_types::ToolType;
use document_legacy::color::Color;
use graphene_core::raster::color::Color;
/// A set of utility functions to make the writing of editor test more declarative
pub trait EditorTestUtils {

View file

@ -5,7 +5,6 @@
use crate::helpers::{translate_key, Error};
use crate::{EDITOR_HAS_CRASHED, EDITOR_INSTANCES, JS_EDITOR_HANDLES};
use document_legacy::color::Color;
use document_legacy::LayerId;
use editor::application::generate_uuid;
use editor::application::Editor;
@ -15,6 +14,7 @@ use editor::messages::input_mapper::utility_types::input_mouse::{EditorMouseStat
use editor::messages::portfolio::utility_types::{ImaginateServerStatus, Platform};
use editor::messages::prelude::*;
use graph_craft::document::NodeId;
use graphene_core::raster::color::Color;
use serde::Serialize;
use serde_wasm_bindgen::{self, from_value};

View file

@ -5,7 +5,6 @@
use crate::helpers::{translate_key, Error};
use crate::{EDITOR_HAS_CRASHED, EDITOR_INSTANCES, JS_EDITOR_HANDLES};
use document_legacy::color::Color;
use document_legacy::LayerId;
use editor::application::generate_uuid;
use editor::application::Editor;
@ -15,6 +14,7 @@ use editor::messages::input_mapper::utility_types::input_mouse::{EditorMouseStat
use editor::messages::portfolio::utility_types::{ImaginateServerStatus, Platform};
use editor::messages::prelude::*;
use graph_craft::document::NodeId;
use graphene_core::raster::color::Color;
use serde::Serialize;
use serde_wasm_bindgen::{self, from_value};

View file

@ -44,6 +44,12 @@ impl Color {
pub const RED: Color = Color::from_rgbf32_unchecked(1., 0., 0.);
pub const GREEN: Color = Color::from_rgbf32_unchecked(0., 1., 0.);
pub const BLUE: Color = Color::from_rgbf32_unchecked(0., 0., 1.);
pub const TRANSPARENT: Color = Self {
red: 0.,
green: 0.,
blue: 0.,
alpha: 0.,
};
/// Returns `Some(Color)` if `red`, `green`, `blue` and `alpha` have a valid value. Negative numbers (including `-0.0`), NaN, and infinity are not valid values and return `None`.
/// Alpha values greater than `1.0` are not valid.
@ -67,13 +73,13 @@ impl Color {
}
/// Return an opaque `Color` from given `f32` RGB channels.
pub const fn from_rgbaf32_unchecked(red: f32, green: f32, blue: f32, alpha: f32) -> Color {
Color { red, green, blue, alpha }
pub const fn from_rgbf32_unchecked(red: f32, green: f32, blue: f32) -> Color {
Color { red, green, blue, alpha: 1. }
}
/// Return an opaque `Color` from given `f32` RGB channels.
pub const fn from_rgbf32_unchecked(red: f32, green: f32, blue: f32) -> Color {
Color { red, green, blue, alpha: 1. }
pub const fn from_rgbaf32_unchecked(red: f32, green: f32, blue: f32, alpha: f32) -> Color {
Color { red, green, blue, alpha }
}
/// Return an opaque SDR `Color` given RGB channels from `0` to `255`.
@ -202,6 +208,34 @@ impl Color {
(self.red, self.green, self.blue, self.alpha)
}
/// Return an 8-character RGBA hex string (without a # prefix).
///
/// # Examples
/// ```
/// use graphene_core::raster::color::Color;
/// let color = Color::from_rgba8(0x7C, 0x67, 0xFA, 0x61);
/// assert!("7C67FA61" == color.rgba_hex())
/// ```
pub fn rgba_hex(&self) -> String {
format!(
"{:02X?}{:02X?}{:02X?}{:02X?}",
(self.r() * 255.) as u8,
(self.g() * 255.) as u8,
(self.b() * 255.) as u8,
(self.a() * 255.) as u8,
)
}
/// Return a 6-character RGB hex string (without a # prefix).
/// ```
/// use graphene_core::raster::color::Color;
/// let color = Color::from_rgba8(0x7C, 0x67, 0xFA, 0x61);
/// assert!("7C67FA" == color.rgb_hex())
/// ```
pub fn rgb_hex(&self) -> String {
format!("{:02X?}{:02X?}{:02X?}", (self.r() * 255.) as u8, (self.g() * 255.) as u8, (self.b() * 255.) as u8,)
}
/// Return the all components as a u8 slice, first component is red, followed by green, followed by blue, followed by alpha.
///
/// # Examples
@ -287,6 +321,19 @@ impl Color {
Some(Color::from_rgb8(r, g, b))
}
/// Linearly interpolates between two colors based on t.
///
/// T must be between 0 and 1.
pub fn lerp(self, other: Color, t: f32) -> Option<Self> {
assert!((0. ..=1.).contains(&t));
Color::from_rgbaf32(
self.red + ((other.red - self.red) * t),
self.green + ((other.green - self.green) * t),
self.blue + ((other.blue - self.blue) * t),
self.alpha + ((other.alpha - self.alpha) * t),
)
}
}
#[test]