How to change transparency of bitmap image?

Must I use two loops and set alpha value for each pixel ? I want a faster way, or algorithm.

Images are normally stored with the value for each channel (red, green, blue, alpha) next to each other, so any function which sets the alpha channel will reduce to traversing the image's pixels and updating every 4th channel.

If you are using the image crate, the basic implementation would go something like this:

use image::{Rgba, RgbaImage};

fn main() {
    let width = 256;
    let height = 256;
    let mut image = RgbaImage::from_pixel(width, height, Rgba([0; 4]));

    image.pixels_mut().for_each(|p| p[3] += 2);
}

(playground)

We might be able to use rayon to throw multiple threads at the problem. This implementation works by getting the underlying u8 buffer, splitting it into chunks of 4 consecutive bytes (the red, green, blue, and alpha channels), then updating the 4th channel in parallel.

use image::{Rgba, RgbaImage};
use rayon::prelude::*;

fn main() {
    let width = 256;
    let height = 256;
    let mut image = RgbaImage::from_pixel(width, height, Rgba([0; 4]));

    image
        .as_flat_samples_mut()
        .samples
        .par_chunks_mut(4)
        .for_each(|channels: &mut [u8]| channels[3] += 2);
}

(playground)

In theory, you could use a GPU to parallelise the operation, but that's guaranteed to be slower because you've got to copy the entire image (which requires reading every pixel) to the GPU and back again.

5 Likes

Thank you! Here are so many elites

One thing to keep in mind is that debug builds will be ludicrously slow at this for any decently sized image. A bad option is to use unsafe code and pointers, a good option is to push it out to a crate (or use an existing one!) and configure cargo to optimize it.

IIRC, the following added to cargo.toml should work:

# optimize all dependencies
[profile.dev."*"]
opt-level = 2

Ok, thank you.