use crate::opbasics::*;
use crate::color_conversions::*;
#[derive(Copy, Clone, Debug, Serialize, Deserialize)]
pub struct OpToLab {
pub cam_to_xyz: [[f32;4];3],
pub cam_to_xyz_normalized: [[f32;4];3],
pub xyz_to_cam: [[f32;3];4],
pub wb_coeffs: [f32;4],
}
fn normalize_wbs(vals: [f32;4]) -> [f32;4] {
let unity: f32 = vals[1];
macro_rules! norm {
($val:expr) => {
if !$val.is_normal() {
1.0
} else {
$val / unity
}
};
}
[norm!(vals[0]), norm!(vals[1]), norm!(vals[2]), norm!(vals[3])]
}
impl OpToLab {
pub fn new(img: &ImageSource) -> OpToLab {
match img {
ImageSource::Raw(img) => {
let coeffs = if !img.wb_coeffs[0].is_normal() ||
!img.wb_coeffs[1].is_normal() ||
!img.wb_coeffs[2].is_normal() {
normalize_wbs(img.neutralwb())
} else {
normalize_wbs(img.wb_coeffs)
};
OpToLab{
cam_to_xyz: img.cam_to_xyz(),
cam_to_xyz_normalized: img.cam_to_xyz_normalized(),
xyz_to_cam: img.xyz_to_cam,
wb_coeffs: coeffs,
}
},
ImageSource::Other(_) => {
OpToLab{
cam_to_xyz: *SRGB_D65_43,
cam_to_xyz_normalized: *SRGB_D65_43,
xyz_to_cam: *XYZ_D65_34,
wb_coeffs: [1.0, 1.0, 1.0, 0.0],
}
}
}
}
pub fn set_temp(&mut self, temp: f32, tint: f32) {
let xyz = temp_to_xyz(temp);
let xyz = [xyz[0], xyz[1]/tint, xyz[2]];
for i in 0..4 {
self.wb_coeffs[i] = 0.0;
for j in 0..3 {
self.wb_coeffs[i] += self.xyz_to_cam[i][j] * xyz[j];
}
self.wb_coeffs[i] = self.wb_coeffs[i].recip();
}
self.wb_coeffs = normalize_wbs(self.wb_coeffs);
}
pub fn get_temp(&self) -> (f32, f32) {
let mut xyz = [0.0; 3];
for i in 0..3 {
for j in 0..4 {
let mul = self.wb_coeffs[j];
if mul > 0.0 {
xyz[i] += self.cam_to_xyz[i][j] / mul;
}
}
}
let (temp, tint) = xyz_to_temp(xyz);
(temp, tint)
}
}
impl<'a> ImageOp<'a> for OpToLab {
fn name(&self) -> &str {"to_lab"}
fn run(&self, _pipeline: &PipelineGlobals, buf: Arc<OpBuffer>) -> Arc<OpBuffer> {
let cmatrix = if buf.monochrome {
*SRGB_D65_43
} else {
self.cam_to_xyz_normalized
};
let mul = if buf.monochrome {
[1.0, 1.0, 1.0, 1.0]
} else {
normalize_wbs(self.wb_coeffs)
};
Arc::new(buf.process_into_new(3, &(|outb: &mut [f32], inb: &[f32]| {
for (pixin, pixout) in inb.chunks_exact(4).zip(outb.chunks_exact_mut(3)) {
let (l,a,b) = camera_to_lab(mul, cmatrix, pixin);
pixout[0] = l;
pixout[1] = a;
pixout[2] = b;
}
})))
}
}
#[derive(Copy, Clone, Debug, Serialize, Deserialize)]
pub struct OpFromLab {
}
impl OpFromLab {
pub fn new(_img: &ImageSource) -> OpFromLab {
OpFromLab{}
}
}
impl<'a> ImageOp<'a> for OpFromLab {
fn name(&self) -> &str {"from_lab"}
fn run(&self, _pipeline: &PipelineGlobals, buf: Arc<OpBuffer>) -> Arc<OpBuffer> {
Arc::new(buf.mutate_lines_copying(&(|line: &mut [f32], _| {
for pix in line.chunks_exact_mut(3) {
let (r,g,b) = lab_to_rgb(*XYZ_D65_33, pix);
pix[0] = r;
pix[1] = g;
pix[2] = b;
}
})))
}
}