ezk-image 0.4.3

Convert pixel and color formats such and RGB, YUV (YCbCr), ICtCp
Documentation
use crate::formats::rgb::{RgbaPixel, RgbaSrc, SWIZZLE_BGRA, SWIZZLE_RGBA};
use crate::formats::visit_2x2::{Image2x2Visitor, visit};
use crate::planes::read_planes_mut;
use crate::primitive::Primitive;
use crate::vector::Vector;
use crate::{ConvertError, ImageMut, ImageRefExt};
use std::marker::PhantomData;

pub(crate) struct WriteRgb<'a, const SWIZZLE: u8, P, S>
where
    P: Primitive,
    S: RgbaSrc,
{
    rgb: &'a mut [u8],

    rgb_stride: usize,

    max_value: f32,

    rgba_src: S,

    _m: PhantomData<&'a mut [P]>,
}

impl<'a, const SWIZZLE: u8, P, S> WriteRgb<'a, SWIZZLE, P, S>
where
    P: Primitive,
    S: RgbaSrc,
{
    pub(crate) fn write(dst: &'a mut dyn ImageMut, rgba_src: S) -> Result<(), ConvertError> {
        dst.bounds_check()?;

        let dst_width = dst.width();
        let dst_height = dst.height();
        let dst_format = dst.format();

        let [(rgb, rgb_stride)] = read_planes_mut(dst.planes_mut())?;

        visit(
            dst_width,
            dst_height,
            Self {
                rgb,
                rgb_stride,
                max_value: crate::formats::max_value_for_bits(dst_format.bits_per_component()),
                rgba_src,
                _m: PhantomData,
            },
        );

        Ok(())
    }
}

impl<const SWIZZLE: u8, P, S> Image2x2Visitor for WriteRgb<'_, SWIZZLE, P, S>
where
    P: Primitive,
    S: RgbaSrc,
{
    #[inline(always)]
    unsafe fn visit<V: Vector>(&mut self, x: usize, y: usize) {
        let block = self.rgba_src.read::<V>(x, y);

        let offset00 = y * self.rgb_stride + x * 3 * P::SIZE;
        let offset10 = (y + 1) * self.rgb_stride + x * 3 * P::SIZE;

        P::write_interleaved_3x_2x(
            &mut self.rgb[offset00..],
            [
                multiply_and_reverse::<SWIZZLE, V>(block.px00, self.max_value),
                multiply_and_reverse::<SWIZZLE, V>(block.px01, self.max_value),
            ],
        );

        P::write_interleaved_3x_2x(
            &mut self.rgb[offset10..],
            [
                multiply_and_reverse::<SWIZZLE, V>(block.px10, self.max_value),
                multiply_and_reverse::<SWIZZLE, V>(block.px11, self.max_value),
            ],
        );
    }
}

#[inline(always)]
unsafe fn multiply_and_reverse<const SWIZZLE: u8, V: Vector>(
    px: RgbaPixel<V>,
    max_value: f32,
) -> [V; 3] {
    let r = px.r.vmulf(max_value);
    let g = px.g.vmulf(max_value);
    let b = px.b.vmulf(max_value);

    match SWIZZLE {
        SWIZZLE_RGBA => [r, g, b],
        SWIZZLE_BGRA => [b, g, r],
        _ => unreachable!("unknown swizzle {SWIZZLE}"),
    }
}