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
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
use winapi::um::wingdi::{GetDIBits, GetObjectW};
use std::{ptr, slice, io, mem};
use std::os::raw::{c_void, c_int, c_long, c_ulong};
use crate::utils;
struct Dc(winapi::shared::windef::HDC);
impl Dc {
fn new() -> Self {
Self(unsafe { winapi::um::winuser::GetDC(ptr::null_mut()) })
}
}
impl Drop for Dc {
fn drop(&mut self) {
unsafe { winapi::um::winuser::ReleaseDC(ptr::null_mut(), self.0) };
}
}
#[repr(C)]
#[derive(Clone, Copy)]
struct BmpHeader {
typ: u16,
size: u32,
reserved: u32,
offset: u32,
info: winapi::um::wingdi::BITMAPINFO,
}
impl BmpHeader {
const fn len() -> usize {
mem::size_of::<BmpHeader>() - mem::size_of::<winapi::um::wingdi::RGBQUAD>()
}
}
impl Default for BmpHeader {
fn default() -> Self {
Self {
typ: 0x4D42,
size: 0,
reserved: 0,
offset: 54,
info: unsafe { mem::zeroed() }
}
}
}
pub struct Bitmap {
inner: winapi::shared::windef::HBITMAP,
pub data: winapi::um::wingdi::BITMAP,
}
impl Bitmap {
pub fn new(ptr: *mut c_void) -> io::Result<Self> {
use winapi::um::wingdi::BITMAP;
let mut data: BITMAP = unsafe { mem::zeroed() };
let data_ptr = &mut data as *mut BITMAP as *mut c_void;
match unsafe { GetObjectW(ptr as *mut c_void, mem::size_of::<BITMAP>() as c_int, data_ptr) } {
0 => Err(utils::get_last_error()),
_ => Ok(Self {
inner: ptr as winapi::shared::windef::HBITMAP,
data
}),
}
}
#[inline]
pub fn size(&self) -> usize {
let color_bits = (self.data.bmPlanes * self.data.bmBitsPixel) as c_long;
let result = ((self.data.bmWidth * color_bits + 31) / color_bits) * 4 * self.data.bmHeight;
result as usize
}
#[inline]
pub fn as_bytes(&self) -> &[u8] {
unsafe { slice::from_raw_parts(self.data.bmBits as *const _, self.size()) }
}
#[inline]
pub fn as_raw(&self) -> winapi::shared::windef::HBITMAP {
self.inner
}
#[inline]
pub fn dimensions(&self) -> (usize, usize) {
(self.data.bmWidth as usize, self.data.bmHeight as usize)
}
#[doc(hidden)]
pub fn data(&self) -> io::Result<Vec<u8>> {
use winapi::um::wingdi::{DIB_RGB_COLORS, BITMAPINFOHEADER, BITMAPINFO};
let dc = Dc::new();
let mut header = BmpHeader::default();
header.info.bmiHeader.biSize = mem::size_of::<BITMAPINFOHEADER>() as c_ulong;
let data_ptr = &mut header.info as *mut BITMAPINFO;
match unsafe { GetDIBits(dc.0, self.inner, 0, 0, ptr::null_mut(), data_ptr, DIB_RGB_COLORS) } {
0 => return Err(utils::get_last_error()),
_ => (),
}
header.info.bmiHeader.biCompression = winapi::um::wingdi::BI_RGB;
header.size = header.info.bmiHeader.biSizeImage as u32 + header.offset;
let buffer_len = BmpHeader::len() + header.info.bmiHeader.biSizeImage as usize;
let mut buffer = Vec::with_capacity(buffer_len);
buffer.extend_from_slice(unsafe { slice::from_raw_parts(&header as *const _ as *const u8, BmpHeader::len()) });
unsafe { buffer.set_len(buffer_len) };
match unsafe { GetDIBits(dc.0, self.inner, 0, 0, buffer.get_unchecked_mut(mem::size_of::<BmpHeader>()) as *mut u8 as *mut _, data_ptr, DIB_RGB_COLORS) } {
0 => Err(utils::get_last_error()),
_ => Ok(buffer),
}
}
}