rust-osdev / uefi-rs

Rust wrapper for UEFI.
https://rust-osdev.com/uefi-book
Mozilla Public License 2.0
1.26k stars 153 forks source link

Display BMP image on screen #344

Closed JakubGawron1 closed 2 years ago

JakubGawron1 commented 2 years ago

Overall I am very impressed with the design and it is great in general, but I recently found a Redox bootloader for uefi and there is an option to display a BMP image on the screen. And I'm just wondering if you could do something similar with just uefi-rs?

I apologize in advance for my English but English is not my mother tongue

nicholasbishop commented 2 years ago

I don't think we have any direct support for BMPs, but it should be possible to implement that using the GOP interface.

There's an example of that protocol being used to draw blocks of color here: https://github.com/rust-osdev/uefi-rs/blob/master/uefi-test-runner/src/proto/console/gop.rs

Here's a no-std BMP crate that you might be able to use to load your input: https://docs.rs/tinybmp/0.3.1/tinybmp/

nicholasbishop commented 2 years ago

I put together a quick self-contained example: https://github.com/nicholasbishop/uefi-bmp-example

The core of it is:

fn draw_bmp(gop: &mut GraphicsOutput) {
    // Embed a BMP.
    let bmp_data = include_bytes!("../image.bmp");

    // Parse the BMP data.
    let bmp = Bmp::<Rgb888>::from_slice(bmp_data).unwrap();

    // Convert width/height to usize.
    let width: usize = bmp.as_raw().size().width.try_into().unwrap();
    let height: usize = bmp.as_raw().size().height.try_into().unwrap();

    // Convert the pixel data into a form expected by the blit operation.
    let mut buffer = Vec::with_capacity(width * height);
    for pixel in bmp.pixels() {
        let color = pixel.1;
        buffer.push(BltPixel::new(color.r(), color.g(), color.b()));
    }

    // Blit the buffer to the framebuffer.
    gop.blt(BltOp::BufferToVideo {
        buffer: &buffer,
        src: BltRegion::Full,
        dest: (0, 0),
        dims: (width, height),
    })
    .expect_success("Failed to draw bmp");
}

To keep things simple I allocated an intermediate buffer there to convert pixel data, so this is probably not the most efficient solution, but it's sufficient for demonstration purposes.

Closing, but feel free to reopen if that didn't fully answer your question.