Skip to content

Conversation

@Ddystopia
Copy link

This PR adds support for 4 bit images for BMP encoder. I tested it with different images (with even/odd number of rows etc) with tinybmp and images look exactly right.

As far as I understand the API, if user passes L4 then we expect bytes user gives to already be packed. In my own code I used this helper to create those bufs (this is not a part of PR):

fn rgb_to_4bit_packed(image: &image::RgbImage, palette: &[[u8; 3]]) -> Vec<u8> {
    let stride = image.width() + (image.width() % 2); // pad to even width
    let buffer_size = (stride * 4).div_ceil(8) * image.height();
    let mut output = vec![0u8; buffer_size as usize];

    assert!(palette.len() <= 16, "palette must have at most 16 colors");

    for (x, y, pixel) in image.enumerate_pixels() {
        let idx = palette
            .iter()
            .position(|&c| c == pixel.0)
            .expect("Pixel color not in palette") as u8;

        let i = x as usize + y as usize * stride as usize;

        if i % 2 == 0 {
            output[i / 2] = idx << 4;
        } else {
            output[i / 2] |= idx;
        }
    }

    output
}

@Ddystopia
Copy link
Author

CI failure is not related to the pr, avif decoder was not touched:

error: there is no need to manually implement bit rotation
   --> src/codecs/avif/decoder.rs:652:21
    |
652 |             *item = (*item << target_expand_bits) | (*item >> (16 - target_expand_bits));
    |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: this expression can be rewritten as: `(*item).rotate_left(target_expand_bits)`

@Shnatsel
Copy link
Member

What is the motivation for this change?

Paletted mode mostly provides size savings, but BMP is an awful format if you want a small image size, so I'm not sure it's worth supporting in 2025.

@Ddystopia
Copy link
Author

I don't know any better image format for 4bpp images that is fast to decompress too
Tga? 8bpp minimum. Qoi? No less then rgb888. In the end 4bpp images with rle are quite good, for embedded use cases.

@Ddystopia
Copy link
Author

But at the end of the day I just vendored that encoder inside, if anyone would want that stuff they may dig out that pr and use it. I did pr just to share work.

@Shnatsel
Copy link
Member

Oh, you needed to write a paletted image with 16 colors for embedded use where it's cheap to decode? That explains the motivation, thank you.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants