use std::collections::HashMap; use std::fs; use std::io::Cursor; use std::path::Path; use base64_url as base64; use image::ImageFormat; use log::{debug, trace}; use ray_format::Ray; use serde::{Deserialize, Serialize}; use tauri::api::dialog::blocking::FileDialogBuilder; use tauri::api::path::{cache_dir, home_dir, picture_dir}; const OBJ_URL: &'static str = "data:image/png;base64,"; #[derive(Serialize, Deserialize, Clone, Debug)] pub(crate) struct WebRay { frames: [String; 4], meta: HashMap, } #[tauri::command] pub(crate) async fn open_image() -> Option { debug!("Opening iamge dialog..."); let path = FileDialogBuilder::new() .add_filter("Images", &["png", "jpg"]) .set_directory(picture_dir().unwrap_or_else(|| home_dir().unwrap())) .set_title("Select an image") .pick_file()?; if let Ok(b) = image::open(path) { let mut buf = Cursor::new(vec![]); b.write_to(&mut buf, ImageFormat::Png).unwrap(); let encoded = base64::encode(buf.get_ref()); trace!("Encoded: {:?}", encoded); Some(format!("{}{}", OBJ_URL, encoded)) } else { None } } #[tauri::command] pub(crate) async fn open_ray() -> Option { let path = FileDialogBuilder::new() .add_filter("Rays", &["ray"]) .set_directory(home_dir()?) .pick_file()?; load_ray(path) } pub(crate) fn load_ray(path: impl AsRef) -> Option { let ray = Ray::load(path.as_ref()).ok()?; let mut frames = [String::new(), String::new(), String::new(), String::new()]; let mut meta = HashMap::new(); for i in 0..4 { debug!("Trying frame {}", i); if let Some(f) = ray.get_frame(i as usize) { debug!("Got frame {}", i); if f.is_empty() { debug!("Frame {} was empty", i); continue; } let encoded = base64::encode(&f); frames[i as usize] = format!("{}{}", OBJ_URL, encoded); } } for k in ray.get_meta_keys() { if let Some(v) = ray.get_meta_value(&k) { meta.insert(k.clone(), v.clone()); } } fs::write( cache_dir().unwrap().join("cathode").join("last_selected"), path.as_ref() .canonicalize() .unwrap() .to_str() .unwrap() .as_bytes(), ) .unwrap(); Some(WebRay { frames, meta }) } #[tauri::command] pub(crate) async fn save_ray(ray: WebRay) -> Result<(), String> { if let Some(path) = FileDialogBuilder::new() .add_filter("Rays", &["ray"]) .set_directory(home_dir().unwrap()) .set_title("Save Ray") .set_file_name("new.ray") .save_file() { let mut res = Ray::default(); for (i, f) in ray.frames.iter().enumerate() { let stripped = f.strip_prefix(OBJ_URL).unwrap_or(f); let decoded = base64::decode(stripped).unwrap(); res.set_frame(i as usize, decoded); } for (k, v) in ray.meta { res.add_meta(k, v); } res.save(&path) .map_err(|e| format!("Failed to save ray file: {}", e)) } else { Ok(()) } }