Skip to main content

proka_kernel/libs/
bmp.rs

1/// BMP Image Parser
2extern crate alloc;
3use crate::graphics::color;
4use alloc::vec::Vec;
5
6#[derive(Debug)]
7pub enum BmpError {
8    InvalidSignature,
9    UnsupportedFormat,
10    InvalidData,
11}
12
13pub struct BmpImage {
14    width: u32,
15    height: u32,
16    pixels: Vec<color::Color>,
17}
18
19impl BmpImage {
20    pub fn from_bytes(data: &[u8]) -> Result<Self, BmpError> {
21        // 检查BMP文件头
22        if data.len() < 54 || data[0] != b'B' || data[1] != b'M' {
23            return Err(BmpError::InvalidSignature);
24        }
25
26        // 解析BMP文件头
27        let width = u32::from_le_bytes([data[18], data[19], data[20], data[21]]);
28        let height = u32::from_le_bytes([data[22], data[23], data[24], data[25]]);
29        let bpp = u16::from_le_bytes([data[28], data[29]]);
30
31        // 目前只支持24位和32位BMP
32        if bpp != 24 && bpp != 32 {
33            return Err(BmpError::UnsupportedFormat);
34        }
35
36        let data_offset = u32::from_le_bytes([data[10], data[11], data[12], data[13]]) as usize;
37
38        let mut pixels = Vec::with_capacity((width * height) as usize);
39        let bytes_per_pixel = (bpp / 8) as usize;
40        let row_padding = (4 - (width * bytes_per_pixel as u32) % 4) % 4;
41
42        // 解析像素数据 (BMP是倒序存储的)
43        for y in 0..height {
44            let row_start = data_offset
45                + ((height - y - 1) * (width * bytes_per_pixel as u32 + row_padding)) as usize;
46
47            for x in 0..width {
48                let pixel_start = row_start + (x * bytes_per_pixel as u32) as usize;
49                if pixel_start + bytes_per_pixel > data.len() {
50                    return Err(BmpError::InvalidData);
51                }
52
53                let b = data[pixel_start];
54                let g = data[pixel_start + 1];
55                let r = data[pixel_start + 2];
56                let a = if bytes_per_pixel == 4 {
57                    data[pixel_start + 3]
58                } else {
59                    255
60                };
61
62                pixels.push(color::Color::with_alpha(r, g, b, a));
63            }
64        }
65
66        Ok(BmpImage {
67            width,
68            height,
69            pixels,
70        })
71    }
72
73    pub fn width(&self) -> u32 {
74        self.width
75    }
76
77    pub fn height(&self) -> u32 {
78        self.height
79    }
80
81    pub fn pixel(&self, x: u32, y: u32) -> Option<color::Color> {
82        if x < self.width && y < self.height {
83            let index = (y * self.width + x) as usize;
84            Some(self.pixels[index])
85        } else {
86            None
87        }
88    }
89}