英文:
How to get a screenshot of a specific window with Rust on Windows?
问题
我想知道如何截取特定窗口的部分屏幕截图。应用程序上可能会有一个覆盖物(游戏覆盖层),它会隐藏我感兴趣的内容。我想找到一种方法,仅截取应用程序的屏幕截图,忽略覆盖层或位于顶部的内容。
我想知道是否有可能进行优化,以获得每秒大约5张屏幕截图。
目前,我尝试了这个screenshots cargo包,使用以下代码:
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();
// 将图像类型更改为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);
// 在控制台中打印处理图像所需的时间
println!("{} ms", now.elapsed().as_millis());
}
}
但似乎不可能只截取覆盖层后面的特定窗口的屏幕截图。
我使用
cargo run --release
目标操作系统是Windows,我也在Windows下进行开发。
英文:
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
答案1
得分: 3
你可以使用 winapi
和 user32
存储库来获取任何窗口的屏幕截图。
你之前可能错误地使用了在Windows上不起作用的opencv
库。
以下是我的示例代码。假设我们有一个名为 '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);
}
}
你可以通过输入 cargo run
来运行它。
英文:
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
.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论