ARGB32 Color Model

Hey! I was hoping for some help with image formats.

I'm trying to use ksni to add an icon to the system tray. The method that determines the icon shown is called icon_pixmap and it returns Vec<Icon>. Icon represents an ARGB32 image in network byte order and it takes a height, width, and data as Vec<u8>.

I have the icons as PNGs which I am embedding via include_bytes!, but I'm having a hard time figuring out how to convert it to ARGB32. The closest lead I've found is cairo's variant for Argb32. I would appreciate any guidance in the right direction?

If you don't find a crate to do this for you, you could use the image crate to get a RgbaImage from the PNG, iterate over the pixels which will be [u8; 4], read each of those into a u32 and rotate it to turn RGBA into ARGB, and then store it back into the pixel in the desired order, and finally extract the bytes.

You could do this in a build script, output the ARGBs, and include_bytes those instead. Or just convert them with something else if it's a static-ish set; I'm sure there's some ImageMagick incantation to do it for example.

2 Likes

Thank you so much for all your help, @quinedot! Could you please review my implementation below when you get a chance? Interestingly, only one of the PNGs is showing correctly and the other seems to have its channels in a different order.

use image::{load_from_memory, Rgba};

fn rgba_image_bytes_to_argb32_network_order(image_bytes: &[u8]) -> Vec<u8> {
    if let Ok(image) = load_from_memory(image_bytes) {
        let mut image_buffer = image.to_rgba8();

        for pixel in image_buffer.pixels_mut() {
            *pixel = Rgba(u32::from_le_bytes(pixel.0).rotate_right(8).to_be_bytes());
        }

        image_buffer.into_raw()
    } else {
        println!("Error converting RGBA image bytes to ARGB 32 network order.");
        Vec::<u8>::new()
    }
}

That's pretty much what I was thinking, yep. But I didn't test it, probably I got the byte order wrong in my head. Does using from_be_bytes fix it?

// Only stylistically different from yours, post-change
fn convert(img: &[u8]) -> Result<Vec<u8>, ImageError> {
    let img = image::load_from_memory(img)?;
    let mut img = img.to_rgba8();
    for Rgba(pixel) in img.pixels_mut() {
        *pixel = u32::from_be_bytes(*pixel)
            .rotate_right(8)
            .to_be_bytes();
    }
    
    Ok(img.into_raw())
}
1 Like

The from_be_bytes fixed it --- thank you!

Also, extra special thanks for taking the time to rewrite the code in idiomatic Rust. I'm still trying to improve in that regard, so your refactoring was very helpful. :pray:t5:

1 Like

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.