98 lines
2.5 KiB
Rust
98 lines
2.5 KiB
Rust
// Copyright 2020 Sergiusz 'q3k' Bazanski <q3k@q3k.org>
|
|
//
|
|
// This file is part of Abrasion.
|
|
//
|
|
// Abrasion is free software: you can redistribute it and/or modify it under
|
|
// the terms of the GNU General Public License as published by the Free
|
|
// Software Foundation, version 3.
|
|
//
|
|
// Abrasion is distributed in the hope that it will be useful, but WITHOUT ANY
|
|
// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
|
// FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
|
// details.
|
|
//
|
|
// You should have received a copy of the GNU General Public License along with
|
|
// Abrasion. If not, see <https://www.gnu.org/licenses/>.
|
|
|
|
#[derive(Copy, Clone, Debug)]
|
|
pub struct XYZ {
|
|
pub x: f32,
|
|
pub y: f32,
|
|
pub z: f32,
|
|
}
|
|
|
|
impl XYZ {
|
|
pub fn new(x: f32, y: f32, z: f32) -> Self {
|
|
Self {
|
|
x, y, z,
|
|
}
|
|
}
|
|
pub fn from_srgb(r: f32, g: f32, b: f32) -> Self {
|
|
let (x, y, z) = srgb_to_cie_xyz(r, g, b);
|
|
Self {
|
|
x, y, z
|
|
}
|
|
}
|
|
}
|
|
|
|
#[derive(Debug)]
|
|
pub struct LinearF32 {
|
|
pub d: f32,
|
|
}
|
|
|
|
impl LinearF32 {
|
|
pub fn new(d: f32) -> Self {
|
|
Self {
|
|
d,
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Convert sRGB color space (in R8G8B8A8) to XYZ colorspace (floats).
|
|
pub fn srgb_packed_to_cie_xyz(rgba: u32) -> (f32, f32, f32, f32) {
|
|
// Unpack RGBA to R, G, B, A 0-255 values.
|
|
let r = ((rgba >> 24) & 0xff) as f32;
|
|
let g = ((rgba >> 16) & 0xff) as f32;
|
|
let b = ((rgba >> 8 ) & 0xff) as f32;
|
|
let a = ((rgba ) & 0xff) as f32;
|
|
|
|
let r = r/255.0;
|
|
let g = g/255.0;
|
|
let b = b/255.0;
|
|
|
|
let (x, y, z) = srgb_to_cie_xyz(r, g, b);
|
|
(x, y, z, a)
|
|
}
|
|
|
|
/// Convert sRGB color space (floats) to XYZ colorspace (floats).
|
|
/// The input are floats in the range 0-1.0.
|
|
/// The output is a tuple of (X, Y, Z) floats.
|
|
pub fn srgb_to_cie_xyz(r: f32, g: f32, b: f32) -> (f32, f32, f32) {
|
|
assert!(r >= 0.0 && r <= 1.0);
|
|
assert!(g >= 0.0 && g <= 1.0);
|
|
assert!(b >= 0.0 && b <= 1.0);
|
|
|
|
// Following DIN EN 61966-2-1:2003-09
|
|
// (which corresponds to IEC 61966-2-1:1999)
|
|
// Equations (5) and (6)
|
|
let eq56 = |v| {
|
|
if v < 0.004045 {
|
|
v / 12.92
|
|
} else {
|
|
let v: f32 = (v + 0.055) / (1.055);
|
|
v.powf(2.4) as f32
|
|
}
|
|
};
|
|
let r = eq56(r);
|
|
let g = eq56(g);
|
|
let b = eq56(b);
|
|
|
|
// Equation (7)
|
|
// (unrolled matrix multiplication)
|
|
let x = 0.4124 * r + 0.3576 * g + 0.1805 * b;
|
|
let y = 0.2126 * r + 0.7152 * g + 0.0722 * b;
|
|
let z = 0.0193 * r + 0.1192 * g + 0.9505 * b;
|
|
|
|
(x, y , z)
|
|
}
|