| use base64::{engine::general_purpose, Engine as _};
|
| use tauri::{AppHandle, Manager};
|
|
|
|
|
|
|
| #[tauri::command]
|
| pub fn board_load_state(app: AppHandle) -> Result<String, String> {
|
| let path = crate::persistence::app_file_path(&app, "canvas_state.json")?;
|
| if !path.exists() { return Ok("{}".to_string()); }
|
| std::fs::read_to_string(&path).map_err(|e| e.to_string())
|
| }
|
|
|
| #[tauri::command]
|
| pub fn board_save_state(app: AppHandle, state: String) -> Result<(), String> {
|
| let path = crate::persistence::app_file_path(&app, "canvas_state.json")?;
|
| std::fs::write(&path, &state).map_err(|e| e.to_string())
|
| }
|
|
|
| #[tauri::command]
|
| pub fn board_export_file(_app: AppHandle, filepath: String, state: String) -> Result<(), String> {
|
| std::fs::write(&filepath, &state).map_err(|e| e.to_string())
|
| }
|
|
|
| #[tauri::command]
|
| pub fn board_import_file(_app: AppHandle, filepath: String) -> Result<String, String> {
|
| let content = std::fs::read_to_string(&filepath).map_err(|e| e.to_string())?;
|
| let _: serde_json::Value = serde_json::from_str(&content).map_err(|e| format!("Invalid board file: {e}"))?;
|
| Ok(content)
|
| }
|
|
|
| fn encode_rgba_to_png_data_url(width: u32, height: u32, raw_pixels: Vec<u8>) -> Result<String, String> {
|
| let img_buffer = image::RgbaImage::from_raw(width, height, raw_pixels)
|
| .ok_or_else(|| "Failed to create image buffer from screenshot pixels".to_string())?;
|
| let dynamic = image::DynamicImage::ImageRgba8(img_buffer);
|
| let mut png_bytes: Vec<u8> = Vec::new();
|
| dynamic.write_to(&mut std::io::Cursor::new(&mut png_bytes), image::ImageFormat::Png)
|
| .map_err(|e| format!("PNG encode failed: {e}"))?;
|
| let b64 = general_purpose::STANDARD.encode(&png_bytes);
|
| Ok(format!("data:image/png;base64,{b64}"))
|
| }
|
|
|
|
|
| #[tauri::command]
|
| pub fn screen_capture_full() -> Result<String, String> {
|
| use screenshots::Screen;
|
| let screens = Screen::all().map_err(|e| format!("Failed to get screens: {e}"))?;
|
| let screen = screens.first().ok_or("No screen found")?;
|
| let capture = screen.capture().map_err(|e| format!("Capture failed: {e}"))?;
|
| let width = capture.width();
|
| let height = capture.height();
|
| encode_rgba_to_png_data_url(width, height, capture.into_raw())
|
| }
|
|
|
|
|
| #[tauri::command]
|
| pub fn screen_capture_region(x: i32, y: i32, width: u32, height: u32) -> Result<String, String> {
|
| use screenshots::Screen;
|
| let screens = Screen::all().map_err(|e| format!("Failed to get screens: {e}"))?;
|
| let screen = screens.first().ok_or("No screen found")?;
|
| let capture = screen.capture_area(x, y, width, height)
|
| .map_err(|e| format!("Region capture failed: {e}"))?;
|
| let w = capture.width();
|
| let h = capture.height();
|
| encode_rgba_to_png_data_url(w, h, capture.into_raw())
|
| }
|
|
|
|
|
|
|
|
|
| #[tauri::command]
|
| pub fn screen_capture_window_region(app: AppHandle, x: f64, y: f64, width: f64, height: f64) -> Result<String, String> {
|
| let window = app.get_window("main").ok_or("main window not found")?;
|
| let scale = window.scale_factor().map_err(|e| format!("scale_factor failed: {e}"))?;
|
| let pos = window.outer_position().map_err(|e| format!("outer_position failed: {e}"))?;
|
|
|
| let px = pos.x + (x * scale).round() as i32;
|
| let py = pos.y + (y * scale).round() as i32;
|
| let pw = (width * scale).round().max(1.0) as u32;
|
| let ph = (height * scale).round().max(1.0) as u32;
|
|
|
| screen_capture_region(px, py, pw, ph)
|
| }
|
|
|
| #[tauri::command]
|
| pub fn phase0_status() -> String {
|
| "Refstudio v1.0-alpha — Board-first reference tool for artists".to_string()
|
| }
|
|
|