Blending colors source -> destination

I have a homewritten bitmap using a Vec + width + height.
For blending bitmap1 to bitmap2 I use the per pixel blend routine down here.

Any remarks on the algorithm and tips / tricks for performance?

pub struct Rgba(pub u32);

impl Rgba
{
    #[inline]
    pub const fn transmute_to_rgba_bytes(self) -> RgbaBytes
    {
        unsafe { transmute(self) }
    }

    #[inline]
    pub fn transmute_to_rgba_bytes_mut(&mut self) -> &mut RgbaBytes
    {
        unsafe { transmute(self) }
    }
}

#[repr(C)]
#[derive(Default, Clone, Copy, PartialEq, Eq, Hash, Debug)]
pub struct RgbaBytes
{
    pub b: u8,
    pub g: u8,
    pub r: u8,
    pub a: u8,
}

#[inline]
pub fn blend(rgba_src: Rgba, rgba_dst: &mut Rgba)
{
		let src = rgba_src.transmute_to_rgba_bytes();
		let dst = rgba_dst.transmute_to_rgba_bytes_mut();

		let src_a = src.a as u32;
		let dst_a = dst.a as u32;

		dst.b = ((src.b as u32 * src_a + dst.b as u32 * (255 - src_a)) / 255) as u8;
		dst.g = ((src.g as u32 * src_a + dst.g as u32 * (255 - src_a)) / 255) as u8;
		dst.r = ((src.r as u32 * src_a + dst.r as u32 * (255 - src_a)) / 255) as u8;
		dst.a = (src_a + dst_a * (255 - src_a) / 255) as u8;
}
    #[inline]
    pub fn transmute_to_rgba_bytes_mut(&mut self) -> &mut RgbaBytes
    {
        unsafe { transmute(self) }
    }

It's a bad idea to convert pointers using transmute. The preferred implementation of this function would be

unsafe { &mut *(self as *mut _).cast() }
1 Like

I have difficulties reading that. What is *mut _ ?
.cast() does type-inference to the function result?
And I thought transmute was compiler checked in this case.

Use

for such conversions. Or even use

which already has the RGBA struct and safe traits for transmuting.

3 Likes

A mutable raw pointer to an inferred type.

The cast function itself doesn't – it's not magic, Every unspecified type parameter is eligible for inference by the compiler.

That would add a dependency and I cannot add traits/functions for structs in another crate.
My rgba is quite simple and I need only 2 or 3 functions in the whole program for converting different types of colors.

You absolutely can.

You absolutely can.

ok.

The more important thing was the blend routine itself.
It feels like processing these pixelblending could be done smarter. In Delphi and C# I believe I used a difficult lookup table, but that will probably not be any faster.

BTW: It performs reasonably already.

You can add a trait, and that trait can include functions - the extension trait pattern is exactly this.

While the coherence rules aren't trivial, you can treat them as "either the struct I'm implementing the trait for, or the trait I'm implementing, or both, must be defined in this crate" - this rule is slightly stricter than the coherence rules in cases where there are generic parameters involved.

2 Likes

It might be useful to add a fast path for fully-opaque or transparent pixels. On the other hand, the branching control flow might cost more speed than it gains, so you’ll need to benchmark it.

2 Likes

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.