Formating of code

This commit is contained in:
Piyush मिश्रः 2022-03-27 00:16:29 +05:30
parent 627912f89e
commit 231ab35f7b
11 changed files with 155 additions and 105 deletions

2
Cargo.lock generated
View File

@ -877,7 +877,7 @@ dependencies = [
[[package]] [[package]]
name = "post_maker" name = "post_maker"
version = "0.4.0-alpha.3" version = "0.4.0-alpha.4"
dependencies = [ dependencies = [
"clap", "clap",
"dirs", "dirs",

View File

@ -1,6 +1,6 @@
[package] [package]
name = "post_maker" name = "post_maker"
version = "0.4.0-alpha.3" version = "0.4.0-alpha.4"
edition = "2021" edition = "2021"
description = "Post Maker helps you to make post for Instagram and other Social Media apps easily." description = "Post Maker helps you to make post for Instagram and other Social Media apps easily."
authors = ["PiyushXCoder <https://piyushxcoder.in>"] authors = ["PiyushXCoder <https://piyushxcoder.in>"]
@ -23,7 +23,7 @@ simplelog = "0.11"
fltk = "1.2" fltk = "1.2"
fltk-theme = "0.4" fltk-theme = "0.4"
image = "0.24.1" image = "0.24.1"
imageproc = { git = "https://github.com/image-rs/imageproc"} imageproc = { git = "https://github.com/image-rs/imageproc" }
webp = "0.2" webp = "0.2"
rusttype = "0.9" rusttype = "0.9"
serde_json = "1.0" serde_json = "1.0"

View File

@ -167,7 +167,8 @@ impl About {
// License Link // License Link
self.license_link.handle(|_, ev| { self.license_link.handle(|_, ev| {
if ev == Event::Push { if ev == Event::Push {
webbrowser::open("https://www.gnu.org/licenses/gpl-3.0.html").warn_log("Failed to open the link!"); webbrowser::open("https://www.gnu.org/licenses/gpl-3.0.html")
.warn_log("Failed to open the link!");
} }
true true
}); });

View File

@ -13,9 +13,10 @@
*/ */
//! load, save configuration and parse cli args //! load, save configuration and parse cli args
use crate::{config_picker::ConfigPicker, globals, result_ext::ResultExt, utils::ImageType}; use crate::{
config_picker::ConfigPicker, dialog, globals, result_ext::ResultExt, utils::ImageType,
};
use clap::{ArgEnum, Parser}; use clap::{ArgEnum, Parser};
use crate::dialog;
use fltk_theme::ThemeType; use fltk_theme::ThemeType;
use lazy_static::lazy_static; use lazy_static::lazy_static;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
@ -211,7 +212,8 @@ pub(crate) fn get_configs() -> Option<HashMap<String, ConfigFile>> {
/// Save configs /// Save configs
pub(crate) fn save_configs(configs: HashMap<String, ConfigFile>) { pub(crate) fn save_configs(configs: HashMap<String, ConfigFile>) {
std::fs::write(&*CONFIG_FILE, serde_json::to_string(&configs).unwrap()).expect_log("Can't write config!"); std::fs::write(&*CONFIG_FILE, serde_json::to_string(&configs).unwrap())
.expect_log("Can't write config!");
} }
pub(crate) fn log_file() -> File { pub(crate) fn log_file() -> File {

View File

@ -14,9 +14,11 @@
//! Window to edit configuration //! Window to edit configuration
use std::{cell::RefCell, collections::HashMap, rc::Rc}; use crate::{
use crate::dialog; config::{self, ConfigFile},
dialog, globals,
utils::{self, ImageType},
};
use fltk::{ use fltk::{
app, app,
browser::{Browser, BrowserType}, browser::{Browser, BrowserType},
@ -31,11 +33,7 @@ use fltk::{
valuator::ValueInput, valuator::ValueInput,
window::Window, window::Window,
}; };
use std::{cell::RefCell, collections::HashMap, rc::Rc};
use crate::{
config::{self, ConfigFile},
globals, utils::{self, ImageType},
};
pub(crate) struct ConfigWindow { pub(crate) struct ConfigWindow {
pub(crate) win: Window, pub(crate) win: Window,
@ -378,15 +376,10 @@ impl ConfigWindow {
image_ratio_grp.end(); image_ratio_grp.end();
col.set_size(&image_ratio_grp, 30); col.set_size(&image_ratio_grp, 30);
let mut label = Frame::default().with_label("Image with limits:"); let mut label = Frame::default().with_label("Image with limits:");
label.set_label_font(enums::Font::HelveticaBold); label.set_label_font(enums::Font::HelveticaBold);
col.set_size(&label, 15); col.set_size(&label, 15);
let mut hint = let mut hint = Frame::default().with_label("Limiting width of image in pixels");
Frame::default().with_label("Limiting width of image in pixels");
hint.set_label_font(Font::CourierItalic); hint.set_label_font(Font::CourierItalic);
hint.set_label_size(12); hint.set_label_size(12);
col.set_size(&hint, 20); col.set_size(&hint, 20);
@ -423,10 +416,6 @@ impl ConfigWindow {
row_grp.end(); row_grp.end();
col.set_size(&row_grp, 40); col.set_size(&row_grp, 40);
let mut label = Frame::default().with_label("Colour for dark layer:"); let mut label = Frame::default().with_label("Colour for dark layer:");
label.set_label_font(enums::Font::HelveticaBold); label.set_label_font(enums::Font::HelveticaBold);
col.set_size(&label, 15); col.set_size(&label, 15);
@ -555,8 +544,10 @@ impl ConfigWindow {
.set_value(config.tag2_position_ratio); .set_value(config.tag2_position_ratio);
self.image_ratio_width.set_value(config.image_ratio.0); self.image_ratio_width.set_value(config.image_ratio.0);
self.image_ratio_height.set_value(config.image_ratio.1); self.image_ratio_height.set_value(config.image_ratio.1);
self.minimum_width_limit.set_value(config.minimum_width_limit); self.minimum_width_limit
self.maximum_width_limit.set_value(config.maximum_width_limit); .set_value(config.minimum_width_limit);
self.maximum_width_limit
.set_value(config.maximum_width_limit);
utils::set_color_btn_rgba(config.color_layer, &mut self.translucent_layer_rgb); utils::set_color_btn_rgba(config.color_layer, &mut self.translucent_layer_rgb);
self.translucent_layer_alpha self.translucent_layer_alpha
.set_value(config.color_layer[3] as f64); .set_value(config.color_layer[3] as f64);

View File

@ -15,7 +15,7 @@
//! Window to change Crop properties of image //! Window to change Crop properties of image
use crate::{ use crate::{
globals, globals,
utils::{self, Coord, ImageContainer, ImageProperties, ImageInfo}, utils::{self, Coord, ImageContainer, ImageInfo, ImageProperties},
}; };
use fltk::{ use fltk::{
app, button::Button, draw, enums::Event, frame::Frame, group::Flex, image::SvgImage, app, button::Button, draw, enums::Event, frame::Frame, group::Flex, image::SvgImage,

View File

@ -1,24 +1,22 @@
use fltk::dialog; pub(crate) use fltk::dialog::{color_chooser_with_default, ColorMode};
use fltk::app::get_mouse; use fltk::{app::get_mouse, dialog};
pub(crate) use dialog::color_chooser_with_default;
pub(crate) use dialog::ColorMode;
pub(crate) fn input_default(txt: &str, deflt: &str) -> Option<String> { pub(crate) fn input_default(txt: &str, deflt: &str) -> Option<String> {
let (x,y) = get_mouse(); let (x, y) = get_mouse();
dialog::input(x, y, txt, deflt) dialog::input(x, y, txt, deflt)
} }
pub(crate) fn alert_default(txt: &str) { pub(crate) fn alert_default(txt: &str) {
let (x,y) = get_mouse(); let (x, y) = get_mouse();
dialog::alert(x, y, txt) dialog::alert(x, y, txt)
} }
pub(crate) fn message_default(txt: &str) { pub(crate) fn message_default(txt: &str) {
let (x,y) = get_mouse(); let (x, y) = get_mouse();
dialog::message(x, y, txt) dialog::message(x, y, txt)
} }
pub(crate) fn choice_default(txt: &str, b0: &str, b1: &str) -> i32 { pub(crate) fn choice_default(txt: &str, b0: &str, b1: &str) -> i32 {
let (x,y) = get_mouse(); let (x, y) = get_mouse();
dialog::choice(x, y, txt, b0, b1, "") dialog::choice(x, y, txt, b0, b1, "")
} }

View File

@ -14,12 +14,11 @@
//! Thread to manage drawing in background //! Thread to manage drawing in background
use crate::globals;
use crate::result_ext::ResultExt;
use crate::utils::{ImageContainer, ImageProperties, ImageInfo};
use crate::{ use crate::{
globals,
main_window::{MainWindow, Page}, main_window::{MainWindow, Page},
utils::{self, ImagePropertiesFile}, result_ext::ResultExt,
utils::{self, ImageContainer, ImageInfo, ImageProperties, ImagePropertiesFile},
AppMessage, AppMessage,
}; };
use fltk::{ use fltk::{
@ -57,7 +56,7 @@ pub(crate) enum DrawMessage {
/// Show details about images linke count of quotes /// Show details about images linke count of quotes
ShowImagesDetails, ShowImagesDetails,
/// Check If image is proper /// Check If image is proper
CheckImage CheckImage,
} }
/// Spawn thread to manage all actions related to image, like: edit, save, delete /// Spawn thread to manage all actions related to image, like: edit, save, delete
@ -222,9 +221,7 @@ pub(crate) fn spawn_image_thread(
app::awake(); app::awake();
} }
} }
DrawMessage::ShowImagesDetails => { DrawMessage::ShowImagesDetails => show_images_details(Arc::clone(&images_list)),
show_images_details(Arc::clone(&images_list))
}
DrawMessage::CheckImage => { DrawMessage::CheckImage => {
let (width, height) = properties.read().unwrap().original_dimension; let (width, height) = properties.read().unwrap().original_dimension;
if utils::is_too_small(width, height) { if utils::is_too_small(width, height) {
@ -286,8 +283,9 @@ fn load_image(
let read = match serde_json::from_str::<ImagePropertiesFile>(&read) { let read = match serde_json::from_str::<ImagePropertiesFile>(&read) {
Ok(r) => r, Ok(r) => r,
Err(e) => { Err(e) => {
Result::<(),_>::Err(e).warn_log("Config is corrupt"); Result::<(), _>::Err(e).warn_log("Config is corrupt");
fs::remove_file(&properties_file).warn_log("Failed to delete image properties file!"); fs::remove_file(&properties_file)
.warn_log("Failed to delete image properties file!");
ImagePropertiesFile::default() ImagePropertiesFile::default()
} }
}; };
@ -379,12 +377,15 @@ fn show_images_details(images_list: Arc<RwLock<Vec<ImageInfo>>>) {
} else { } else {
image_with_quote += 1; image_with_quote += 1;
} }
}else { } else {
image_without_quote += 1; image_without_quote += 1;
} }
} }
utils::show_message(&format!("With Quote: {}\nWithout Quote: {}", image_with_quote, image_without_quote)); utils::show_message(&format!(
"With Quote: {}\nWithout Quote: {}",
image_with_quote, image_without_quote
));
} }
/// Flush the Buffer from image container to drawing buffer for fltk /// Flush the Buffer from image container to drawing buffer for fltk

View File

@ -13,16 +13,16 @@
*/ */
//! Main window where you do all editing //! Main window where you do all editing
use crate::about_window::About; use crate::{
use crate::crop_window::CropWindow; about_window::About,
use crate::draw_thread::*; config_window::ConfigWindow,
use crate::result_ext::ResultExt; crop_window::CropWindow,
use crate::utils; dialog,
use crate::utils::ImageInfo; draw_thread::*,
use crate::utils::ImageType; globals,
use crate::utils::ImageProperties; result_ext::ResultExt,
use crate::{config_window::ConfigWindow, globals}; utils::{self, ImageInfo, ImageProperties, ImageType},
use crate::dialog; };
use fltk::{ use fltk::{
button::Button, button::Button,
dialog::NativeFileChooser, dialog::NativeFileChooser,
@ -38,10 +38,13 @@ use fltk::{
valuator::{Slider, SliderType}, valuator::{Slider, SliderType},
window::Window, window::Window,
}; };
use std::ffi::OsStr; use std::{
use std::path::PathBuf; ffi::OsStr,
use std::sync::{mpsc, RwLock}; fs,
use std::{ fs, sync::Arc}; path::PathBuf,
sync::Arc,
sync::{mpsc, RwLock},
};
pub(crate) struct MainWindow { pub(crate) struct MainWindow {
pub(crate) win: Window, pub(crate) win: Window,
@ -430,7 +433,12 @@ impl MainWindow {
return; return;
} }
} }
win.set_label(&format!("{} - Post Maker", path.file_name().unwrap_or(OsStr::new("Unknown")).to_string_lossy())); win.set_label(&format!(
"{} - Post Maker",
path.file_name()
.unwrap_or(OsStr::new("Unknown"))
.to_string_lossy()
));
load_dir(&path, Arc::clone(&imgs), &mut file_choice, &sender); load_dir(&path, Arc::clone(&imgs), &mut file_choice, &sender);
}, },
); );
@ -1047,7 +1055,10 @@ fn load_dir(
ImageType::None => (), ImageType::None => (),
_ => { _ => {
text = format!("{}|{}", text, path.file_name().unwrap().to_str().unwrap()); text = format!("{}|{}", text, path.file_name().unwrap().to_str().unwrap());
imgs_b.push(ImageInfo { path, image_type: ImageType::from_mime(mime) }); imgs_b.push(ImageInfo {
path,
image_type: ImageType::from_mime(mime),
});
} }
} }
} }

View File

@ -1,5 +1,4 @@
use std::fmt::Debug; use std::{fmt::Debug, panic::Location};
use std::panic::Location;
use crate::utils; use crate::utils;

View File

@ -14,16 +14,17 @@
use std::{ use std::{
fs::{self, File}, fs::{self, File},
io::Read,
path::{Path, PathBuf}, path::{Path, PathBuf},
sync::{Arc, RwLock}, io::Read sync::{Arc, RwLock},
}; };
use fltk::{button::Button, enums, prelude::*}; use fltk::{button::Button, enums, prelude::*};
use image::{DynamicImage, GenericImageView, ImageBuffer, ImageEncoder}; use image::{DynamicImage, GenericImageView, ImageBuffer, ImageEncoder};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use crate::result_ext::ResultExt;
use crate::globals; use crate::globals;
use crate::result_ext::ResultExt;
/// helps cast tupels to f64 /// helps cast tupels to f64
pub(crate) struct Coord(pub(crate) f64, pub(crate) f64); pub(crate) struct Coord(pub(crate) f64, pub(crate) f64);
@ -64,7 +65,6 @@ impl Into<(i32, i32)> for Coord {
} }
} }
impl Into<(usize, usize)> for Coord { impl Into<(usize, usize)> for Coord {
fn into(self) -> (usize, usize) { fn into(self) -> (usize, usize) {
(self.0 as usize, self.1 as usize) (self.0 as usize, self.1 as usize)
@ -74,7 +74,7 @@ impl Into<(usize, usize)> for Coord {
#[derive(Serialize, Deserialize, Debug, Clone)] #[derive(Serialize, Deserialize, Debug, Clone)]
pub(crate) struct ImageInfo { pub(crate) struct ImageInfo {
pub(crate) path: PathBuf, pub(crate) path: PathBuf,
pub(crate) image_type: ImageType pub(crate) image_type: ImageType,
} }
#[derive(Serialize, Deserialize, Debug, Clone)] #[derive(Serialize, Deserialize, Debug, Clone)]
@ -82,7 +82,7 @@ pub(crate) enum ImageType {
Jpeg, Jpeg,
Png, Png,
Webp, Webp,
None None,
} }
impl ImageType { impl ImageType {
@ -91,7 +91,7 @@ impl ImageType {
"image/jpeg" | "image/jpg" => Self::Jpeg, "image/jpeg" | "image/jpg" => Self::Jpeg,
"image/png" => Self::Png, "image/png" => Self::Png,
"image/webp" => Self::Webp, "image/webp" => Self::Webp,
_ => Self::None _ => Self::None,
} }
} }
@ -100,8 +100,9 @@ impl ImageType {
Self::Jpeg => "jpg", Self::Jpeg => "jpg",
Self::Png => "png", Self::Png => "png",
Self::Webp => "webp", Self::Webp => "webp",
Self::None => "none" Self::None => "none",
}.to_owned() }
.to_owned()
} }
} }
@ -221,7 +222,11 @@ impl ImageContainer {
let prop = self.properties.read().unwrap(); let prop = self.properties.read().unwrap();
let image_info = &prop.image_info; let image_info = &prop.image_info;
let (export_path, path_properties, mut original_image) = match image_info { let (export_path, path_properties, mut original_image) = match image_info {
Some(p) => (get_export_image_path(p), get_properties_path(p), load_image(p)), Some(p) => (
get_export_image_path(p),
get_properties_path(p),
load_image(p),
),
None => return, None => return,
}; };
let config = globals::CONFIG.read().unwrap(); let config = globals::CONFIG.read().unwrap();
@ -229,7 +234,11 @@ impl ImageContainer {
let mut prop = prop.clone(); let mut prop = prop.clone();
prop.image_info = None; prop.image_info = None;
fs::write(&path_properties, serde_json::to_string(&ImagePropertiesFile::from(&prop)).unwrap()).warn_log("Failed to save properties!"); fs::write(
&path_properties,
serde_json::to_string(&ImagePropertiesFile::from(&prop)).unwrap(),
)
.warn_log("Failed to save properties!");
let (width, height): (f64, f64) = Coord::from(original_image.dimensions()).into(); let (width, height): (f64, f64) = Coord::from(original_image.dimensions()).into();
let (crop_x, crop_y) = prop.crop_position.unwrap(); let (crop_x, crop_y) = prop.crop_position.unwrap();
@ -242,8 +251,15 @@ impl ImageContainer {
); );
if crop_width > config.maximum_width_limit { if crop_width > config.maximum_width_limit {
let (resize_width,resize_height) = (config.maximum_width_limit, height_from_width(config.maximum_width_limit)); let (resize_width, resize_height) = (
img = img.resize_exact(resize_width as u32,resize_height as u32, image::imageops::FilterType::Lanczos3); config.maximum_width_limit,
height_from_width(config.maximum_width_limit),
);
img = img.resize_exact(
resize_width as u32,
resize_height as u32,
image::imageops::FilterType::Lanczos3,
);
} }
draw_layer_and_text( draw_layer_and_text(
@ -275,11 +291,13 @@ impl ImageContainer {
let encoder = image::codecs::png::PngEncoder::new_with_quality( let encoder = image::codecs::png::PngEncoder::new_with_quality(
&mut output, &mut output,
image::codecs::png::CompressionType::Best, image::codecs::png::CompressionType::Best,
image::codecs::png::FilterType::Sub image::codecs::png::FilterType::Sub,
); );
let (w, h) = img.dimensions(); let (w, h) = img.dimensions();
encoder.write_image(&img.into_rgba8(), w, h, image::ColorType::Rgba8).warn_log("Failed to export Image!"); encoder
.write_image(&img.into_rgba8(), w, h, image::ColorType::Rgba8)
.warn_log("Failed to export Image!");
} }
ImageType::Jpeg => { ImageType::Jpeg => {
let (width, height) = Coord::from(img.dimensions()).into(); let (width, height) = Coord::from(img.dimensions()).into();
@ -298,8 +316,10 @@ impl ImageContainer {
comp.finish_compress(); comp.finish_compress();
match comp.data_to_vec() { match comp.data_to_vec() {
Ok(data) => std::fs::write(&export_path, data).warn_log("Failed to export Image!"), Ok(data) => {
Err(e) => Result::<(), _>::Err(e).warn_log("Failed to encode image!") std::fs::write(&export_path, data).warn_log("Failed to export Image!")
}
Err(e) => Result::<(), _>::Err(e).warn_log("Failed to encode image!"),
} }
} }
_ => (), _ => (),
@ -325,11 +345,13 @@ impl ImageContainer {
let path_properties_new = get_properties_path(&new_image_info); let path_properties_new = get_properties_path(&new_image_info);
if image_info.path.exists() { if image_info.path.exists() {
fs::copy(&image_info.path, &new_image_info.path).warn_log("Failed to clone image!"); fs::copy(&image_info.path, &new_image_info.path)
.warn_log("Failed to clone image!");
} }
if path_properties.exists() { if path_properties.exists() {
fs::copy(path_properties, &path_properties_new).warn_log("Failed to clone image properties!"); fs::copy(path_properties, &path_properties_new)
.warn_log("Failed to clone image properties!");
} }
Some(new_image_info) Some(new_image_info)
} }
@ -342,7 +364,11 @@ impl ImageContainer {
let image_info = &prop.image_info; let image_info = &prop.image_info;
let (export_path, path_image, path_properties) = match image_info { let (export_path, path_image, path_properties) = match image_info {
Some(p) => (get_export_image_path(p), Path::new(&p.path), get_properties_path(p)), Some(p) => (
get_export_image_path(p),
Path::new(&p.path),
get_properties_path(p),
),
None => return, None => return,
}; };
@ -490,7 +516,10 @@ fn load_image(image_info: &ImageInfo) -> DynamicImage {
let mut f = File::open(&image_info.path).expect_log("Failed to open image!"); let mut f = File::open(&image_info.path).expect_log("Failed to open image!");
let mut buf = vec![]; let mut buf = vec![];
f.read_to_end(&mut buf).expect_log("Failed to read image!"); f.read_to_end(&mut buf).expect_log("Failed to read image!");
let a = webp::Decoder::new(&buf).decode().ok_or("").expect_log("Failed to decode image!"); let a = webp::Decoder::new(&buf)
.decode()
.ok_or("")
.expect_log("Failed to decode image!");
a.to_image() a.to_image()
} }
ImageType::Jpeg => { ImageType::Jpeg => {
@ -498,15 +527,20 @@ fn load_image(image_info: &ImageInfo) -> DynamicImage {
let mut buf = vec![]; let mut buf = vec![];
f.read_to_end(&mut buf).expect_log("Failed to read image!"); f.read_to_end(&mut buf).expect_log("Failed to read image!");
let d = mozjpeg::Decompress::with_markers(mozjpeg::ALL_MARKERS).from_mem(&buf) let d = mozjpeg::Decompress::with_markers(mozjpeg::ALL_MARKERS)
.from_mem(&buf)
.expect_log("Failed to decompress image!"); .expect_log("Failed to decompress image!");
let mut image = d.rgb().expect_log("Failed to covert to rgb image!"); let mut image = d.rgb().expect_log("Failed to covert to rgb image!");
let pixels = image.read_scanlines_flat().unwrap(); let pixels = image.read_scanlines_flat().unwrap();
let image = ImageBuffer::from_raw(image.width() as u32, image.height() as u32, pixels).unwrap(); let image =
ImageBuffer::from_raw(image.width() as u32, image.height() as u32, pixels).unwrap();
DynamicImage::ImageRgb8(image) DynamicImage::ImageRgb8(image)
} }
ImageType::Png => { ImageType::Png => {
let dec = image::codecs::png::PngDecoder::new(File::open(&image_info.path).expect_log("Failed to open image!")).expect_log("Failed to decode image!"); let dec = image::codecs::png::PngDecoder::new(
File::open(&image_info.path).expect_log("Failed to open image!"),
)
.expect_log("Failed to decode image!");
DynamicImage::from_decoder(dec).expect_log("Failed to open image!") DynamicImage::from_decoder(dec).expect_log("Failed to open image!")
} }
ImageType::None => { ImageType::None => {
@ -659,11 +693,9 @@ pub(crate) fn get_properties_path(image_info: &ImageInfo) -> PathBuf {
let path = img.with_extension("prop"); let path = img.with_extension("prop");
if path.exists() { if path.exists() {
match std::fs::copy(&path, &default_path){ match std::fs::copy(&path, &default_path) {
Ok(_) => { Ok(_) => std::fs::remove_file(&path).warn_log("Failed to delete depricated prop file"),
std::fs::remove_file(&path).warn_log("Failed to delete depricated prop file") Err(e) => Result::<(), _>::Err(e).warn_log("Failed to copy depricated prop file"),
}
Err(e) => Result::<(), _>::Err(e).warn_log("Failed to copy depricated prop file")
} }
} }
@ -674,9 +706,24 @@ pub(crate) fn get_properties_path(image_info: &ImageInfo) -> PathBuf {
pub(crate) fn get_export_image_path(image_info: &ImageInfo) -> PathBuf { pub(crate) fn get_export_image_path(image_info: &ImageInfo) -> PathBuf {
let config = globals::CONFIG.read().unwrap(); let config = globals::CONFIG.read().unwrap();
let export_format = &config.image_format; let export_format = &config.image_format;
let mut export = image_info.path.parent().unwrap().join("export") let mut export = image_info
.join(format!("{}-{}", image_info.path.file_stem().unwrap_or_default().to_string_lossy(), .path
image_info.path.extension().unwrap_or_default().to_string_lossy())); .parent()
.unwrap()
.join("export")
.join(format!(
"{}-{}",
image_info
.path
.file_stem()
.unwrap_or_default()
.to_string_lossy(),
image_info
.path
.extension()
.unwrap_or_default()
.to_string_lossy()
));
export.set_extension(export_format.as_extension()); export.set_extension(export_format.as_extension());
export export
} }