diff --git a/.gitignore b/.gitignore index c41e51a..5ec5e64 100644 --- a/.gitignore +++ b/.gitignore @@ -11,3 +11,5 @@ assets/fonts/lato.zip *.anno *.xml + +*.tif diff --git a/Cargo.lock b/Cargo.lock index 01da528..833f9de 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -869,6 +869,7 @@ dependencies = [ "bevy", "bevy_egui", "bevy_prototype_lyon", + "chrono", "egui", "futures-intrusive", "futures-lite", @@ -1036,6 +1037,21 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fd16c4719339c4530435d38e511904438d07cce7950afa3718a84ac36c10e89e" +[[package]] +name = "chrono" +version = "0.4.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16b0a3d9ed01224b22057780a37bb8c5dbfe1be8ba48678e7bf57ec4b385411f" +dependencies = [ + "iana-time-zone", + "js-sys", + "num-integer", + "num-traits", + "time", + "wasm-bindgen", + "winapi", +] + [[package]] name = "clipboard-win" version = "4.4.2" @@ -1324,6 +1340,50 @@ version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ef8ae57c4978a2acd8b869ce6b9ca1dfe817bff704c220209fdef2c0b75a01b9" +[[package]] +name = "cxx" +version = "1.0.82" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4a41a86530d0fe7f5d9ea779916b7cadd2d4f9add748b99c2c029cbbdfaf453" +dependencies = [ + "cc", + "cxxbridge-flags", + "cxxbridge-macro", + "link-cplusplus", +] + +[[package]] +name = "cxx-build" +version = "1.0.82" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06416d667ff3e3ad2df1cd8cd8afae5da26cf9cec4d0825040f88b5ca659a2f0" +dependencies = [ + "cc", + "codespan-reporting", + "once_cell", + "proc-macro2", + "quote", + "scratch", + "syn", +] + +[[package]] +name = "cxxbridge-flags" +version = "1.0.82" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "820a9a2af1669deeef27cb271f476ffd196a2c4b6731336011e0ba63e2c7cf71" + +[[package]] +name = "cxxbridge-macro" +version = "1.0.82" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a08a6e2fcc370a089ad3b4aaf54db3b1b4cee38ddabce5896b33eb693275f470" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "d3d12" version = "0.5.0" @@ -2079,6 +2139,30 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dfa686283ad6dd069f105e5ab091b04c62850d3e4cf5d67debad1933f55023df" +[[package]] +name = "iana-time-zone" +version = "0.1.53" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64c122667b287044802d6ce17ee2ddf13207ed924c712de9a66a5814d5b64765" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "wasm-bindgen", + "winapi", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0703ae284fc167426161c2e3f1da3ea71d94b21bedbcc9494e92b28e334e3dca" +dependencies = [ + "cxx", + "cxx-build", +] + [[package]] name = "ident_case" version = "1.0.1" @@ -2310,6 +2394,15 @@ version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "348108ab3fba42ec82ff6e9564fc4ca0247bdccdc68dd8af9764bbc79c3c8ffb" +[[package]] +name = "link-cplusplus" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9272ab7b96c9046fbc5bc56c06c117cb639fe2d509df0c421cad82d2915cf369" +dependencies = [ + "cc", +] + [[package]] name = "lock_api" version = "0.4.9" @@ -3405,6 +3498,12 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" +[[package]] +name = "scratch" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8132065adcfd6e02db789d9285a0deb2f3fcb04002865ab67d5fb103533898" + [[package]] name = "sctk-adwaita" version = "0.4.3" @@ -3725,6 +3824,17 @@ dependencies = [ "weezl", ] +[[package]] +name = "time" +version = "0.1.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6db9e6914ab8b1ae1c260a4ae7a49b6c5611b40328a735b21862567685e73255" +dependencies = [ + "libc", + "wasi 0.10.0+wasi-snapshot-preview1", + "winapi", +] + [[package]] name = "tiny-skia" version = "0.7.0" @@ -3976,6 +4086,12 @@ version = "0.9.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" +[[package]] +name = "wasi" +version = "0.10.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f" + [[package]] name = "wasi" version = "0.11.0+wasi-snapshot-preview1" diff --git a/Cargo.toml b/Cargo.toml index 98d4133..ffc3b41 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,6 +14,7 @@ image = "0.24.1" tiff = "0.7.4" imageproc = "0.23" rfd = "0.10" +chrono = "0.4.23" # Interacting with clipboard arboard = "3.2.0" diff --git a/src/camera.rs b/src/camera.rs index 230b2e1..54253bb 100644 --- a/src/camera.rs +++ b/src/camera.rs @@ -18,6 +18,7 @@ use bevy::{ window::{WindowId, WindowResized}, }; use bevy_egui::EguiContext; +use image::RgbaImage; use crate::{ image_copy::{ImageCopier, ImageCopyPlugin}, @@ -51,7 +52,7 @@ impl Plugin for CameraPlugin { // .after(UiLabel::Display), ) .add_system(ui_changed) - .add_system(copy_to_clipboard.before("issue_camera_commands")) // This should be before handling camera events, to force it to be run on the next frame - otherwise the screenshot is empty + .add_system(save_view_to_target.before("issue_camera_commands")) // This should be before handling camera events, to force it to be run on the next frame - otherwise the screenshot is empty .add_system_to_stage(CoreStage::Update, update_camera) .add_system(issue_camera_commands.label("issue_camera_commands")) .add_system( @@ -213,7 +214,7 @@ fn issue_camera_commands( } } -fn copy_to_clipboard( +fn save_view_to_target( mut commands: Commands, q_copier: Query<(Entity, &ImageCopier, &SaveToTarget)>, camera_setup: Res, @@ -272,7 +273,16 @@ fn copy_to_clipboard( }); } } - SaveToTarget::File(path) => {} + SaveToTarget::File(path) => { + if let Some(image) = RgbaImage::from_vec(size.x as u32, size.y as u32, data) { + if let Err(error) = image.save(path) { + commands.spawn(Message { + severity: Severity::Error, + message: error.to_string(), + }); + } + } + } } commands.entity(entity).despawn_recursive(); diff --git a/src/ui/mod.rs b/src/ui/mod.rs index d7817aa..5a9f6ca 100644 --- a/src/ui/mod.rs +++ b/src/ui/mod.rs @@ -10,6 +10,7 @@ use bevy_egui::{ }, EguiContext, EguiPlugin, EguiSettings, }; +use chrono::{DateTime, Datelike, Local, Timelike, Utc}; use imc_rs::ChannelIdentifier; use crate::{ @@ -847,7 +848,20 @@ fn ui_camera_panel(world: &mut World, ui: &mut Ui) { camera_events.push(CameraCommand::SaveTo(SaveToTarget::Clipboard)); } if ui.button("Save view as file").clicked() { + // let now = Utc::now(); + let now: DateTime = Local::now(); + let (is_common_era, year) = now.year_ce(); + if let Some(path) = rfd::FileDialog::new() + .set_file_name(&format!( + "{}-{:02}-{:02}_{}-{}-{}_biquinho-screenshot.tif", + year, + now.month(), + now.day(), + now.hour(), + now.minute(), + now.second() + )) .add_filter("TIFF (.tif, .tiff)", &["tif", "tiff"]) .add_filter("JPEG (.jpg, .jpeg)", &["jpg", "jpeg"]) .save_file()