SimplePanoramaViewer/src/main.rs

153 lines
4.8 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#![windows_subsystem = "windows"]
use anyhow::{anyhow, Result};
use clap::{Arg, Command};
use image::{imageops::FilterType, io::Reader as ImageReader};
use log::info;
use native_dialog::{FileDialog, MessageDialog};
use rexiv2::Metadata;
use rust_embed::RustEmbed;
use simplelog::{ColorChoice, ConfigBuilder, LevelFilter, TermLogger, TerminalMode};
use std::{fs::File, io::BufWriter, path::PathBuf, thread::JoinHandle};
use tempfile::tempdir;
use warp::Filter;
use wry::{
application::{
event::{Event, StartCause, WindowEvent},
event_loop::{ControlFlow, EventLoop},
window::WindowBuilder,
},
webview::WebViewBuilder,
};
#[derive(RustEmbed)]
#[folder = "embed/"]
struct Embed;
fn main() -> Result<()> {
// Init log
TermLogger::init(
LevelFilter::Info,
ConfigBuilder::new()
.set_time_offset_to_local()
.unwrap()
.build(),
TerminalMode::Mixed,
ColorChoice::Auto,
)?;
let tmp_dir = tempdir()?;
let cmd = Command::new("Simple panorama viewer")
.arg(
Arg::new("filename")
.allow_invalid_utf8(true)
.help("Image path"),
)
.get_matches();
let img_path = if let Some(img_path) = cmd.value_of_os("filename") {
PathBuf::from(img_path)
} else {
let user_dirs = directories::UserDirs::new().unwrap();
let dir = if let Some(img_dir) = user_dirs.picture_dir() {
img_dir
} else {
user_dirs.home_dir()
};
FileDialog::new()
.add_filter(
"Images",
&[
"jpg", "JPG", "jpeg", "pjpeg", "pjpg", "PJPG", "webp", "avif",
],
)
.set_location(dir)
.show_open_single_file()?
.ok_or_else(|| anyhow!("No file"))?
};
info!("Open `{}`", img_path.display());
let (width, height) = image::image_dimensions(&img_path)?;
const MAX_IMG_SIZE: u32 = 20_000_000;
let img_data_path = if height * width > MAX_IMG_SIZE {
// @todo Option pas de resize / taille en ligne de commande
// @todo Option pas de resize / taille dans une config
// @todo Icon
let ratio = (height * width) as f64 / MAX_IMG_SIZE as f64;
let new_height = (height as f64 / ratio.sqrt()) as u32;
let new_width = (width as f64 / ratio.sqrt()) as u32;
if MessageDialog::new()
.set_title("Resize")
.set_text(&format!("Resize the file to {} × {}", new_width, new_height))
.show_confirm()?
{
// Resize image
let img = ImageReader::open(&img_path)?.decode()?;
info!("Resize image to {} × {}", new_width, new_height);
let image_resized = img.resize(new_width, new_height, FilterType::Triangle);
// Save file and add metadata
let tmp_img_path = tmp_dir.path().join("img.jpg");
image_resized.write_to(
&mut BufWriter::new(File::create(&tmp_img_path)?),
image::ImageOutputFormat::Jpeg(95),
)?;
let metadata = Metadata::new_from_path(&img_path)?;
metadata.save_to_file(&tmp_img_path)?;
tmp_img_path
} else {
img_path
}
} else {
img_path
};
let img_data = std::fs::read(&img_data_path)?;
tmp_dir.close()?;
let img_base_64 = base64::encode(img_data);
info!("Generate HTML");
let html = std::str::from_utf8(Embed::get("index.html").unwrap().data.as_ref())?
.replace("__BASE_64_IMG__", &img_base_64);
run_server(html);
info!("Create webview");
let event_loop = EventLoop::new();
let window = WindowBuilder::new()
.with_title("Simple panorama viewer")
.with_maximized(true)
.build(&event_loop)?;
let _webview = WebViewBuilder::new(window)?
.with_url("http://127.0.0.1:62371")?
.build()?;
info!("Event loop");
event_loop.run(move |event, _, control_flow| {
*control_flow = ControlFlow::Wait;
match event {
Event::NewEvents(StartCause::Init) => info!("Panorama open"),
Event::WindowEvent {
event: WindowEvent::CloseRequested,
..
} => {
info!("Close");
*control_flow = ControlFlow::Exit
}
_ => (),
}
});
}
fn run_server(html: String) -> JoinHandle<()> {
std::thread::spawn(|| {
let async_runtime = tokio::runtime::Builder::new_current_thread()
.enable_all()
.build()
.unwrap();
let hello = warp::any().map(move || warp::reply::html(html.clone()));
async_runtime.block_on(warp::serve(hello).run(([127, 0, 0, 1], 62371)));
})
}