feat: window screenshot (PrintWindow), name-based window resolution
This commit is contained in:
parent
27b1ffc55b
commit
efc9cab2c3
6 changed files with 164 additions and 10 deletions
|
|
@ -117,6 +117,76 @@ pub fn take_screenshot() -> Result<(String, u32, u32), String> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Capture a specific window using PrintWindow (works even if occluded).
|
||||
#[cfg(windows)]
|
||||
pub fn take_window_screenshot(window_id: u64) -> Result<(String, u32, u32), String> {
|
||||
use windows::Win32::Foundation::{HWND, RECT};
|
||||
use windows::Win32::Graphics::Gdi::{
|
||||
CreateCompatibleBitmap, CreateCompatibleDC, DeleteDC, DeleteObject,
|
||||
GetDIBits, SelectObject, BITMAPINFO, BITMAPINFOHEADER, DIB_RGB_COLORS,
|
||||
};
|
||||
use windows::Win32::UI::WindowsAndMessaging::{GetWindowRect, PrintWindow, PW_RENDERFULLCONTENT};
|
||||
use windows::Win32::Graphics::Gdi::GetDC;
|
||||
use windows::Win32::Graphics::Gdi::ReleaseDC;
|
||||
|
||||
let hwnd = HWND(window_id as isize);
|
||||
|
||||
unsafe {
|
||||
let mut rect = RECT::default();
|
||||
GetWindowRect(hwnd, &mut rect).map_err(|e| format!("GetWindowRect failed: {e}"))?;
|
||||
let width = (rect.right - rect.left) as u32;
|
||||
let height = (rect.bottom - rect.top) as u32;
|
||||
if width == 0 || height == 0 {
|
||||
return Err(format!("Window has zero size: {width}x{height}"));
|
||||
}
|
||||
|
||||
let hdc_screen = GetDC(None);
|
||||
let hdc_mem = CreateCompatibleDC(hdc_screen);
|
||||
let hbm = CreateCompatibleBitmap(hdc_screen, width as i32, height as i32);
|
||||
let old_obj = SelectObject(hdc_mem, hbm);
|
||||
|
||||
// PrintWindow captures the window even if it's behind others
|
||||
PrintWindow(hwnd, hdc_mem, PW_RENDERFULLCONTENT);
|
||||
|
||||
let mut bmi = BITMAPINFO {
|
||||
bmiHeader: BITMAPINFOHEADER {
|
||||
biSize: std::mem::size_of::<BITMAPINFOHEADER>() as u32,
|
||||
biWidth: width as i32,
|
||||
biHeight: -(height as i32),
|
||||
biPlanes: 1,
|
||||
biBitCount: 32,
|
||||
biCompression: 0,
|
||||
biSizeImage: 0,
|
||||
biXPelsPerMeter: 0,
|
||||
biYPelsPerMeter: 0,
|
||||
biClrUsed: 0,
|
||||
biClrImportant: 0,
|
||||
},
|
||||
bmiColors: [Default::default()],
|
||||
};
|
||||
|
||||
let mut pixel_buf: Vec<u8> = vec![0u8; (width * height * 4) as usize];
|
||||
GetDIBits(hdc_mem, hbm, 0, height, Some(pixel_buf.as_mut_ptr() as *mut _), &mut bmi, DIB_RGB_COLORS);
|
||||
|
||||
SelectObject(hdc_mem, old_obj);
|
||||
DeleteObject(hbm);
|
||||
DeleteDC(hdc_mem);
|
||||
ReleaseDC(None, hdc_screen);
|
||||
|
||||
// BGRA → RGBA
|
||||
for chunk in pixel_buf.chunks_exact_mut(4) { chunk.swap(0, 2); }
|
||||
|
||||
let png_bytes = encode_png(&pixel_buf, width, height)?;
|
||||
let b64 = base64::engine::general_purpose::STANDARD.encode(&png_bytes);
|
||||
Ok((b64, width, height))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(windows))]
|
||||
pub fn take_window_screenshot(_window_id: u64) -> Result<(String, u32, u32), String> {
|
||||
Err("Window screenshot only supported on Windows".to_string())
|
||||
}
|
||||
|
||||
#[cfg(not(windows))]
|
||||
pub fn take_screenshot() -> Result<(String, u32, u32), String> {
|
||||
// Stub for non-Windows builds
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue