1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
use std::io::{BufRead, Seek, SeekFrom};
use byteorder::{ReadBytesExt, LittleEndian};
use crate::errors::{ImageError, ImageResult, ImageResultU};
use crate::types::{Color, ColorMode, Dimensions, Format, ImageMeta};
pub fn load<R: ?Sized + BufRead + Seek>(image: &mut R) -> ImageResult<ImageMeta> {
read_signature(image)?;
let (dimensions, color) = read_header(image)?;
Ok(ImageMeta {
animation_frames: None,
color,
dimensions,
format: Format::Bmp,
})
}
fn read_signature<R: ?Sized + BufRead + Seek>(image: &mut R) -> ImageResultU {
let mut signature = [0u8;2];
image.read_exact(&mut signature)?;
if signature != *b"BM" {
return Err(ImageError::InvalidSignature);
}
image.seek(SeekFrom::Current(12))?;
Ok(())
}
fn read_header<R: ?Sized + BufRead + Seek>(image: &mut R) -> ImageResult<(Dimensions, Color)> {
let header_size = image.read_u32::<LittleEndian>()?;
match header_size {
12 | 64 => read_os2_header(image),
40 | 108 | 124 => read_windows_header(image),
sz => Err(ImageError::CorruptImage(format!("Unsupported header size: {}", sz).into()))
}
}
fn read_windows_header<R: ?Sized + BufRead + Seek>(image: &mut R) -> ImageResult<(Dimensions, Color)> {
let width = image.read_u32::<LittleEndian>()?;
let height = image.read_i32::<LittleEndian>()?.abs() as u32;
image.seek(SeekFrom::Current(2))?;
let resolution = image.read_u16::<LittleEndian>()? / 3;
let dimensions = Dimensions { height, width };
let color = Color {
alpha_channel: false,
mode: ColorMode::Rgb,
resolution: resolution as u8,
};
Ok((dimensions, color))
}
fn read_os2_header<R: ?Sized + BufRead + Seek>(image: &mut R) -> ImageResult<(Dimensions, Color)> {
let width = image.read_u16::<LittleEndian>().map(u32::from)?;
let height = image.read_i16::<LittleEndian>()?.abs() as u32;
image.seek(SeekFrom::Current(2))?;
let resolution = image.read_u16::<LittleEndian>()? / 3;
let dimensions = Dimensions { height, width };
let color = Color {
alpha_channel: false,
mode: ColorMode::Rgb,
resolution: resolution as u8,
};
Ok((dimensions, color))
}