How to get a screenshot of a specific window with Rust on Windows?
Matthew Martinez
I would like to know how to take screenshots of a part of a specific window. There may be an overlay on top of the application (a game overlay) that hides what I'm interested in. I would like to find a way to take a screenshot of the application only, ignoring the overlay or what would be on top.
And I wonder if it's possible to optimize it in order to have ~5 screenshots/seconds
For now i tried the screenshots cargo package with the following code :
use opencv::{core, highgui, imgcodecs};
use screenshots::Screen;
use std::{time::Instant};
use opencv::core::{log, Mat};
const WIDTH: i32 = 275;
const HEIGHT: i32 = 275;
fn get_img(screen: Screen) -> Mat { let image = screen.capture().unwrap(); let buffer: Vec<u8> = image.into(); // Change image type to OpenCV Mat let original_image: Mat = imgcodecs::imdecode(&core::Mat::from_slice(buffer.as_slice()).unwrap(), imgcodecs::IMREAD_COLOR).unwrap(); return original_image;
}
fn main() { let window_name = "test".to_owned(); highgui::named_window(&window_name, highgui::WINDOW_NORMAL).unwrap(); highgui::resize_window(&window_name, WIDTH, HEIGHT).unwrap(); let screens = Screen::all().unwrap(); let screen = screens[1].clone(); let mut img = get_img(screen); loop { let now = Instant::now(); img = get_img(screen); // print in console the time it took to process the image println!("{} ms", now.elapsed().as_millis()); }
}But it seem not possible to take screenshot of just a specific window behind an overlay.
I use
cargo run --release
The target os is Windows and I'm also developing under Windows.
ps : I convert my image to OpenCV Mat for the next part of my code
31 Answer
You can use winapi and user32 repo to get any window screenshot.
Wrong that you had made maybe using onencv library that not working on Windows.
Here's my example code. Let's say we have a window call 'Chrome'
use winapi::um::winuser::{FindWindowA, GetWindowRect, GetDC, ReleaseDC};
use winapi::shared::windef::RECT;
use std::ptr::null_mut;
fn main() { let window_title = "Chrome"; let hwnd = unsafe { FindWindowA(null_mut(), window_title.as_ptr() as *const i8) }; let mut rect = RECT::default(); unsafe { GetWindowRect(hwnd, &mut rect); let width = rect.right - rect.left; let height = rect.bottom - rect.top; let hdc = GetDC(hwnd); let mut buf: Vec<u32> = vec![0; (width * height) as usize]; let pitch = width * std::mem::size_of::<u32>() as i32; winapi::um::wingdi::BitBlt(hdc, 0, 0, width, height, hdc, 0, 0, winapi::um::wingdi::SRCCOPY); winapi::um::wingdi::GetDIBits(hdc, null_mut(), 0, height as u32, buf.as_mut_ptr() as *mut _, &mut winapi::um::wingdi::BITMAPINFO { bmiHeader: winapi::um::wingdi::BITMAPINFOHEADER { biSize: std::mem::size_of::<winapi::um::wingdi::BITMAPINFOHEADER>() as u32, biWidth: width, biHeight: height * -1, biPlanes: 1, biBitCount: 32, ..Default::default() }, ..Default::default() }, winapi::um::wingdi::DIB_RGB_COLORS); ReleaseDC(hwnd, hdc); }
}you can run it by typing cargo run.