Upgrade dependencies and use fast_image_resize
This commit is contained in:
parent
83fa2c6864
commit
4c598da07a
3 changed files with 1308 additions and 686 deletions
1908
Cargo.lock
generated
1908
Cargo.lock
generated
File diff suppressed because it is too large
Load diff
11
Cargo.toml
11
Cargo.toml
|
@ -7,14 +7,15 @@ edition = "2021"
|
|||
anyhow = "1.0"
|
||||
log = "0.4"
|
||||
simplelog = "0.12"
|
||||
wry = "0.20"
|
||||
wry = "0.27"
|
||||
native-dialog = "0.6"
|
||||
rust-embed = "6"
|
||||
base64 = "0.13"
|
||||
directories = "4"
|
||||
clap = "3"
|
||||
base64 = "0.21"
|
||||
directories = "5"
|
||||
clap = "4"
|
||||
warp = "0.3"
|
||||
tokio = { version = "1", features = ["full"] }
|
||||
image = "0.24"
|
||||
rexiv2 = "0.9"
|
||||
rexiv2 = "0.10"
|
||||
tempfile = "3"
|
||||
fast_image_resize = "2"
|
73
src/main.rs
73
src/main.rs
|
@ -1,14 +1,15 @@
|
|||
#![windows_subsystem = "windows"]
|
||||
|
||||
use anyhow::{anyhow, Result};
|
||||
use base64::Engine;
|
||||
use clap::{Arg, Command};
|
||||
use image::{imageops::FilterType, io::Reader as ImageReader};
|
||||
use image::{io::Reader as ImageReader, DynamicImage};
|
||||
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 std::{fs::File, io::BufWriter, path::PathBuf, thread::JoinHandle, num::NonZeroU32};
|
||||
use tempfile::tempdir;
|
||||
use warp::Filter;
|
||||
use wry::{
|
||||
|
@ -19,6 +20,7 @@ use wry::{
|
|||
},
|
||||
webview::WebViewBuilder,
|
||||
};
|
||||
use fast_image_resize as fr;
|
||||
|
||||
#[derive(RustEmbed)]
|
||||
#[folder = "embed/"]
|
||||
|
@ -39,15 +41,11 @@ fn main() -> Result<()> {
|
|||
let tmp_dir = tempdir()?;
|
||||
|
||||
let cmd = Command::new("Simple panorama viewer")
|
||||
.arg(
|
||||
Arg::new("filename")
|
||||
.allow_invalid_utf8(true)
|
||||
.help("Image path"),
|
||||
)
|
||||
.arg(Arg::new("filename").value_parser(clap::value_parser!(PathBuf)).help("Image path"))
|
||||
.get_matches();
|
||||
|
||||
let img_path = if let Some(img_path) = cmd.value_of_os("filename") {
|
||||
PathBuf::from(img_path)
|
||||
let img_path = if let Some(img_path) = cmd.get_one::<PathBuf>("filename") {
|
||||
img_path.clone()
|
||||
} else {
|
||||
let user_dirs = directories::UserDirs::new().unwrap();
|
||||
let dir = if let Some(img_dir) = user_dirs.picture_dir() {
|
||||
|
@ -72,7 +70,7 @@ fn main() -> Result<()> {
|
|||
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 Option pas de resize / taille dans une config (confy)
|
||||
// @todo Icon
|
||||
let ratio = (height * width) as f64 / MAX_IMG_SIZE as f64;
|
||||
let new_height = (height as f64 / ratio.sqrt()) as u32;
|
||||
|
@ -80,13 +78,16 @@ fn main() -> Result<()> {
|
|||
|
||||
if MessageDialog::new()
|
||||
.set_title("Resize")
|
||||
.set_text(&format!("Resize the file to {} × {}", new_width, new_height))
|
||||
.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);
|
||||
let image_resized = fast_image_resize(&img, new_width, new_height)?;
|
||||
|
||||
// Save file and add metadata
|
||||
let tmp_img_path = tmp_dir.path().join("img.jpg");
|
||||
|
@ -105,7 +106,7 @@ fn main() -> Result<()> {
|
|||
};
|
||||
let img_data = std::fs::read(&img_data_path)?;
|
||||
tmp_dir.close()?;
|
||||
let img_base_64 = base64::encode(img_data);
|
||||
let img_base_64 = base64::engine::general_purpose::STANDARD.encode(img_data);
|
||||
|
||||
info!("Generate HTML");
|
||||
let html = std::str::from_utf8(Embed::get("index.html").unwrap().data.as_ref())?
|
||||
|
@ -150,3 +151,49 @@ fn run_server(html: String) -> JoinHandle<()> {
|
|||
async_runtime.block_on(warp::serve(hello).run(([127, 0, 0, 1], 62371)));
|
||||
})
|
||||
}
|
||||
|
||||
/// Fast resize
|
||||
pub fn fast_image_resize(
|
||||
img: &DynamicImage,
|
||||
max_width: u32,
|
||||
max_height: u32,
|
||||
) -> Result<DynamicImage> {
|
||||
// Create source image
|
||||
let width = NonZeroU32::new(img.width()).unwrap();
|
||||
let height = NonZeroU32::new(img.height()).unwrap();
|
||||
let src_image =
|
||||
fr::Image::from_vec_u8(width, height, img.to_rgb8().into_raw(), fr::PixelType::U8x3)?;
|
||||
let mut src_view = src_image.view();
|
||||
|
||||
// Create container for data of destination image
|
||||
let (dst_width, dst_height) = if width > height {
|
||||
(
|
||||
NonZeroU32::new(max_width).unwrap(),
|
||||
NonZeroU32::new((max_width * img.height()) / img.width()).unwrap(),
|
||||
)
|
||||
} else {
|
||||
(
|
||||
NonZeroU32::new((max_height * img.width()) / img.height()).unwrap(),
|
||||
NonZeroU32::new(max_height).unwrap(),
|
||||
)
|
||||
};
|
||||
src_view.set_crop_box_to_fit_dst_size(dst_width, dst_height, None);
|
||||
let mut dst_image = fr::Image::new(dst_width, dst_height, src_view.pixel_type());
|
||||
|
||||
// Get mutable view of destination image data
|
||||
let mut dst_view = dst_image.view_mut();
|
||||
|
||||
// Create Resizer instance and resize source image into buffer of destination image
|
||||
let mut resizer = fr::Resizer::new(fr::ResizeAlg::Convolution(fr::FilterType::Lanczos3));
|
||||
resizer.resize(&src_view, &mut dst_view)?;
|
||||
|
||||
// Create Dynamic image
|
||||
let img_buffer = image::RgbImage::from_raw(
|
||||
dst_image.width().get(),
|
||||
dst_image.height().get(),
|
||||
dst_image.into_vec(),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
Ok(img_buffer.into())
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue