94 lines
3.0 KiB
Rust
94 lines
3.0 KiB
Rust
use base64::{engine::general_purpose::STANDARD as BASE64, Engine as _};
|
|
use std::process::{Command, Output};
|
|
use std::{fs, path::PathBuf};
|
|
use tauri::{AppHandle, Emitter, Runtime};
|
|
|
|
#[cfg(target_os = "macos")]
|
|
fn screenshot(path: &PathBuf) -> Result<Output, String> {
|
|
Command::new("screencapture")
|
|
.arg("-i") // interactive selection
|
|
.arg("-x") // don't play sound
|
|
.arg("-o") // don't show cursor
|
|
.arg("-r") // don't add shadow
|
|
.arg(path.to_str().unwrap())
|
|
.output()
|
|
.map_err(|e| format!("Failed to execute screencapture: {}", e))
|
|
}
|
|
|
|
#[cfg(target_os = "linux")]
|
|
fn screenshot(path: &PathBuf) -> Result<Output, String> {
|
|
let slurp_output = Command::new("slurp")
|
|
.output()
|
|
.map_err(|e| format!("Failed to execute screencapture: {}", e))?;
|
|
|
|
if !slurp_output.status.success() {
|
|
let stderr = String::from_utf8_lossy(&slurp_output.stderr);
|
|
if slurp_output.status.code() == Some(1) && stderr.is_empty() {
|
|
log::warn!("slurp cancelled by user.");
|
|
return Err("Screenshot cancelled by user.".to_string());
|
|
}
|
|
return Err(format!(
|
|
"slurp failed. Status: {:?}, Stderr: {}",
|
|
slurp_output.status, stderr
|
|
));
|
|
}
|
|
|
|
let geometry = String::from_utf8(slurp_output.stdout)
|
|
.map_err(|e| format!("slurp output is not valid UTF-8: {}", e))?
|
|
.trim()
|
|
.to_string();
|
|
|
|
if geometry.is_empty() {
|
|
return Err("slurp succeeded but returned empty geometry".to_string());
|
|
}
|
|
|
|
Command::new("grim")
|
|
.arg("-g")
|
|
.arg(&geometry)
|
|
.arg(path.to_str().unwrap())
|
|
.output()
|
|
.map_err(|e| format!("Failed to execute screencapture: {}", e))
|
|
}
|
|
|
|
/// Takes a screenshot of a selected area and returns the image data as base64
|
|
#[cfg(any(target_os = "linux", target_os = "macos"))]
|
|
pub fn take_area_screenshot<R: Runtime>(app: &AppHandle<R>) -> Result<String, String> {
|
|
// Create a temporary file path
|
|
let temp_dir = std::env::temp_dir();
|
|
let timestamp = chrono::Local::now().format("%Y%m%d_%H%M%S");
|
|
let temp_file = temp_dir.join(format!("haystack_screenshot_{}.png", timestamp));
|
|
|
|
log::info!("{}", temp_file.display());
|
|
|
|
let output = screenshot(&temp_file)?;
|
|
log::info!("0");
|
|
|
|
if !output.status.success() {
|
|
return Err(format!(
|
|
"screencapture failed: {}",
|
|
String::from_utf8_lossy(&output.stderr)
|
|
));
|
|
}
|
|
|
|
log::info!("1");
|
|
|
|
// Read the captured image
|
|
let contents =
|
|
fs::read(&temp_file).map_err(|e| format!("Failed to read screenshot file: {}", e))?;
|
|
|
|
log::info!("2");
|
|
|
|
// Convert to base64
|
|
let base64_string = BASE64.encode(&contents);
|
|
|
|
// Clean up the temporary file
|
|
if let Err(e) = fs::remove_file(&temp_file) {
|
|
println!("Warning: Failed to remove temporary screenshot file: {}", e);
|
|
}
|
|
|
|
app.emit("png-processed", base64_string.clone())
|
|
.map_err(|e| format!("Failed to emit event: {}", e))?;
|
|
|
|
Ok(base64_string)
|
|
}
|