use std::thread;
use std::time::{Duration, Instant};
#[cfg(target_os = "windows")]
use arboard::Clipboard;
#[cfg(target_os = "windows")]
use image::{DynamicImage, ImageBuffer, Rgba};
pub fn start_snapshot_cropper() -> Option<DynamicImage> {
#[cfg(target_os = "windows")]
{
use std::process::Command;
let prev_image_signature = capture_clipboard_image_signature();
let _ = Command::new("powershell")
.args(&["-NoProfile", "-Command", "Start-Process -WindowStyle Hidden 'ms-screenclip:'"])
.status();
let poll_interval = Duration::from_millis(250);
let overall_timeout = Duration::from_secs(60);
let start = Instant::now();
thread::sleep(Duration::from_millis(300));
loop {
if start.elapsed() > overall_timeout {
eprintln!("desktop_cropper: timed out waiting for snip after 60s");
return None;
}
if let Some(img) = read_new_clipboard_image(&prev_image_signature) {
return Some(img);
}
thread::sleep(poll_interval);
}
}
#[cfg(not(target_os = "windows"))]
{
None
}
}
#[cfg(target_os = "windows")]
fn capture_clipboard_image_signature() -> Option<(usize, usize, Vec<u8>)> {
let mut clipboard = Clipboard::new().ok()?;
match clipboard.get_image() {
Ok(data) => {
let prefix = data.bytes.iter().take(64).copied().collect::<Vec<_>>();
Some((data.width, data.height, prefix))
}
Err(_) => None,
}
}
#[cfg(target_os = "windows")]
fn read_new_clipboard_image(prev: &Option<(usize, usize, Vec<u8>)>) -> Option<DynamicImage> {
let mut clipboard = match Clipboard::new() {
Ok(c) => c,
Err(_) => return None,
};
let data = match clipboard.get_image() {
Ok(d) => d,
Err(_) => return None,
};
if data.width == 0 || data.height == 0 {
return None;
}
if let Some((pw, ph, pprefix)) = prev {
if data.width == *pw && data.height == *ph {
let current_prefix: Vec<u8> =
data.bytes.iter().take(64).copied().collect();
if current_prefix == *pprefix {
return None;
}
}
}
eprintln!(
"desktop_cropper: got image {}x{} ({} bytes)",
data.width,
data.height,
data.bytes.len()
);
let mut rgba_data: Vec<u8> = Vec::with_capacity(data.bytes.len());
let bytes = data.bytes.as_ref();
for chunk in bytes.chunks(4) {
if chunk.len() >= 4 {
rgba_data.push(chunk[2]); rgba_data.push(chunk[1]); rgba_data.push(chunk[0]); rgba_data.push(chunk[3]); }
}
let buf = ImageBuffer::<Rgba<u8>, Vec<u8>>::from_raw(
data.width as u32,
data.height as u32,
rgba_data,
)?;
let debug_path = std::env::temp_dir().join("qr_clipped_raw.png");
let dyn_img = DynamicImage::ImageRgba8(buf);
if dyn_img.save(&debug_path).is_ok() {
eprintln!("desktop_cropper: saved debug to {:?}", debug_path);
}
Some(dyn_img)
}