tons of stuffs, specially fltk comps in thread and loading images from other thread
This commit is contained in:
parent
887d5d9e58
commit
a5b4b84eec
|
|
@ -0,0 +1,45 @@
|
||||||
|
{
|
||||||
|
// Use IntelliSense to learn about possible attributes.
|
||||||
|
// Hover to view descriptions of existing attributes.
|
||||||
|
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
||||||
|
"version": "0.2.0",
|
||||||
|
"configurations": [
|
||||||
|
{
|
||||||
|
"type": "lldb",
|
||||||
|
"request": "launch",
|
||||||
|
"name": "Debug executable 'post_maker'",
|
||||||
|
"cargo": {
|
||||||
|
"args": [
|
||||||
|
"build",
|
||||||
|
"--bin=post_maker",
|
||||||
|
"--package=post_maker"
|
||||||
|
],
|
||||||
|
"filter": {
|
||||||
|
"name": "post_maker",
|
||||||
|
"kind": "bin"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"args": [],
|
||||||
|
"cwd": "${workspaceFolder}"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "lldb",
|
||||||
|
"request": "launch",
|
||||||
|
"name": "Debug unit tests in executable 'post_maker'",
|
||||||
|
"cargo": {
|
||||||
|
"args": [
|
||||||
|
"test",
|
||||||
|
"--no-run",
|
||||||
|
"--bin=post_maker",
|
||||||
|
"--package=post_maker"
|
||||||
|
],
|
||||||
|
"filter": {
|
||||||
|
"name": "post_maker",
|
||||||
|
"kind": "bin"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"args": [],
|
||||||
|
"cwd": "${workspaceFolder}"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
@ -556,6 +556,7 @@ dependencies = [
|
||||||
"fltk-theme",
|
"fltk-theme",
|
||||||
"image",
|
"image",
|
||||||
"imageproc",
|
"imageproc",
|
||||||
|
"lazy_static",
|
||||||
"rusttype",
|
"rusttype",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
|
|
|
||||||
|
|
@ -14,3 +14,4 @@ imageproc = "0.22"
|
||||||
rusttype = "0.9"
|
rusttype = "0.9"
|
||||||
serde_json = "1.0"
|
serde_json = "1.0"
|
||||||
serde = { version = "1.0", features = ["derive"] }
|
serde = { version = "1.0", features = ["derive"] }
|
||||||
|
lazy_static = "1.4"
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,182 @@
|
||||||
|
use crate::{
|
||||||
|
main_window::{MainWindow, Page},
|
||||||
|
AppMessage,
|
||||||
|
};
|
||||||
|
use fltk::{
|
||||||
|
app,
|
||||||
|
input::{Input, MultilineInput},
|
||||||
|
menu,
|
||||||
|
misc::Spinner,
|
||||||
|
prelude::*,
|
||||||
|
};
|
||||||
|
|
||||||
|
use std::{
|
||||||
|
fs,
|
||||||
|
path::Path,
|
||||||
|
sync::{mpsc, Arc, RwLock},
|
||||||
|
};
|
||||||
|
|
||||||
|
use crate::utils::{ImageContainer, ImageProperties};
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub(crate) enum DrawMessage {
|
||||||
|
Open,
|
||||||
|
Recalc,
|
||||||
|
Flush,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn spawn_image_thread(
|
||||||
|
reciver: mpsc::Receiver<DrawMessage>,
|
||||||
|
app_sender: app::Sender<crate::AppMessage>,
|
||||||
|
properties: Arc<RwLock<ImageProperties>>,
|
||||||
|
main_win: &MainWindow,
|
||||||
|
) {
|
||||||
|
let mut file_choice = main_win.file_choice.clone();
|
||||||
|
let mut quote = main_win.quote.clone();
|
||||||
|
let mut tag = main_win.tag.clone();
|
||||||
|
let mut layer_red = main_win.layer_red.clone();
|
||||||
|
let mut layer_green = main_win.layer_green.clone();
|
||||||
|
let mut layer_blue = main_win.layer_blue.clone();
|
||||||
|
let mut layer_alpha = main_win.layer_alpha.clone();
|
||||||
|
let mut quote_position = main_win.quote_position.clone();
|
||||||
|
let mut tag_position = main_win.tag_position.clone();
|
||||||
|
let mut page = main_win.page.clone();
|
||||||
|
|
||||||
|
let mut _container: Option<ImageContainer> = None;
|
||||||
|
std::thread::spawn(move || loop {
|
||||||
|
if let Ok(val) = reciver.recv() {
|
||||||
|
match val {
|
||||||
|
DrawMessage::Open => load_image(
|
||||||
|
&mut file_choice,
|
||||||
|
&mut quote,
|
||||||
|
&mut tag,
|
||||||
|
&mut layer_red,
|
||||||
|
&mut layer_green,
|
||||||
|
&mut layer_blue,
|
||||||
|
&mut layer_alpha,
|
||||||
|
&mut quote_position,
|
||||||
|
&mut tag_position,
|
||||||
|
&mut page,
|
||||||
|
&app_sender,
|
||||||
|
&properties,
|
||||||
|
&mut _container,
|
||||||
|
),
|
||||||
|
DrawMessage::Recalc => {
|
||||||
|
if let Some(cont) = &mut _container {
|
||||||
|
cont.recalc();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// DrawMessage::CropPos(x, y) => {
|
||||||
|
// if let Some(cont) = &mut _container {
|
||||||
|
// cont.apply_crop_pos(x, y);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// DrawMessage::Crop => {
|
||||||
|
// if let Some(cont) = &mut _container {
|
||||||
|
// cont.apply_crop();
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
DrawMessage::Flush => {
|
||||||
|
flush_buffer(&app_sender, &mut _container);
|
||||||
|
println!("recived");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
fn load_image(
|
||||||
|
file_choice: &mut menu::Choice,
|
||||||
|
quote: &mut MultilineInput,
|
||||||
|
tag: &mut Input,
|
||||||
|
layer_red: &mut Spinner,
|
||||||
|
layer_green: &mut Spinner,
|
||||||
|
layer_blue: &mut Spinner,
|
||||||
|
layer_alpha: &mut Spinner,
|
||||||
|
quote_position: &mut Spinner,
|
||||||
|
tag_position: &mut Spinner,
|
||||||
|
page: &mut Page,
|
||||||
|
app_sender: &app::Sender<crate::AppMessage>,
|
||||||
|
properties: &Arc<RwLock<ImageProperties>>,
|
||||||
|
container: &mut Option<ImageContainer>,
|
||||||
|
) {
|
||||||
|
let file: String = match file_choice.choice() {
|
||||||
|
Some(val) => val,
|
||||||
|
None => return,
|
||||||
|
};
|
||||||
|
|
||||||
|
*container = Some(ImageContainer::new(&file, Arc::clone(properties)));
|
||||||
|
|
||||||
|
if let Some(cont) = container {
|
||||||
|
let file = Path::new(&file);
|
||||||
|
let conf = file.with_extension("conf");
|
||||||
|
|
||||||
|
let properties = Arc::clone(&cont.properties);
|
||||||
|
let mut use_defaults = true;
|
||||||
|
if conf.exists() {
|
||||||
|
let read = fs::read_to_string(&conf).unwrap();
|
||||||
|
if let Ok(saved_prop) = serde_json::from_str::<ImageProperties>(&read) {
|
||||||
|
let mut prop = properties.write().unwrap();
|
||||||
|
layer_red.set_value(saved_prop.rgba[0] as f64);
|
||||||
|
layer_green.set_value(saved_prop.rgba[1] as f64);
|
||||||
|
layer_blue.set_value(saved_prop.rgba[2] as f64);
|
||||||
|
layer_alpha.set_value(saved_prop.rgba[3] as f64);
|
||||||
|
quote.set_value(&saved_prop.quote);
|
||||||
|
tag.set_value(&saved_prop.tag);
|
||||||
|
quote_position.set_range(0.0, prop.original_dimension.1 as f64);
|
||||||
|
quote_position.set_value(saved_prop.quote_position as f64);
|
||||||
|
tag_position.set_range(0.0, prop.original_dimension.1 as f64);
|
||||||
|
tag_position.set_value(saved_prop.tag_position as f64);
|
||||||
|
|
||||||
|
prop.quote = saved_prop.quote;
|
||||||
|
prop.tag = saved_prop.tag;
|
||||||
|
prop.quote_position = saved_prop.quote_position;
|
||||||
|
prop.tag_position = saved_prop.quote_position;
|
||||||
|
prop.rgba = saved_prop.rgba;
|
||||||
|
use_defaults = false;
|
||||||
|
|
||||||
|
drop(prop);
|
||||||
|
if let Some((x, y)) = saved_prop.crop_position {
|
||||||
|
cont.apply_crop_pos(x, y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if use_defaults {
|
||||||
|
let mut prop = properties.write().unwrap();
|
||||||
|
quote.set_value("");
|
||||||
|
tag.set_value("");
|
||||||
|
|
||||||
|
quote_position.set_range(0.0, prop.original_dimension.1 as f64);
|
||||||
|
quote_position.set_value(prop.quote_position as f64);
|
||||||
|
tag_position.set_range(0.0, prop.original_dimension.1 as f64);
|
||||||
|
tag_position.set_value(prop.tag_position as f64);
|
||||||
|
|
||||||
|
prop.rgba = [
|
||||||
|
layer_red.value() as u8,
|
||||||
|
layer_green.value() as u8,
|
||||||
|
layer_blue.value() as u8,
|
||||||
|
layer_alpha.value() as u8,
|
||||||
|
];
|
||||||
|
drop(prop);
|
||||||
|
cont.apply_crop();
|
||||||
|
}
|
||||||
|
|
||||||
|
let prop = properties.read().unwrap();
|
||||||
|
let (width, height) = prop.dimension;
|
||||||
|
page.col_flex.set_size(&page.image, height as i32);
|
||||||
|
page.row_flex.set_size(&page.col_flex, width as i32);
|
||||||
|
page.col_flex.recalc();
|
||||||
|
page.row_flex.recalc();
|
||||||
|
cont.recalc();
|
||||||
|
}
|
||||||
|
flush_buffer(&app_sender, &container);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn flush_buffer(app_sender: &app::Sender<crate::AppMessage>, container: &Option<ImageContainer>) {
|
||||||
|
if let Some(cont) = container {
|
||||||
|
app_sender.send(AppMessage::RedrawMainWindowImage(
|
||||||
|
cont.buffer.as_rgb8().unwrap().as_raw().to_owned(),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
35
src/main.rs
35
src/main.rs
|
|
@ -1,15 +1,25 @@
|
||||||
mod config;
|
mod config;
|
||||||
// mod crop_window;
|
// mod crop_window;
|
||||||
|
mod draw_thread;
|
||||||
mod main_window;
|
mod main_window;
|
||||||
mod properties;
|
mod properties;
|
||||||
mod utils;
|
mod utils;
|
||||||
|
|
||||||
// use crop_window::CropWindow;
|
// use crop_window::CropWindow;
|
||||||
use fltk::{app::App, enums::Font};
|
use fltk::{
|
||||||
|
app::{channel, App},
|
||||||
|
enums::Font,
|
||||||
|
prelude::*,
|
||||||
|
};
|
||||||
use fltk_theme::WidgetTheme;
|
use fltk_theme::WidgetTheme;
|
||||||
|
|
||||||
use main_window::MainWindow;
|
use main_window::MainWindow;
|
||||||
use std::{cell::RefCell, rc::Rc};
|
use std::sync::{Arc, RwLock};
|
||||||
use utils::ImageContainer;
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub(crate) enum AppMessage {
|
||||||
|
RedrawMainWindowImage(Vec<u8>),
|
||||||
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let app = App::default();
|
let app = App::default();
|
||||||
|
|
@ -21,14 +31,25 @@ fn main() {
|
||||||
.into(),
|
.into(),
|
||||||
)
|
)
|
||||||
.apply();
|
.apply();
|
||||||
|
|
||||||
let f1 = Font::load_font("ReenieBeanie-Regular.ttf").unwrap();
|
let f1 = Font::load_font("ReenieBeanie-Regular.ttf").unwrap();
|
||||||
let f2 = Font::load_font("Kalam-Regular.ttf").unwrap();
|
let f2 = Font::load_font("Kalam-Regular.ttf").unwrap();
|
||||||
Font::set_font(Font::Times, &f1);
|
Font::set_font(Font::Times, &f1);
|
||||||
Font::set_font(Font::TimesItalic, &f2);
|
Font::set_font(Font::TimesItalic, &f2);
|
||||||
|
|
||||||
let container: Rc<RefCell<Option<ImageContainer>>> = Rc::new(RefCell::new(None));
|
let draw_buff: Arc<RwLock<Vec<u8>>> = Arc::new(RwLock::new(vec![]));
|
||||||
|
let (main_sender, main_receiver) = channel::<AppMessage>();
|
||||||
|
let mut main_window = MainWindow::new(main_sender, Arc::clone(&draw_buff));
|
||||||
|
|
||||||
let main_win = MainWindow::new(Rc::clone(&container));
|
while app.wait() {
|
||||||
app.run().unwrap();
|
if let Some(msg) = main_receiver.recv() {
|
||||||
|
match msg {
|
||||||
|
AppMessage::RedrawMainWindowImage(data) => {
|
||||||
|
let mut buff = draw_buff.write().unwrap();
|
||||||
|
*buff = data;
|
||||||
|
println!("copy buff");
|
||||||
|
main_window.win.redraw();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
use crate::utils::ImageContainer;
|
use crate::utils::ImageProperties;
|
||||||
use crate::{properties::Properties, utils};
|
use crate::{draw_thread::*, properties};
|
||||||
use fltk::{
|
use fltk::{
|
||||||
|
app,
|
||||||
button::Button,
|
button::Button,
|
||||||
dialog::NativeFileChooser,
|
dialog::NativeFileChooser,
|
||||||
draw as dr, enums,
|
draw as dr, enums,
|
||||||
|
|
@ -13,40 +14,45 @@ use fltk::{
|
||||||
prelude::*,
|
prelude::*,
|
||||||
window::Window,
|
window::Window,
|
||||||
};
|
};
|
||||||
use image::GenericImageView;
|
use std::sync::{mpsc, RwLock};
|
||||||
use std::io::Read;
|
use std::{ffi::OsStr, fs, path::Path, sync::Arc};
|
||||||
use std::{cell::RefCell, ffi::OsStr, fs, path::Path, rc::Rc};
|
|
||||||
|
|
||||||
pub(crate) struct MainWindow {
|
pub(crate) struct MainWindow {
|
||||||
pub(crate) win: Window,
|
pub(crate) win: Window,
|
||||||
menubar: menu::SysMenuBar,
|
pub(crate) menubar: menu::SysMenuBar,
|
||||||
back_btn: Button,
|
pub(crate) back_btn: Button,
|
||||||
next_btn: Button,
|
pub(crate) next_btn: Button,
|
||||||
save_btn: Button,
|
pub(crate) save_btn: Button,
|
||||||
file_choice: menu::Choice,
|
pub(crate) file_choice: menu::Choice,
|
||||||
quote: MultilineInput,
|
pub(crate) quote: MultilineInput,
|
||||||
tag: Input,
|
pub(crate) tag: Input,
|
||||||
layer_red: Spinner,
|
pub(crate) layer_red: Spinner,
|
||||||
layer_green: Spinner,
|
pub(crate) layer_green: Spinner,
|
||||||
layer_blue: Spinner,
|
pub(crate) layer_blue: Spinner,
|
||||||
layer_alpha: Spinner,
|
pub(crate) layer_alpha: Spinner,
|
||||||
quote_position: Spinner,
|
pub(crate) quote_position: Spinner,
|
||||||
tag_position: Spinner,
|
pub(crate) tag_position: Spinner,
|
||||||
crop_btn: Button,
|
pub(crate) crop_btn: Button,
|
||||||
reset_btn: Button,
|
pub(crate) reset_btn: Button,
|
||||||
page: Page,
|
pub(crate) status: Frame,
|
||||||
container: Rc<RefCell<Option<ImageContainer>>>,
|
pub(crate) page: Page,
|
||||||
|
pub(crate) draw_buff: Arc<RwLock<Vec<u8>>>,
|
||||||
|
pub(crate) properties: Arc<RwLock<ImageProperties>>,
|
||||||
|
pub(crate) sender: mpsc::Sender<DrawMessage>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub(crate) struct Page {
|
pub(crate) struct Page {
|
||||||
image: Frame,
|
pub(crate) image: Frame,
|
||||||
row_flex: Flex,
|
pub(crate) row_flex: Flex,
|
||||||
col_flex: Flex,
|
pub(crate) col_flex: Flex,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MainWindow {
|
impl MainWindow {
|
||||||
pub(crate) fn new(container: Rc<RefCell<Option<ImageContainer>>>) -> Self {
|
pub(crate) fn new(
|
||||||
|
sender: app::Sender<crate::AppMessage>,
|
||||||
|
draw_buff: Arc<RwLock<Vec<u8>>>,
|
||||||
|
) -> Self {
|
||||||
let color = [25, 29, 34, 190];
|
let color = [25, 29, 34, 190];
|
||||||
|
|
||||||
let mut win = Window::default()
|
let mut win = Window::default()
|
||||||
|
|
@ -144,6 +150,11 @@ impl MainWindow {
|
||||||
actions_flex.end();
|
actions_flex.end();
|
||||||
controls_flex.set_size(&actions_flex, 30);
|
controls_flex.set_size(&actions_flex, 30);
|
||||||
|
|
||||||
|
Frame::default();
|
||||||
|
|
||||||
|
let status = Frame::default();
|
||||||
|
controls_flex.set_size(&status, 30);
|
||||||
|
|
||||||
controls_flex.end();
|
controls_flex.end();
|
||||||
workspace_flex.set_size(&controls_flex, 360);
|
workspace_flex.set_size(&controls_flex, 360);
|
||||||
|
|
||||||
|
|
@ -167,6 +178,8 @@ impl MainWindow {
|
||||||
win.make_resizable(true);
|
win.make_resizable(true);
|
||||||
win.show();
|
win.show();
|
||||||
|
|
||||||
|
let properties = Arc::new(RwLock::new(ImageProperties::new()));
|
||||||
|
let (rx, tx) = std::sync::mpsc::channel();
|
||||||
let mut main_win = Self {
|
let mut main_win = Self {
|
||||||
win,
|
win,
|
||||||
menubar,
|
menubar,
|
||||||
|
|
@ -184,13 +197,17 @@ impl MainWindow {
|
||||||
tag_position,
|
tag_position,
|
||||||
crop_btn,
|
crop_btn,
|
||||||
reset_btn,
|
reset_btn,
|
||||||
container,
|
status,
|
||||||
|
draw_buff,
|
||||||
|
properties: Arc::clone(&properties),
|
||||||
page: Page {
|
page: Page {
|
||||||
image: img_view,
|
image: img_view,
|
||||||
row_flex: center_row_flex,
|
row_flex: center_row_flex,
|
||||||
col_flex: center_col_flex,
|
col_flex: center_col_flex,
|
||||||
},
|
},
|
||||||
|
sender: rx,
|
||||||
};
|
};
|
||||||
|
spawn_image_thread(tx, sender, Arc::clone(&properties), &main_win);
|
||||||
main_win.menu();
|
main_win.menu();
|
||||||
main_win.draw();
|
main_win.draw();
|
||||||
main_win.events();
|
main_win.events();
|
||||||
|
|
@ -199,27 +216,30 @@ impl MainWindow {
|
||||||
|
|
||||||
fn menu(&mut self) {
|
fn menu(&mut self) {
|
||||||
let mut file_choice = self.file_choice.clone();
|
let mut file_choice = self.file_choice.clone();
|
||||||
let mut quote = self.quote.clone();
|
// let mut quote = self.quote.clone();
|
||||||
let mut tag = self.tag.clone();
|
// let mut tag = self.tag.clone();
|
||||||
let mut layer_red = self.layer_red.clone();
|
// let mut layer_red = self.layer_red.clone();
|
||||||
let mut layer_green = self.layer_green.clone();
|
// let mut layer_green = self.layer_green.clone();
|
||||||
let mut layer_blue = self.layer_blue.clone();
|
// let mut layer_blue = self.layer_blue.clone();
|
||||||
let mut layer_alpha = self.layer_alpha.clone();
|
// let mut layer_alpha = self.layer_alpha.clone();
|
||||||
let mut quote_position = self.quote_position.clone();
|
// let mut quote_position = self.quote_position.clone();
|
||||||
let mut tag_position = self.tag_position.clone();
|
// let mut tag_position = self.tag_position.clone();
|
||||||
let mut page = self.page.clone();
|
// let mut page = self.page.clone();
|
||||||
let container = Rc::clone(&self.container);
|
let sender = self.sender.clone();
|
||||||
|
// let properties = Arc::clone(&self.properties);
|
||||||
let mut win = self.win.clone();
|
let mut win = self.win.clone();
|
||||||
self.menubar.add(
|
self.menubar.add(
|
||||||
"&File/Open Folder...\t",
|
"&File/Open Folder...\t",
|
||||||
Shortcut::Ctrl | 'o',
|
Shortcut::Ctrl | 'o',
|
||||||
menu::MenuFlag::Normal,
|
menu::MenuFlag::Normal,
|
||||||
move |_| {
|
move |_| {
|
||||||
|
win.redraw();
|
||||||
let mut chooser = NativeFileChooser::new(fltk::dialog::FileDialogType::BrowseDir);
|
let mut chooser = NativeFileChooser::new(fltk::dialog::FileDialogType::BrowseDir);
|
||||||
chooser.set_option(fltk::dialog::FileDialogOptions::NewFolder);
|
chooser.set_option(fltk::dialog::FileDialogOptions::NewFolder);
|
||||||
chooser.show();
|
chooser.show();
|
||||||
let path = chooser.filename();
|
let path = chooser.filename();
|
||||||
if !path.exists() {
|
if !path.exists() {
|
||||||
|
win.activate();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let files = fs::read_dir(path).unwrap();
|
let files = fs::read_dir(path).unwrap();
|
||||||
|
|
@ -232,26 +252,13 @@ impl MainWindow {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if text.len() == 0 {
|
if text.len() == 0 {
|
||||||
|
win.activate();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
file_choice.clear();
|
file_choice.clear();
|
||||||
file_choice.add_choice(&text[1..]);
|
file_choice.add_choice(&text[1..]);
|
||||||
file_choice.set_value(0);
|
file_choice.set_value(0);
|
||||||
|
sender.send(DrawMessage::Open).unwrap();
|
||||||
load_image(
|
|
||||||
&mut file_choice,
|
|
||||||
&mut quote,
|
|
||||||
&mut tag,
|
|
||||||
&mut layer_red,
|
|
||||||
&mut layer_green,
|
|
||||||
&mut layer_blue,
|
|
||||||
&mut layer_alpha,
|
|
||||||
&mut quote_position,
|
|
||||||
&mut tag_position,
|
|
||||||
&mut page,
|
|
||||||
&container,
|
|
||||||
);
|
|
||||||
win.redraw();
|
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
@ -273,130 +280,193 @@ impl MainWindow {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn draw(&mut self) {
|
fn draw(&mut self) {
|
||||||
let mut buffer = Vec::new();
|
println!("in draw");
|
||||||
fs::File::open("ReenieBeanie-Regular.ttf")
|
let buff = Arc::clone(&self.draw_buff);
|
||||||
.unwrap()
|
let properties = Arc::clone(&self.properties);
|
||||||
.read_to_end(&mut buffer)
|
|
||||||
.unwrap();
|
|
||||||
let font = rusttype::Font::try_from_vec(buffer).unwrap();
|
|
||||||
|
|
||||||
let container = Rc::clone(&self.container);
|
|
||||||
let quote = self.quote.clone();
|
|
||||||
self.page.image.draw(move |f| {
|
self.page.image.draw(move |f| {
|
||||||
if let Some(cont) = &*container.borrow() {
|
let (width, height) = properties.read().unwrap().dimension;
|
||||||
let image = cont.image.as_rgb8().unwrap();
|
let image = &*buff.read().unwrap();
|
||||||
dr::draw_image(
|
dr::draw_image(
|
||||||
image.as_raw(),
|
&image,
|
||||||
f.x(),
|
f.x(),
|
||||||
f.y(),
|
f.y(),
|
||||||
image.width() as i32,
|
width as i32,
|
||||||
image.height() as i32,
|
height as i32,
|
||||||
enums::ColorDepth::Rgb8,
|
enums::ColorDepth::Rgb8,
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
dr::set_color_rgb(255, 255, 255);
|
|
||||||
|
|
||||||
let size = utils::quote_from_height(image.height());
|
|
||||||
dr::set_font(enums::Font::Times, size as i32);
|
|
||||||
|
|
||||||
let (text_width, text_height) = utils::measure_line(
|
|
||||||
&font,
|
|
||||||
"e.value(),
|
|
||||||
rusttype::Scale::uniform(size as f32),
|
|
||||||
);
|
|
||||||
|
|
||||||
dr::draw_text(
|
|
||||||
"e.value(),
|
|
||||||
f.x() + image.width() as i32 / 2 - text_width as i32 / 2,
|
|
||||||
f.y() + image.height() as i32 / 2 - text_height as i32 / 2,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn events(&mut self) {
|
fn events(&mut self) {
|
||||||
let mut image = self.page.image.clone();
|
let mut image = self.page.image.clone();
|
||||||
self.quote.handle(move |_, ev| {
|
let properties = Arc::clone(&self.properties);
|
||||||
|
let sender = self.sender.clone();
|
||||||
|
self.quote.handle(move |f, ev| {
|
||||||
if ev == enums::Event::KeyUp {
|
if ev == enums::Event::KeyUp {
|
||||||
|
let mut prop = properties.write().unwrap();
|
||||||
|
prop.quote = f.value();
|
||||||
|
sender.send(DrawMessage::Recalc).unwrap();
|
||||||
|
sender.send(DrawMessage::Flush).unwrap();
|
||||||
image.redraw();
|
image.redraw();
|
||||||
}
|
}
|
||||||
true
|
true
|
||||||
});
|
});
|
||||||
|
|
||||||
|
let mut image = self.page.image.clone();
|
||||||
|
let properties = Arc::clone(&self.properties);
|
||||||
|
let sender = self.sender.clone();
|
||||||
|
self.tag.handle(move |f, ev| {
|
||||||
|
if ev == enums::Event::KeyUp {
|
||||||
|
let mut prop = properties.write().unwrap();
|
||||||
|
prop.tag = f.value();
|
||||||
|
sender.send(DrawMessage::Recalc).unwrap();
|
||||||
|
sender.send(DrawMessage::Flush).unwrap();
|
||||||
|
image.redraw();
|
||||||
|
}
|
||||||
|
true
|
||||||
|
});
|
||||||
|
|
||||||
|
let mut image = self.page.image.clone();
|
||||||
|
let properties = Arc::clone(&self.properties);
|
||||||
|
let sender = self.sender.clone();
|
||||||
|
self.quote_position.set_callback(move |f| {
|
||||||
|
let mut prop = properties.write().unwrap();
|
||||||
|
prop.quote_position = f.value() as u32;
|
||||||
|
sender.send(DrawMessage::Recalc).unwrap();
|
||||||
|
sender.send(DrawMessage::Flush).unwrap();
|
||||||
|
image.redraw();
|
||||||
|
});
|
||||||
|
|
||||||
|
let mut image = self.page.image.clone();
|
||||||
|
let properties = Arc::clone(&self.properties);
|
||||||
|
let sender = self.sender.clone();
|
||||||
|
self.tag_position.set_callback(move |f| {
|
||||||
|
let mut prop = properties.write().unwrap();
|
||||||
|
prop.tag_position = f.value() as u32;
|
||||||
|
sender.send(DrawMessage::Recalc).unwrap();
|
||||||
|
sender.send(DrawMessage::Flush).unwrap();
|
||||||
|
image.redraw();
|
||||||
|
});
|
||||||
|
|
||||||
|
let mut image = self.page.image.clone();
|
||||||
|
let properties = Arc::clone(&self.properties);
|
||||||
|
let sender = self.sender.clone();
|
||||||
|
self.layer_red.set_callback(move |f| {
|
||||||
|
let mut prop = properties.write().unwrap();
|
||||||
|
prop.rgba[0] = f.value() as u8;
|
||||||
|
sender.send(DrawMessage::Recalc).unwrap();
|
||||||
|
sender.send(DrawMessage::Flush).unwrap();
|
||||||
|
image.redraw();
|
||||||
|
});
|
||||||
|
|
||||||
|
let mut image = self.page.image.clone();
|
||||||
|
let properties = Arc::clone(&self.properties);
|
||||||
|
let sender = self.sender.clone();
|
||||||
|
self.layer_green.set_callback(move |f| {
|
||||||
|
let mut prop = properties.write().unwrap();
|
||||||
|
prop.rgba[1] = f.value() as u8;
|
||||||
|
sender.send(DrawMessage::Recalc).unwrap();
|
||||||
|
sender.send(DrawMessage::Flush).unwrap();
|
||||||
|
image.redraw();
|
||||||
|
});
|
||||||
|
|
||||||
|
let mut image = self.page.image.clone();
|
||||||
|
let properties = Arc::clone(&self.properties);
|
||||||
|
let sender = self.sender.clone();
|
||||||
|
self.layer_blue.set_callback(move |f| {
|
||||||
|
let mut prop = properties.write().unwrap();
|
||||||
|
prop.rgba[2] = f.value() as u8;
|
||||||
|
sender.send(DrawMessage::Recalc).unwrap();
|
||||||
|
sender.send(DrawMessage::Flush).unwrap();
|
||||||
|
image.redraw();
|
||||||
|
});
|
||||||
|
|
||||||
|
let mut image = self.page.image.clone();
|
||||||
|
let properties = Arc::clone(&self.properties);
|
||||||
|
let sender = self.sender.clone();
|
||||||
|
self.layer_alpha.set_callback(move |f| {
|
||||||
|
let mut prop = properties.write().unwrap();
|
||||||
|
prop.rgba[3] = f.value() as u8;
|
||||||
|
sender.send(DrawMessage::Recalc).unwrap();
|
||||||
|
sender.send(DrawMessage::Flush).unwrap();
|
||||||
|
image.redraw();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn load_image(
|
// fn load_image(
|
||||||
file_choice: &mut menu::Choice,
|
// file_choice: &mut menu::Choice,
|
||||||
quote: &mut MultilineInput,
|
// quote: &mut MultilineInput,
|
||||||
tag: &mut Input,
|
// tag: &mut Input,
|
||||||
layer_red: &mut Spinner,
|
// layer_red: &mut Spinner,
|
||||||
layer_green: &mut Spinner,
|
// layer_green: &mut Spinner,
|
||||||
layer_blue: &mut Spinner,
|
// layer_blue: &mut Spinner,
|
||||||
layer_alpha: &mut Spinner,
|
// layer_alpha: &mut Spinner,
|
||||||
quote_position: &mut Spinner,
|
// quote_position: &mut Spinner,
|
||||||
tag_position: &mut Spinner,
|
// tag_position: &mut Spinner,
|
||||||
page: &mut Page,
|
// page: &mut Page,
|
||||||
container: &Rc<RefCell<Option<ImageContainer>>>,
|
// properties: &Arc<RwLock<ImageProperties>>,
|
||||||
) {
|
// sender: &mpsc::Sender<DrawMessage>,
|
||||||
let file: String = match file_choice.choice() {
|
// ) {
|
||||||
Some(val) => val,
|
// let file: String = match file_choice.choice() {
|
||||||
None => return,
|
// Some(val) => val,
|
||||||
};
|
// None => return,
|
||||||
|
// };
|
||||||
|
|
||||||
*container.borrow_mut() = Some(ImageContainer::new(&file));
|
// sender.send(DrawMessage::Open(file.clone())).unwrap();
|
||||||
|
|
||||||
let file = Path::new(&file);
|
// let file = Path::new(&file);
|
||||||
let conf = file.with_extension("conf");
|
// let conf = file.with_extension("conf");
|
||||||
|
|
||||||
let mut use_defaults = true;
|
// let mut prop = properties.write().unwrap();
|
||||||
if conf.exists() {
|
// let mut use_defaults = true;
|
||||||
let read = fs::read_to_string(&conf).unwrap();
|
// if conf.exists() {
|
||||||
if let Ok(prop) = serde_json::from_str::<Properties>(&read) {
|
// let read = fs::read_to_string(&conf).unwrap();
|
||||||
if let Some(cont) = &mut *container.borrow_mut() {
|
// if let Ok(saved_prop) = serde_json::from_str::<ImageProperties>(&read) {
|
||||||
layer_red.set_value(prop.rgba[0] as f64);
|
// layer_red.set_value(saved_prop.rgba[0] as f64);
|
||||||
layer_green.set_value(prop.rgba[1] as f64);
|
// layer_green.set_value(saved_prop.rgba[1] as f64);
|
||||||
layer_blue.set_value(prop.rgba[2] as f64);
|
// layer_blue.set_value(saved_prop.rgba[2] as f64);
|
||||||
layer_alpha.set_value(prop.rgba[3] as f64);
|
// layer_alpha.set_value(saved_prop.rgba[3] as f64);
|
||||||
quote.set_value(&prop.quote);
|
// quote.set_value(&saved_prop.quote);
|
||||||
tag.set_value(&prop.tag);
|
// tag.set_value(&saved_prop.tag);
|
||||||
quote_position.set_value(prop.quote_position as f64);
|
// quote_position.set_range(0.0, prop.original_dimension.1 as f64);
|
||||||
tag_position.set_value(prop.tag_position as f64);
|
// quote_position.set_value(saved_prop.quote_position as f64);
|
||||||
cont.apply_crop_pos(prop.crop_position.0, prop.crop_position.1);
|
// tag_position.set_range(0.0, prop.original_dimension.1 as f64);
|
||||||
|
// tag_position.set_value(saved_prop.tag_position as f64);
|
||||||
|
|
||||||
cont.quote = prop.quote;
|
// if let Some((x, y)) = saved_prop.crop_position {
|
||||||
cont.tag = prop.tag;
|
// sender.send(DrawMessage::CropPos(x, y)).unwrap();
|
||||||
cont.quote_position = prop.quote_position;
|
// }
|
||||||
cont.tag_position = prop.quote_position;
|
|
||||||
cont.rgba = prop.rgba;
|
|
||||||
}
|
|
||||||
use_defaults = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if use_defaults {
|
// prop.quote = saved_prop.quote;
|
||||||
if let Some(cont) = &mut *container.borrow_mut() {
|
// prop.tag = saved_prop.tag;
|
||||||
quote.set_value("");
|
// prop.quote_position = saved_prop.quote_position;
|
||||||
tag.set_value("");
|
// prop.tag_position = saved_prop.quote_position;
|
||||||
quote_position.set_value(cont.quote_position as f64);
|
// prop.rgba = saved_prop.rgba;
|
||||||
tag_position.set_value(cont.tag_position as f64);
|
// use_defaults = false;
|
||||||
cont.apply_crop();
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
cont.rgba = [
|
// if use_defaults {
|
||||||
layer_red.value() as u8,
|
// quote.set_value("");
|
||||||
layer_green.value() as u8,
|
// tag.set_value("");
|
||||||
layer_blue.value() as u8,
|
|
||||||
layer_alpha.value() as u8,
|
|
||||||
];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(cont) = &mut *container.borrow_mut() {
|
// quote_position.set_range(0.0, prop.original_dimension.1 as f64);
|
||||||
cont.apply_layer();
|
// quote_position.set_value(prop.quote_position as f64);
|
||||||
let (width, height) = cont.image.dimensions();
|
// tag_position.set_range(0.0, prop.original_dimension.1 as f64);
|
||||||
page.row_flex.set_size(&page.col_flex, width as i32);
|
// tag_position.set_value(prop.tag_position as f64);
|
||||||
page.col_flex.set_size(&page.image, height as i32);
|
|
||||||
page.row_flex.recalc();
|
// sender.send(DrawMessage::Crop).unwrap();
|
||||||
page.col_flex.recalc();
|
|
||||||
}
|
// prop.rgba = [
|
||||||
}
|
// layer_red.value() as u8,
|
||||||
|
// layer_green.value() as u8,
|
||||||
|
// layer_blue.value() as u8,
|
||||||
|
// layer_alpha.value() as u8,
|
||||||
|
// ];
|
||||||
|
// }
|
||||||
|
// sender.send(DrawMessage::Recalc).unwrap();
|
||||||
|
// println!("sent");
|
||||||
|
// sender.send(DrawMessage::Flush).unwrap();
|
||||||
|
// }
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,22 @@
|
||||||
use serde::{Deserialize, Serialize};
|
use lazy_static::lazy_static;
|
||||||
|
use rusttype::Font;
|
||||||
|
use std::io::Read;
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug)]
|
lazy_static! {
|
||||||
pub(crate) struct Properties {
|
pub static ref FONT_QUOTE: Font<'static> = {
|
||||||
pub(crate) quote: String,
|
let mut buffer = Vec::new();
|
||||||
pub(crate) tag: String,
|
std::fs::File::open("ReenieBeanie-Regular.ttf")
|
||||||
pub(crate) quote_position: u32,
|
.unwrap()
|
||||||
pub(crate) tag_position: u32,
|
.read_to_end(&mut buffer)
|
||||||
pub(crate) crop_position: (u32, u32),
|
.unwrap();
|
||||||
pub(crate) rgba: [u8; 4],
|
rusttype::Font::try_from_vec(buffer).unwrap()
|
||||||
|
};
|
||||||
|
pub static ref FONT_TAG: Font<'static> = {
|
||||||
|
let mut buffer = Vec::new();
|
||||||
|
std::fs::File::open("Kalam-Regular.ttf")
|
||||||
|
.unwrap()
|
||||||
|
.read_to_end(&mut buffer)
|
||||||
|
.unwrap();
|
||||||
|
rusttype::Font::try_from_vec(buffer).unwrap()
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
195
src/utils.rs
195
src/utils.rs
|
|
@ -1,9 +1,135 @@
|
||||||
use fltk::prelude::ImageExt;
|
use std::sync::{Arc, RwLock};
|
||||||
|
|
||||||
use image::{DynamicImage, GenericImageView, ImageBuffer};
|
use image::{DynamicImage, GenericImageView, ImageBuffer};
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
use crate::properties;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub(crate) struct ImageContainer {
|
pub(crate) struct ImageContainer {
|
||||||
pub(crate) image: DynamicImage,
|
pub(crate) image: DynamicImage, //plain
|
||||||
|
pub(crate) buffer: DynamicImage, //buffer to show
|
||||||
|
pub(crate) properties: Arc<RwLock<ImageProperties>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ImageContainer {
|
||||||
|
pub(crate) fn new(path: &str, properties: Arc<RwLock<ImageProperties>>) -> Self {
|
||||||
|
let img = image::open(path).unwrap();
|
||||||
|
let (width, height) = img.dimensions();
|
||||||
|
let (s_width, s_height) = ((width * 500) / height, 500);
|
||||||
|
let img = img.resize(s_width, s_height, image::imageops::FilterType::Triangle);
|
||||||
|
|
||||||
|
let mut prop = properties.write().unwrap();
|
||||||
|
prop.path = path.to_owned();
|
||||||
|
prop.dimension = (s_width, s_height);
|
||||||
|
prop.original_dimension = (width, height);
|
||||||
|
prop.quote_position = height / 2;
|
||||||
|
prop.tag_position = (height * 2) / 3;
|
||||||
|
|
||||||
|
Self {
|
||||||
|
image: img.clone(),
|
||||||
|
buffer: img,
|
||||||
|
properties: Arc::clone(&properties),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn apply_crop(&mut self) {
|
||||||
|
let mut prop = self.properties.write().unwrap();
|
||||||
|
let (original_width, original_height) = prop.original_dimension;
|
||||||
|
let (origina_crop_width, origina_crop_height) = get_4_5(original_width, original_height);
|
||||||
|
prop.crop_position = Some((
|
||||||
|
original_width / 2 - origina_crop_width / 2,
|
||||||
|
original_height / 2 - origina_crop_height / 2,
|
||||||
|
));
|
||||||
|
|
||||||
|
let (s_width, s_height) = self.image.dimensions();
|
||||||
|
let (c_width, c_height) = get_4_5(s_width, s_height);
|
||||||
|
let (cx, cy) = (s_width / 2 - c_width / 2, s_height / 2 - c_height / 2);
|
||||||
|
|
||||||
|
prop.dimension = (c_width, c_height);
|
||||||
|
|
||||||
|
self.image = self.image.crop(cx, cy, c_width, c_height);
|
||||||
|
self.buffer = self.image.clone();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn apply_crop_pos(&mut self, original_x: u32, original_y: u32) {
|
||||||
|
let mut prop = self.properties.write().unwrap();
|
||||||
|
let (original_width, original_height) = prop.original_dimension;
|
||||||
|
prop.crop_position = Some((original_x, original_y));
|
||||||
|
|
||||||
|
let (s_width, s_height) = self.image.dimensions();
|
||||||
|
let (c_width, c_height) = get_4_5(s_width, s_height);
|
||||||
|
let (cx, cy) = (
|
||||||
|
(original_x * s_width) / original_width,
|
||||||
|
(original_y * s_height) / original_height,
|
||||||
|
);
|
||||||
|
|
||||||
|
prop.dimension = (c_width, c_height);
|
||||||
|
|
||||||
|
self.image = self.image.crop(cx, cy, c_width, c_height);
|
||||||
|
self.buffer = self.image.clone();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn recalc(&mut self) {
|
||||||
|
let prop = self.properties.read().unwrap();
|
||||||
|
let mut tmp = self.image.clone();
|
||||||
|
let (width, height) = tmp.dimensions();
|
||||||
|
|
||||||
|
let layer = DynamicImage::ImageRgba8(ImageBuffer::from_fn(width, height, |_, _| {
|
||||||
|
image::Rgba(prop.rgba)
|
||||||
|
}));
|
||||||
|
image::imageops::overlay(&mut tmp, &layer, 0, 0);
|
||||||
|
|
||||||
|
let size = quote_from_height(height);
|
||||||
|
for (index, line) in prop.quote.lines().enumerate() {
|
||||||
|
let (text_width, text_height) = measure_line(
|
||||||
|
&properties::FONT_QUOTE,
|
||||||
|
line,
|
||||||
|
rusttype::Scale::uniform(size as f32),
|
||||||
|
);
|
||||||
|
|
||||||
|
imageproc::drawing::draw_text_mut(
|
||||||
|
&mut tmp,
|
||||||
|
image::Rgba([255, 255, 255, 255]),
|
||||||
|
((width as f32 - text_width) / 2.0) as u32,
|
||||||
|
(prop.quote_position * height) / prop.original_dimension.1
|
||||||
|
+ (text_height / 2.0) as u32
|
||||||
|
+ index as u32 * (text_height * 1.2) as u32,
|
||||||
|
rusttype::Scale::uniform(size as f32),
|
||||||
|
&properties::FONT_QUOTE,
|
||||||
|
line,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
let size = tag_from_height(height);
|
||||||
|
for (index, line) in prop.tag.lines().enumerate() {
|
||||||
|
let (text_width, text_height) = measure_line(
|
||||||
|
&properties::FONT_TAG,
|
||||||
|
line,
|
||||||
|
rusttype::Scale::uniform(size as f32),
|
||||||
|
);
|
||||||
|
|
||||||
|
imageproc::drawing::draw_text_mut(
|
||||||
|
&mut tmp,
|
||||||
|
image::Rgba([255, 255, 255, 255]),
|
||||||
|
(width as f32 * 0.99 - text_width) as u32,
|
||||||
|
(prop.tag_position * height) / prop.original_dimension.1
|
||||||
|
+ (text_height / 2.0) as u32
|
||||||
|
+ index as u32 * (text_height * 1.2) as u32,
|
||||||
|
rusttype::Scale::uniform(size as f32),
|
||||||
|
&properties::FONT_TAG,
|
||||||
|
line,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
self.buffer = tmp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Debug)]
|
||||||
|
pub(crate) struct ImageProperties {
|
||||||
|
pub(crate) path: String,
|
||||||
|
pub(crate) dimension: (u32, u32),
|
||||||
pub(crate) original_dimension: (u32, u32),
|
pub(crate) original_dimension: (u32, u32),
|
||||||
pub(crate) crop_position: Option<(u32, u32)>,
|
pub(crate) crop_position: Option<(u32, u32)>,
|
||||||
pub(crate) quote: String,
|
pub(crate) quote: String,
|
||||||
|
|
@ -14,62 +140,21 @@ pub(crate) struct ImageContainer {
|
||||||
pub(crate) is_saved: bool,
|
pub(crate) is_saved: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ImageContainer {
|
impl ImageProperties {
|
||||||
pub(crate) fn new(path: &str) -> Self {
|
pub(crate) fn new() -> Self {
|
||||||
let img = image::open(path).unwrap();
|
|
||||||
let (width, height) = img.dimensions();
|
|
||||||
let (s_width, s_height) = ((width * 500) / height, 500);
|
|
||||||
let mut img = img.resize(s_width, s_height, image::imageops::FilterType::Triangle);
|
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
image: img,
|
path: "".to_owned(),
|
||||||
original_dimension: (width, height),
|
dimension: (0, 0),
|
||||||
|
original_dimension: (0, 0),
|
||||||
crop_position: None,
|
crop_position: None,
|
||||||
quote: String::new(),
|
quote: "".to_owned(),
|
||||||
tag: String::new(),
|
tag: "".to_owned(),
|
||||||
quote_position: (width * 2) / 3,
|
quote_position: 0,
|
||||||
tag_position: width / 2,
|
tag_position: 0,
|
||||||
rgba: [0; 4],
|
rgba: [0; 4],
|
||||||
is_saved: true,
|
is_saved: true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn apply_crop(&mut self) {
|
|
||||||
let (original_width, original_height) = self.original_dimension;
|
|
||||||
let (origina_crop_width, origina_crop_height) = get_4_5(original_width, original_height);
|
|
||||||
self.crop_position = Some((
|
|
||||||
original_width / 2 - origina_crop_width / 2,
|
|
||||||
original_height / 2 - origina_crop_height / 2,
|
|
||||||
));
|
|
||||||
|
|
||||||
let (s_width, s_height) = self.image.dimensions();
|
|
||||||
let (c_width, c_height) = get_4_5(s_width, s_height);
|
|
||||||
let (cx, cy) = (s_width / 2 - c_width / 2, s_height / 2 - c_height / 2);
|
|
||||||
|
|
||||||
self.image = self.image.crop(cx, cy, c_width, c_height);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn apply_crop_pos(&mut self, original_x: u32, original_y: u32) {
|
|
||||||
let (original_width, original_height) = self.original_dimension;
|
|
||||||
self.crop_position = Some((original_x, original_y));
|
|
||||||
|
|
||||||
let (s_width, s_height) = self.image.dimensions();
|
|
||||||
let (c_width, c_height) = get_4_5(s_width, s_height);
|
|
||||||
let (cx, cy) = (
|
|
||||||
(original_x * s_width) / original_width,
|
|
||||||
(original_y * s_height) / original_height,
|
|
||||||
);
|
|
||||||
|
|
||||||
self.image = self.image.crop(cx, cy, c_width, c_height);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn apply_layer(&mut self) {
|
|
||||||
let (width, height) = self.image.dimensions();
|
|
||||||
let layer = DynamicImage::ImageRgba8(ImageBuffer::from_fn(width, height, |_, _| {
|
|
||||||
image::Rgba(self.rgba)
|
|
||||||
}));
|
|
||||||
image::imageops::overlay(&mut self.image, &layer, 0, 0);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn get_4_5(width: u32, height: u32) -> (u32, u32) {
|
pub(crate) fn get_4_5(width: u32, height: u32) -> (u32, u32) {
|
||||||
|
|
@ -89,11 +174,11 @@ pub(crate) fn height_from_width(width: u32) -> u32 {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn quote_from_height(height: u32) -> u32 {
|
pub(crate) fn quote_from_height(height: u32) -> u32 {
|
||||||
(height * 65) / 1556
|
(height * 70) / 1350
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn id_from_height(height: u32) -> u32 {
|
pub(crate) fn tag_from_height(height: u32) -> u32 {
|
||||||
(height * 30) / 1556
|
(height * 50) / 1350
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn measure_line(
|
pub(crate) fn measure_line(
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue