cathode/src-tauri/src/fs.rs

144 lines
3.9 KiB
Rust

use std::collections::HashMap;
use std::ffi::OsStr;
use std::fs::{self, File};
use std::path::Path;
use anyhow::Result;
use base64::prelude::*;
use image::ImageFormat;
use log::{debug, error};
use ray_format::Ray;
use serde::{Deserialize, Serialize};
use tauri::api::dialog::blocking::FileDialogBuilder;
use tauri::api::path::{cache_dir, home_dir, picture_dir};
#[derive(Serialize, Deserialize, Clone, Debug)]
pub(crate) struct WebRay {
frames: [String; 4],
meta: HashMap<String, String>,
}
#[tauri::command]
pub(crate) async fn open_image() -> Option<String> {
debug!("Opening iamge dialog...");
let path = FileDialogBuilder::new()
.add_filter("Images", &["png", "jpg"])
.set_directory(
picture_dir().unwrap_or_else(|| home_dir().expect("No home directory for user")),
)
.set_title("Select an image")
.pick_file()?;
if let Ok(mut b) = image::open(&path) {
if b.width() > 600 || b.height() > 400 {
b = b.resize(600, 400, image::imageops::FilterType::Lanczos3);
}
let mut loaded = cache_dir()
.expect("Unable to get cache dir")
.join("cathode")
.join("loaded")
.join(path.file_stem().unwrap_or_else(|| OsStr::new("image")));
loaded.set_extension("png");
let mut file = File::create(&loaded).expect("Unable to create file");
b.write_to(&mut file, ImageFormat::Png).unwrap();
loaded.to_str().map(|v| v.to_string())
} else {
None
}
}
#[tauri::command]
pub(crate) async fn open_ray() -> Option<WebRay> {
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<Path>) -> Option<WebRay> {
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_STANDARD.encode(f);
frames[i as usize] = encoded;
}
}
for k in ray.get_meta_keys() {
if let Some(v) = ray.get_meta_value(&k) {
meta.insert(k.clone(), v.clone());
}
}
if let Err(e) = cache_loaded_ray(path.as_ref()) {
error!("Error caching loaded ray: {e}");
}
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() {
if f == "" {
continue;
}
match BASE64_STANDARD.decode(f) {
Ok(decoded) => {
res.set_frame(i as usize, decoded);
}
Err(e) => {
error!("{e:?}");
}
}
}
for (k, v) in ray.meta {
res.add_meta(k, v);
}
cache_loaded_ray(&path).map_err(|e| e.to_string())?;
res.save(&path)
.map_err(|e| format!("Failed to save ray file: {}", e))
} else {
Ok(())
}
}
pub fn cache_loaded_ray(path: impl AsRef<Path>) -> Result<()> {
fs::write(
cache_dir().unwrap().join("cathode").join("last_selected"),
path.as_ref()
.canonicalize()
.unwrap()
.to_str()
.unwrap()
.as_bytes(),
)?;
Ok(())
}