ezk-image 0.4.3

Convert pixel and color formats such and RGB, YUV (YCbCr), ICtCp
Documentation
use super::rgb::{RgbaBlock, RgbaSrc};
use crate::ColorTransfer;
use crate::color::ColorInfo;
use crate::color::primaries::{rgb_to_xyz, xyz_to_rgb};
use crate::vector::Vector;

pub(crate) struct TransferAndPrimariesConvert<S> {
    rgb_to_xyz: &'static [[f32; 3]; 3],
    xyz_to_rgb: &'static [[f32; 3]; 3],

    src_transfer: ColorTransfer,
    dst_transfer: ColorTransfer,

    src: S,
}

pub(crate) fn need_transfer_and_primaries_convert(
    src_color: &ColorInfo,
    dst_color: &ColorInfo,
) -> bool {
    src_color.transfer() != dst_color.transfer() || src_color.primaries() != dst_color.primaries()
}

impl<S> TransferAndPrimariesConvert<S> {
    pub(crate) fn new(src_color: &ColorInfo, dst_color: &ColorInfo, src: S) -> Self {
        Self {
            rgb_to_xyz: src_color.primaries().rgb_to_xyz_mat(),
            xyz_to_rgb: dst_color.primaries().xyz_to_rgb_mat(),
            src_transfer: src_color.transfer(),
            dst_transfer: dst_color.transfer(),
            src,
        }
    }
}

impl<S: RgbaSrc> RgbaSrc for TransferAndPrimariesConvert<S> {
    #[inline(always)]
    unsafe fn read<V: Vector>(&mut self, x: usize, y: usize) -> RgbaBlock<V> {
        let mut block = self.src.read(x, y);

        let mut i = [
            &mut block.px00.r,
            &mut block.px00.g,
            &mut block.px00.b,
            &mut block.px01.r,
            &mut block.px01.g,
            &mut block.px01.b,
            &mut block.px10.r,
            &mut block.px10.g,
            &mut block.px10.b,
            &mut block.px11.r,
            &mut block.px11.g,
            &mut block.px11.b,
        ];

        self.src_transfer.scaled_to_linear_v(&mut i);

        let mut iter = i.chunks_exact_mut(3);

        while let Some([r, g, b]) = iter.next() {
            let [x, y, z] = rgb_to_xyz(self.rgb_to_xyz, **r, **g, **b);

            let [r_, g_, b_] = xyz_to_rgb(self.xyz_to_rgb, x, y, z);

            **r = r_;
            **g = g_;
            **b = b_;
        }

        self.dst_transfer.linear_to_scaled_v(&mut i);

        block
    }
}