blob: 0fadda981d7021e8d09a02720283dc7cb343f518 [file] [log] [blame]
// Copyright 2020 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
use anyhow::Error;
use fidl_fuchsia_ui_gfx::ColorRgba;
fn srgb_to_linear(l: u8) -> f32 {
let l = l as f32 * 255.0f32.recip();
if l <= 0.04045 {
l * 12.92f32.recip()
} else {
((l + 0.055) * 1.055f32.recip()).powf(2.4)
}
}
/// Struct representing an RGBA color value in un-premultiplied non-linear sRGB space
#[derive(Hash, Eq, PartialEq, Debug, Clone, Copy)]
pub struct Color {
/// Red
pub r: u8,
/// Green
pub g: u8,
/// Blue
pub b: u8,
/// Alpha
pub a: u8,
}
impl Color {
/// Create a new color set to black with full alpha
pub const fn new() -> Color {
Color { r: 0, g: 0, b: 0, a: 255 }
}
/// Create a new color set to white with full alpha
pub const fn white() -> Color {
Color { r: 255, g: 255, b: 255, a: 255 }
}
/// Create a new color set to red with full alpha
pub const fn red() -> Color {
Color { r: 255, g: 0, b: 0, a: 255 }
}
/// Create a new color set to green with full alpha
pub const fn green() -> Color {
Color { r: 0, g: 255, b: 0, a: 255 }
}
/// Create a new color set to blue with full alpha
pub const fn blue() -> Color {
Color { r: 0, g: 0, b: 255, a: 255 }
}
/// Create a new color set to Fuchsia with full alpha
pub const fn fuchsia() -> Color {
Color { r: 255, g: 0, b: 255, a: 255 }
}
fn extract_hex_slice(hash_code: &str, start_index: usize) -> Result<u8, Error> {
Ok(u8::from_str_radix(&hash_code[start_index..start_index + 2], 16)?)
}
/// Create a color from a six hexadecimal digit string like '#EBD5B3'
pub fn from_hash_code(hash_code: &str) -> Result<Color, Error> {
let mut new_color = Color::new();
new_color.r = Color::extract_hex_slice(&hash_code, 1)?;
new_color.g = Color::extract_hex_slice(&hash_code, 3)?;
new_color.b = Color::extract_hex_slice(&hash_code, 5)?;
Ok(new_color)
}
/// Create a Scenic-compatible [`ColorRgba`]
pub fn make_color_rgba(&self) -> ColorRgba {
ColorRgba { red: self.r, green: self.g, blue: self.b, alpha: self.a }
}
pub fn to_linear_premult_rgba(&self) -> [f32; 4] {
let alpha = self.a as f32 * 255.0f32.recip();
[
srgb_to_linear(self.r) * alpha,
srgb_to_linear(self.g) * alpha,
srgb_to_linear(self.b) * alpha,
alpha,
]
}
pub fn to_linear_bgra(&self) -> [f32; 4] {
[
srgb_to_linear(self.b),
srgb_to_linear(self.g),
srgb_to_linear(self.r),
self.a as f32 * 255.0f32.recip(),
]
}
pub fn to_srgb_premult_rgba(&self) -> [f32; 4] {
let recip = 255.0f32.recip();
let alpha = self.a as f32 * recip;
[
self.r as f32 * recip * alpha,
self.g as f32 * recip * alpha,
self.b as f32 * recip * alpha,
alpha,
]
}
}
impl Default for Color {
fn default() -> Self {
Color::new()
}
}