use crate::color_matrix::RowMatrix;
use super::{Differencing, Transfer};
trait DigitalDifferencing {
const DIFF: RowMatrix;
}
trait DifferencingAction<R = ()> {
fn digital<D: DigitalDifferencing>(self) -> R;
fn quantized<D: DigitalDifferencing>(self) -> R;
}
pub fn from_rgb_slice(rgb: &mut [[f32; 4]], transfer: Transfer, differencing: Differencing) {
struct EncodeAction<'data>(&'data mut [[f32; 4]]);
impl DifferencingAction for EncodeAction<'_> {
fn digital<D: DigitalDifferencing>(self) {
from_slice_digital::<D>(self.0)
}
fn quantized<D: DigitalDifferencing>(self) {
}
}
if let Some(oe_transfer) = transfer.from_optical_display_slice() {
oe_transfer(rgb);
} else {
for rgb in rgb.iter_mut() {
*rgb = transfer.from_optical_display(*rgb);
}
}
differencing.action(EncodeAction(rgb));
}
pub fn to_rgb_slice(rgb: &mut [[f32; 4]], transfer: Transfer, differencing: Differencing) {
struct EncodeAction<'data>(&'data mut [[f32; 4]]);
impl DifferencingAction for EncodeAction<'_> {
fn digital<D: DigitalDifferencing>(self) {
to_slice_digital::<D>(self.0)
}
fn quantized<D: DigitalDifferencing>(self) {
}
}
differencing.action(EncodeAction(rgb));
if let Some(eo_transfer) = transfer.to_optical_display_slice_inplace() {
eo_transfer(rgb);
} else {
for rgb in rgb.iter_mut() {
*rgb = transfer.to_optical_display(*rgb);
}
}
}
fn from_slice_digital<T: DigitalDifferencing>(pix: &mut [[f32; 4]]) {
let diff = T::DIFF;
for pix in pix {
let [r, g, b, a] = *pix;
let [y, u, v] = diff.mul_vec([r, g, b]);
*pix = [y, u, v, a];
}
}
fn to_slice_digital<T: DigitalDifferencing>(rgb: &mut [[f32; 4]]) {
let diff = T::DIFF.inv();
for pix in rgb {
let [r, g, b, a] = *pix;
let [y, u, v] = diff.mul_vec([r, g, b]);
*pix = [y, u, v, a];
}
}
impl Differencing {
fn action<R>(self, act: impl DifferencingAction<R>) -> R {
match self {
Differencing::Bt407MPal => act.digital::<Bt407MPal>(),
Differencing::Bt407MPalPrecise => act.digital::<Bt407MPalPrecise>(),
Differencing::Bt601 => act.digital::<Bt601>(),
Differencing::Bt601Quantized => act.quantized::<Bt601Quantized>(),
Differencing::Bt601FullSwing => act.quantized::<Bt601FullSwing>(),
Differencing::Bt709 => act.digital::<Bt709>(),
Differencing::Bt709Quantized => act.quantized::<Bt709Quantized>(),
Differencing::Bt709FullSwing => act.quantized::<Bt709FullSwing>(),
Differencing::YDbDr => act.digital::<YDbDr>(),
Differencing::Bt2020 => act.digital::<Bt2020>(),
Differencing::Bt2100 => act.digital::<Bt2100>(),
Differencing::YCoCg => act.digital::<YCoCg>(),
}
}
}
struct Bt407MPal;
struct Bt407MPalPrecise;
struct Pal525;
struct Pal625;
struct Bt601;
struct Bt601Quantized;
struct Bt601FullSwing;
struct Bt709;
struct Bt709Quantized;
struct Bt709FullSwing;
struct Bt2020;
struct Bt2100;
struct YDbDr;
struct YCoCg;
struct YCoCgR;
const UDIV: f32 = 0.886 / 0.436; const VDIV: f32 = 0.701 / 0.615;
impl DigitalDifferencing for Bt407MPalPrecise {
#[rustfmt::skip]
const DIFF: RowMatrix = RowMatrix([
0.299, 0.587, 0.114,
-0.299/UDIV, -0.587/UDIV, 0.886/UDIV,
0.701/VDIV, -0.587/VDIV, -0.114/VDIV,
]);
}
impl DigitalDifferencing for Bt407MPal {
const DIFF: RowMatrix = <Pal525 as DigitalDifferencing>::DIFF;
}
impl DigitalDifferencing for Pal525 {
#[rustfmt::skip]
const DIFF: RowMatrix = RowMatrix([
0.299, 0.587, 0.114,
-0.299*0.493, -0.587*0.943, 0.866*0.493,
0.701*0.877, -0.587*0.877, -0.114*0.877,
]);
}
impl DigitalDifferencing for Pal625 {
const DIFF: RowMatrix = <Pal525 as DigitalDifferencing>::DIFF;
}
impl DigitalDifferencing for Bt601 {
#[rustfmt::skip]
const DIFF: RowMatrix = RowMatrix([
0.299, 0.587, 0.114,
0.701/1.402, -0.587/1.402, -0.114/1.402,
-0.299/1.772, -0.587/1.722, 0.866/1.722,
]);
}
impl DigitalDifferencing for Bt601Quantized {
#[rustfmt::skip]
const DIFF: RowMatrix = panic!();
}
impl DigitalDifferencing for Bt601FullSwing {
#[rustfmt::skip]
const DIFF: RowMatrix = panic!();
}
impl DigitalDifferencing for Bt709 {
#[rustfmt::skip]
const DIFF: RowMatrix = RowMatrix([
0.2126, 0.7152, 0.0722,
-0.2126/1.8556, -0.7152/1.8556, 0.9278/1.8556,
0.7874/1.5748, -0.7152/1.5748, -0.0722/1.5748,
]);
}
impl DigitalDifferencing for Bt709Quantized {
#[rustfmt::skip]
const DIFF: RowMatrix = panic!();
}
impl DigitalDifferencing for Bt709FullSwing {
#[rustfmt::skip]
const DIFF: RowMatrix = panic!();
}
impl DigitalDifferencing for YDbDr {
#[rustfmt::skip]
const DIFF: RowMatrix = RowMatrix([
0.299, 0.587, 0.114,
-0.299*1.505, -0.587*1.505, 0.886*1.505,
-0.701*-1.902, -0.587*-1.902, -0.114*-1.902,
]);
}
impl DigitalDifferencing for YCoCg {
#[rustfmt::skip]
const DIFF: RowMatrix = RowMatrix([
0.25, 0.5, 0.25,
0.5, 0.0, -0.5,
-0.25, 0.5, -0.25,
]);
}
impl DigitalDifferencing for YCoCgR {
#[rustfmt::skip]
const DIFF: RowMatrix = RowMatrix([
0.25, 0.5, 0.25,
1.0, 0.0, -1.0,
-0.5, 1.0, -0.5,
]);
}
impl DigitalDifferencing for Bt2020 {
#[rustfmt::skip]
const DIFF: RowMatrix = RowMatrix([
0.2627, 0.6780, 0.0593,
-0.2627/1.8814, -0.6780/1.8814, 0.9407/1.8814,
0.7373/1.4746, -0.6780/1.4746, -0.0593/1.4746,
]);
}
impl DigitalDifferencing for Bt2100 {
const DIFF: RowMatrix = <Bt2020 as DigitalDifferencing>::DIFF;
}