This function should be able to do what you're looking for. Note that each returned pixel has the components [b, g, r, 0_u8]
; since Image::with_data
expects BGRA pixels, it should work directly, although I don't have sciter available to test.
fn screenshot() -> (u32, u32, Vec<u8>) {
use std::{mem, ptr};
use winapi::{
shared::minwindef,
um::{wingdi, winuser},
};
unsafe {
let width = winuser::GetSystemMetrics(winuser::SM_CXSCREEN);
assert!(width != 0);
let height = winuser::GetSystemMetrics(winuser::SM_CYSCREEN);
assert!(height != 0);
let screen = winuser::GetDC(ptr::null_mut());
assert!(!screen.is_null());
let dc = wingdi::CreateCompatibleDC(screen);
assert!(!dc.is_null());
let bitmap = wingdi::CreateCompatibleBitmap(screen, width, height);
assert!(!bitmap.is_null());
let result = wingdi::SelectObject(dc, bitmap.cast());
assert!(!result.is_null());
let result = wingdi::BitBlt(dc, 0, 0, width, height, screen, 0, 0, wingdi::SRCCOPY);
assert!(result != 0);
assert!(winuser::ReleaseDC(ptr::null_mut(), screen) == 1);
let mut header = wingdi::BITMAPINFOHEADER {
biSize: mem::size_of::<wingdi::BITMAPINFOHEADER>() as minwindef::DWORD,
biWidth: width,
biHeight: -height,
biPlanes: 1,
biBitCount: 32,
biCompression: wingdi::BI_RGB,
biSizeImage: 0,
biXPelsPerMeter: 0,
biYPelsPerMeter: 0,
biClrUsed: 0,
biClrImportant: 0,
};
let buf_size = width as usize * height as usize * 4;
let mut buffer: Vec<u8> = Vec::with_capacity(buf_size);
let result = wingdi::GetDIBits(
dc,
bitmap,
0,
height as minwindef::UINT,
buffer.as_mut_ptr().cast(),
&mut header as *mut _ as wingdi::LPBITMAPINFO,
wingdi::DIB_RGB_COLORS,
);
assert!(result == height);
buffer.set_len(buf_size);
assert!(wingdi::DeleteObject(bitmap.cast()) != 0);
assert!(wingdi::DeleteDC(dc) != 0);
(width as u32, height as u32, buffer)
}
}
Most of this program was adapted from the Capturing an Image example on Microsoft Docs.