tons of stuffs, specially fltk comps in thread and loading images from other thread

This commit is contained in:
Piyush मिश्रः 2022-01-12 15:00:44 +05:30
parent 887d5d9e58
commit a5b4b84eec
8 changed files with 648 additions and 232 deletions

45
.vscode/launch.json vendored Normal file
View File

@ -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}"
}
]
}

1
Cargo.lock generated
View File

@ -556,6 +556,7 @@ dependencies = [
"fltk-theme",
"image",
"imageproc",
"lazy_static",
"rusttype",
"serde",
"serde_json",

View File

@ -14,3 +14,4 @@ imageproc = "0.22"
rusttype = "0.9"
serde_json = "1.0"
serde = { version = "1.0", features = ["derive"] }
lazy_static = "1.4"

182
src/draw_thread.rs Normal file
View File

@ -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(),
));
}
}

View File

@ -1,15 +1,25 @@
mod config;
// mod crop_window;
mod draw_thread;
mod main_window;
mod properties;
mod utils;
// use crop_window::CropWindow;
use fltk::{app::App, enums::Font};
use fltk::{
app::{channel, App},
enums::Font,
prelude::*,
};
use fltk_theme::WidgetTheme;
use main_window::MainWindow;
use std::{cell::RefCell, rc::Rc};
use utils::ImageContainer;
use std::sync::{Arc, RwLock};
#[derive(Clone, Debug)]
pub(crate) enum AppMessage {
RedrawMainWindowImage(Vec<u8>),
}
fn main() {
let app = App::default();
@ -21,14 +31,25 @@ fn main() {
.into(),
)
.apply();
let f1 = Font::load_font("ReenieBeanie-Regular.ttf").unwrap();
let f2 = Font::load_font("Kalam-Regular.ttf").unwrap();
Font::set_font(Font::Times, &f1);
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));
app.run().unwrap();
while app.wait() {
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();
}
}
}
}
}

View File

@ -1,6 +1,7 @@
use crate::utils::ImageContainer;
use crate::{properties::Properties, utils};
use crate::utils::ImageProperties;
use crate::{draw_thread::*, properties};
use fltk::{
app,
button::Button,
dialog::NativeFileChooser,
draw as dr, enums,
@ -13,40 +14,45 @@ use fltk::{
prelude::*,
window::Window,
};
use image::GenericImageView;
use std::io::Read;
use std::{cell::RefCell, ffi::OsStr, fs, path::Path, rc::Rc};
use std::sync::{mpsc, RwLock};
use std::{ffi::OsStr, fs, path::Path, sync::Arc};
pub(crate) struct MainWindow {
pub(crate) win: Window,
menubar: menu::SysMenuBar,
back_btn: Button,
next_btn: Button,
save_btn: Button,
file_choice: menu::Choice,
quote: MultilineInput,
tag: Input,
layer_red: Spinner,
layer_green: Spinner,
layer_blue: Spinner,
layer_alpha: Spinner,
quote_position: Spinner,
tag_position: Spinner,
crop_btn: Button,
reset_btn: Button,
page: Page,
container: Rc<RefCell<Option<ImageContainer>>>,
pub(crate) menubar: menu::SysMenuBar,
pub(crate) back_btn: Button,
pub(crate) next_btn: Button,
pub(crate) save_btn: Button,
pub(crate) file_choice: menu::Choice,
pub(crate) quote: MultilineInput,
pub(crate) tag: Input,
pub(crate) layer_red: Spinner,
pub(crate) layer_green: Spinner,
pub(crate) layer_blue: Spinner,
pub(crate) layer_alpha: Spinner,
pub(crate) quote_position: Spinner,
pub(crate) tag_position: Spinner,
pub(crate) crop_btn: Button,
pub(crate) reset_btn: Button,
pub(crate) status: Frame,
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)]
pub(crate) struct Page {
image: Frame,
row_flex: Flex,
col_flex: Flex,
pub(crate) image: Frame,
pub(crate) row_flex: Flex,
pub(crate) col_flex: Flex,
}
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 mut win = Window::default()
@ -144,6 +150,11 @@ impl MainWindow {
actions_flex.end();
controls_flex.set_size(&actions_flex, 30);
Frame::default();
let status = Frame::default();
controls_flex.set_size(&status, 30);
controls_flex.end();
workspace_flex.set_size(&controls_flex, 360);
@ -167,6 +178,8 @@ impl MainWindow {
win.make_resizable(true);
win.show();
let properties = Arc::new(RwLock::new(ImageProperties::new()));
let (rx, tx) = std::sync::mpsc::channel();
let mut main_win = Self {
win,
menubar,
@ -184,13 +197,17 @@ impl MainWindow {
tag_position,
crop_btn,
reset_btn,
container,
status,
draw_buff,
properties: Arc::clone(&properties),
page: Page {
image: img_view,
row_flex: center_row_flex,
col_flex: center_col_flex,
},
sender: rx,
};
spawn_image_thread(tx, sender, Arc::clone(&properties), &main_win);
main_win.menu();
main_win.draw();
main_win.events();
@ -199,27 +216,30 @@ impl MainWindow {
fn menu(&mut self) {
let mut file_choice = self.file_choice.clone();
let mut quote = self.quote.clone();
let mut tag = self.tag.clone();
let mut layer_red = self.layer_red.clone();
let mut layer_green = self.layer_green.clone();
let mut layer_blue = self.layer_blue.clone();
let mut layer_alpha = self.layer_alpha.clone();
let mut quote_position = self.quote_position.clone();
let mut tag_position = self.tag_position.clone();
let mut page = self.page.clone();
let container = Rc::clone(&self.container);
// let mut quote = self.quote.clone();
// let mut tag = self.tag.clone();
// let mut layer_red = self.layer_red.clone();
// let mut layer_green = self.layer_green.clone();
// let mut layer_blue = self.layer_blue.clone();
// let mut layer_alpha = self.layer_alpha.clone();
// let mut quote_position = self.quote_position.clone();
// let mut tag_position = self.tag_position.clone();
// let mut page = self.page.clone();
let sender = self.sender.clone();
// let properties = Arc::clone(&self.properties);
let mut win = self.win.clone();
self.menubar.add(
"&File/Open Folder...\t",
Shortcut::Ctrl | 'o',
menu::MenuFlag::Normal,
move |_| {
win.redraw();
let mut chooser = NativeFileChooser::new(fltk::dialog::FileDialogType::BrowseDir);
chooser.set_option(fltk::dialog::FileDialogOptions::NewFolder);
chooser.show();
let path = chooser.filename();
if !path.exists() {
win.activate();
return;
}
let files = fs::read_dir(path).unwrap();
@ -232,26 +252,13 @@ impl MainWindow {
}
}
if text.len() == 0 {
win.activate();
return;
}
file_choice.clear();
file_choice.add_choice(&text[1..]);
file_choice.set_value(0);
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();
sender.send(DrawMessage::Open).unwrap();
},
);
@ -273,130 +280,193 @@ impl MainWindow {
}
fn draw(&mut self) {
let mut buffer = Vec::new();
fs::File::open("ReenieBeanie-Regular.ttf")
.unwrap()
.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();
println!("in draw");
let buff = Arc::clone(&self.draw_buff);
let properties = Arc::clone(&self.properties);
self.page.image.draw(move |f| {
if let Some(cont) = &*container.borrow() {
let image = cont.image.as_rgb8().unwrap();
let (width, height) = properties.read().unwrap().dimension;
let image = &*buff.read().unwrap();
dr::draw_image(
image.as_raw(),
&image,
f.x(),
f.y(),
image.width() as i32,
image.height() as i32,
width as i32,
height as i32,
enums::ColorDepth::Rgb8,
)
.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,
&quote.value(),
rusttype::Scale::uniform(size as f32),
);
dr::draw_text(
&quote.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) {
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 {
let mut prop = properties.write().unwrap();
prop.quote = 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.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(
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,
container: &Rc<RefCell<Option<ImageContainer>>>,
) {
let file: String = match file_choice.choice() {
Some(val) => val,
None => return,
};
// 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,
// properties: &Arc<RwLock<ImageProperties>>,
// sender: &mpsc::Sender<DrawMessage>,
// ) {
// let file: String = match file_choice.choice() {
// 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 conf = file.with_extension("conf");
// let file = Path::new(&file);
// let conf = file.with_extension("conf");
let mut use_defaults = true;
if conf.exists() {
let read = fs::read_to_string(&conf).unwrap();
if let Ok(prop) = serde_json::from_str::<Properties>(&read) {
if let Some(cont) = &mut *container.borrow_mut() {
layer_red.set_value(prop.rgba[0] as f64);
layer_green.set_value(prop.rgba[1] as f64);
layer_blue.set_value(prop.rgba[2] as f64);
layer_alpha.set_value(prop.rgba[3] as f64);
quote.set_value(&prop.quote);
tag.set_value(&prop.tag);
quote_position.set_value(prop.quote_position as f64);
tag_position.set_value(prop.tag_position as f64);
cont.apply_crop_pos(prop.crop_position.0, prop.crop_position.1);
// let mut prop = properties.write().unwrap();
// 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) {
// 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);
cont.quote = prop.quote;
cont.tag = prop.tag;
cont.quote_position = prop.quote_position;
cont.tag_position = prop.quote_position;
cont.rgba = prop.rgba;
}
use_defaults = false;
}
}
// if let Some((x, y)) = saved_prop.crop_position {
// sender.send(DrawMessage::CropPos(x, y)).unwrap();
// }
if use_defaults {
if let Some(cont) = &mut *container.borrow_mut() {
quote.set_value("");
tag.set_value("");
quote_position.set_value(cont.quote_position as f64);
tag_position.set_value(cont.tag_position as f64);
cont.apply_crop();
// 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;
// }
// }
cont.rgba = [
layer_red.value() as u8,
layer_green.value() as u8,
layer_blue.value() as u8,
layer_alpha.value() as u8,
];
}
}
// if use_defaults {
// quote.set_value("");
// tag.set_value("");
if let Some(cont) = &mut *container.borrow_mut() {
cont.apply_layer();
let (width, height) = cont.image.dimensions();
page.row_flex.set_size(&page.col_flex, width as i32);
page.col_flex.set_size(&page.image, height as i32);
page.row_flex.recalc();
page.col_flex.recalc();
}
}
// 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);
// sender.send(DrawMessage::Crop).unwrap();
// 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();
// }

View File

@ -1,11 +1,22 @@
use serde::{Deserialize, Serialize};
use lazy_static::lazy_static;
use rusttype::Font;
use std::io::Read;
#[derive(Serialize, Deserialize, Debug)]
pub(crate) struct Properties {
pub(crate) quote: String,
pub(crate) tag: String,
pub(crate) quote_position: u32,
pub(crate) tag_position: u32,
pub(crate) crop_position: (u32, u32),
pub(crate) rgba: [u8; 4],
lazy_static! {
pub static ref FONT_QUOTE: Font<'static> = {
let mut buffer = Vec::new();
std::fs::File::open("ReenieBeanie-Regular.ttf")
.unwrap()
.read_to_end(&mut buffer)
.unwrap();
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()
};
}

View File

@ -1,9 +1,135 @@
use fltk::prelude::ImageExt;
use std::sync::{Arc, RwLock};
use image::{DynamicImage, GenericImageView, ImageBuffer};
use serde::{Deserialize, Serialize};
use crate::properties;
#[derive(Debug)]
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) crop_position: Option<(u32, u32)>,
pub(crate) quote: String,
@ -14,62 +140,21 @@ pub(crate) struct ImageContainer {
pub(crate) is_saved: bool,
}
impl ImageContainer {
pub(crate) fn new(path: &str) -> 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);
impl ImageProperties {
pub(crate) fn new() -> Self {
Self {
image: img,
original_dimension: (width, height),
path: "".to_owned(),
dimension: (0, 0),
original_dimension: (0, 0),
crop_position: None,
quote: String::new(),
tag: String::new(),
quote_position: (width * 2) / 3,
tag_position: width / 2,
quote: "".to_owned(),
tag: "".to_owned(),
quote_position: 0,
tag_position: 0,
rgba: [0; 4],
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) {
@ -89,11 +174,11 @@ pub(crate) fn height_from_width(width: 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 {
(height * 30) / 1556
pub(crate) fn tag_from_height(height: u32) -> u32 {
(height * 50) / 1350
}
pub(crate) fn measure_line(