parent
6517773cf3
commit
278cffd925
|
|
@ -0,0 +1 @@
|
||||||
|
{"path":"/home/piyush/Projects/post_maker/75e253532946877dea6aaa5a60ffd51a.jpg","dimension":[400.0,500.0],"original_dimension":[720.0,1280.0],"crop_position":[0.0,190.0],"quote":"wow!","tag":"","quote_position":853.3333333333334,"tag_position":853.3333333333334,"rgba":[25,29,34,190],"is_saved":false}
|
||||||
|
Before Width: | Height: | Size: 198 KiB After Width: | Height: | Size: 198 KiB |
|
|
@ -0,0 +1 @@
|
||||||
|
{"path":"/home/piyush/Projects/post_maker/bearbrickjia-20211228-0002.jpg","dimension":[400.0,500.0],"original_dimension":[1440.0,1124.0],"crop_position":[270.4,0.0],"quote":"hello","tag":"","quote_position":749.3333333333334,"tag_position":749.3333333333334,"rgba":[25,29,34,190],"is_saved":false}
|
||||||
|
Before Width: | Height: | Size: 132 KiB After Width: | Height: | Size: 132 KiB |
|
Before Width: | Height: | Size: 124 KiB After Width: | Height: | Size: 124 KiB |
|
|
@ -26,6 +26,7 @@ pub(crate) enum DrawMessage {
|
||||||
ChangeCrop((f64, f64)),
|
ChangeCrop((f64, f64)),
|
||||||
Recalc,
|
Recalc,
|
||||||
Flush,
|
Flush,
|
||||||
|
Save,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn spawn_image_thread(
|
pub(crate) fn spawn_image_thread(
|
||||||
|
|
@ -98,6 +99,13 @@ pub(crate) fn spawn_image_thread(
|
||||||
DrawMessage::Flush => {
|
DrawMessage::Flush => {
|
||||||
flush_buffer(&app_sender, &mut _container);
|
flush_buffer(&app_sender, &mut _container);
|
||||||
}
|
}
|
||||||
|
DrawMessage::Save => {
|
||||||
|
if let Some(cont) = &mut _container {
|
||||||
|
status.set_label("Saving...");
|
||||||
|
cont.save();
|
||||||
|
status.set_label("");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
@ -154,6 +162,7 @@ fn load_image(
|
||||||
prop.quote_position = saved_prop.quote_position;
|
prop.quote_position = saved_prop.quote_position;
|
||||||
prop.tag_position = saved_prop.quote_position;
|
prop.tag_position = saved_prop.quote_position;
|
||||||
prop.rgba = saved_prop.rgba;
|
prop.rgba = saved_prop.rgba;
|
||||||
|
prop.is_saved = true;
|
||||||
use_defaults = false;
|
use_defaults = false;
|
||||||
let saved = prop.is_saved;
|
let saved = prop.is_saved;
|
||||||
drop(prop);
|
drop(prop);
|
||||||
|
|
@ -173,7 +182,6 @@ fn load_image(
|
||||||
if use_defaults {
|
if use_defaults {
|
||||||
let mut prop = properties.write().unwrap();
|
let mut prop = properties.write().unwrap();
|
||||||
prop.quote = "".to_owned();
|
prop.quote = "".to_owned();
|
||||||
|
|
||||||
quote_position.set_range(0.0, prop.original_dimension.1);
|
quote_position.set_range(0.0, prop.original_dimension.1);
|
||||||
quote_position.set_value(prop.quote_position);
|
quote_position.set_value(prop.quote_position);
|
||||||
tag_position.set_range(0.0, prop.original_dimension.1);
|
tag_position.set_range(0.0, prop.original_dimension.1);
|
||||||
|
|
@ -185,11 +193,18 @@ fn load_image(
|
||||||
layer_blue.value() as u8,
|
layer_blue.value() as u8,
|
||||||
layer_alpha.value() as u8,
|
layer_alpha.value() as u8,
|
||||||
];
|
];
|
||||||
drop(prop);
|
|
||||||
|
|
||||||
match crop {
|
match crop {
|
||||||
Some((x, y)) => cont.apply_crop_pos(x, y),
|
Some((x, y)) => {
|
||||||
None => cont.apply_crop(),
|
prop.is_saved = false;
|
||||||
|
drop(prop);
|
||||||
|
cont.apply_crop_pos(x, y);
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
prop.is_saved = true;
|
||||||
|
drop(prop);
|
||||||
|
cont.apply_crop();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -254,11 +254,12 @@ impl MainWindow {
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
let sender = self.sender.clone();
|
||||||
self.menubar.add(
|
self.menubar.add(
|
||||||
"&File/Save...\t",
|
"&File/Save...\t",
|
||||||
Shortcut::Ctrl | 's',
|
Shortcut::Ctrl | 's',
|
||||||
menu::MenuFlag::Normal,
|
menu::MenuFlag::Normal,
|
||||||
|_| {},
|
move |_| sender.send(DrawMessage::Save).unwrap(),
|
||||||
);
|
);
|
||||||
|
|
||||||
self.menubar.add(
|
self.menubar.add(
|
||||||
|
|
@ -290,21 +291,37 @@ impl MainWindow {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn events(&mut self) {
|
fn events(&mut self) {
|
||||||
|
let sender = self.sender.clone();
|
||||||
|
self.save_btn
|
||||||
|
.set_callback(move |_| sender.send(DrawMessage::Save).unwrap());
|
||||||
|
|
||||||
let properties = Arc::clone(&self.properties);
|
let properties = Arc::clone(&self.properties);
|
||||||
let mut crop_win = CropWindow::new();
|
let mut crop_win = CropWindow::new();
|
||||||
let sender = self.sender.clone();
|
let sender = self.sender.clone();
|
||||||
self.crop_btn.set_callback(move |_| {
|
self.crop_btn.set_callback(move |_| {
|
||||||
let prop = properties.read().unwrap();
|
let mut prop = properties.write().unwrap();
|
||||||
if let Some(path) = &prop.path {
|
if let Some(path) = &prop.path {
|
||||||
if let Some((x, y)) = crop_win.load_to_crop(path, prop.crop_position) {
|
if let Some((x, y)) = crop_win.load_to_crop(path, prop.crop_position) {
|
||||||
sender.send(DrawMessage::ChangeCrop((x, y))).unwrap();
|
sender.send(DrawMessage::ChangeCrop((x, y))).unwrap();
|
||||||
|
prop.is_saved = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
let mut file_choice = self.file_choice.clone();
|
let mut file_choice = self.file_choice.clone();
|
||||||
let sender = self.sender.clone();
|
let sender = self.sender.clone();
|
||||||
|
let properties = Arc::clone(&self.properties);
|
||||||
self.next_btn.set_callback(move |_| {
|
self.next_btn.set_callback(move |_| {
|
||||||
|
let prop = properties.read().unwrap();
|
||||||
|
if !prop.is_saved {
|
||||||
|
let save = fltk::dialog::choice_default("Save?", "yes", "no", "cancel");
|
||||||
|
match save {
|
||||||
|
0 => sender.send(DrawMessage::Save).unwrap(),
|
||||||
|
1 => {}
|
||||||
|
_ => return,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if file_choice.value() == file_choice.size() - 2 {
|
if file_choice.value() == file_choice.size() - 2 {
|
||||||
file_choice.set_value(0);
|
file_choice.set_value(0);
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -315,7 +332,18 @@ impl MainWindow {
|
||||||
|
|
||||||
let mut file_choice = self.file_choice.clone();
|
let mut file_choice = self.file_choice.clone();
|
||||||
let sender = self.sender.clone();
|
let sender = self.sender.clone();
|
||||||
|
let properties = Arc::clone(&self.properties);
|
||||||
self.back_btn.set_callback(move |_| {
|
self.back_btn.set_callback(move |_| {
|
||||||
|
let prop = properties.read().unwrap();
|
||||||
|
if !prop.is_saved {
|
||||||
|
let save = fltk::dialog::choice_default("Save?", "yes", "no", "cancel");
|
||||||
|
match save {
|
||||||
|
0 => sender.send(DrawMessage::Save).unwrap(),
|
||||||
|
1 => {}
|
||||||
|
_ => return,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if file_choice.value() == 0 {
|
if file_choice.value() == 0 {
|
||||||
file_choice.set_value(file_choice.size() - 2);
|
file_choice.set_value(file_choice.size() - 2);
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -325,7 +353,17 @@ impl MainWindow {
|
||||||
});
|
});
|
||||||
|
|
||||||
let sender = self.sender.clone();
|
let sender = self.sender.clone();
|
||||||
|
let properties = Arc::clone(&self.properties);
|
||||||
self.file_choice.set_callback(move |_| {
|
self.file_choice.set_callback(move |_| {
|
||||||
|
let prop = properties.read().unwrap();
|
||||||
|
if !prop.is_saved {
|
||||||
|
let save = fltk::dialog::choice_default("Save?", "yes", "no", "cancel");
|
||||||
|
match save {
|
||||||
|
0 => sender.send(DrawMessage::Save).unwrap(),
|
||||||
|
1 => {}
|
||||||
|
_ => return,
|
||||||
|
}
|
||||||
|
}
|
||||||
sender.send(DrawMessage::Open).unwrap();
|
sender.send(DrawMessage::Open).unwrap();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -336,6 +374,7 @@ impl MainWindow {
|
||||||
if ev == enums::Event::KeyUp {
|
if ev == enums::Event::KeyUp {
|
||||||
let mut prop = properties.write().unwrap();
|
let mut prop = properties.write().unwrap();
|
||||||
prop.quote = f.value();
|
prop.quote = f.value();
|
||||||
|
prop.is_saved = false;
|
||||||
sender.send(DrawMessage::Recalc).unwrap();
|
sender.send(DrawMessage::Recalc).unwrap();
|
||||||
sender.send(DrawMessage::Flush).unwrap();
|
sender.send(DrawMessage::Flush).unwrap();
|
||||||
image.redraw();
|
image.redraw();
|
||||||
|
|
@ -350,6 +389,7 @@ impl MainWindow {
|
||||||
if ev == enums::Event::KeyUp {
|
if ev == enums::Event::KeyUp {
|
||||||
let mut prop = properties.write().unwrap();
|
let mut prop = properties.write().unwrap();
|
||||||
prop.tag = f.value();
|
prop.tag = f.value();
|
||||||
|
prop.is_saved = false;
|
||||||
sender.send(DrawMessage::Recalc).unwrap();
|
sender.send(DrawMessage::Recalc).unwrap();
|
||||||
sender.send(DrawMessage::Flush).unwrap();
|
sender.send(DrawMessage::Flush).unwrap();
|
||||||
image.redraw();
|
image.redraw();
|
||||||
|
|
@ -363,6 +403,7 @@ impl MainWindow {
|
||||||
self.quote_position.set_callback(move |f| {
|
self.quote_position.set_callback(move |f| {
|
||||||
let mut prop = properties.write().unwrap();
|
let mut prop = properties.write().unwrap();
|
||||||
prop.quote_position = f.value();
|
prop.quote_position = f.value();
|
||||||
|
prop.is_saved = false;
|
||||||
sender.send(DrawMessage::Recalc).unwrap();
|
sender.send(DrawMessage::Recalc).unwrap();
|
||||||
sender.send(DrawMessage::Flush).unwrap();
|
sender.send(DrawMessage::Flush).unwrap();
|
||||||
image.redraw();
|
image.redraw();
|
||||||
|
|
@ -374,6 +415,7 @@ impl MainWindow {
|
||||||
self.tag_position.set_callback(move |f| {
|
self.tag_position.set_callback(move |f| {
|
||||||
let mut prop = properties.write().unwrap();
|
let mut prop = properties.write().unwrap();
|
||||||
prop.tag_position = f.value();
|
prop.tag_position = f.value();
|
||||||
|
prop.is_saved = false;
|
||||||
sender.send(DrawMessage::Recalc).unwrap();
|
sender.send(DrawMessage::Recalc).unwrap();
|
||||||
sender.send(DrawMessage::Flush).unwrap();
|
sender.send(DrawMessage::Flush).unwrap();
|
||||||
image.redraw();
|
image.redraw();
|
||||||
|
|
@ -385,6 +427,7 @@ impl MainWindow {
|
||||||
self.layer_red.set_callback(move |f| {
|
self.layer_red.set_callback(move |f| {
|
||||||
let mut prop = properties.write().unwrap();
|
let mut prop = properties.write().unwrap();
|
||||||
prop.rgba[0] = f.value() as u8;
|
prop.rgba[0] = f.value() as u8;
|
||||||
|
prop.is_saved = false;
|
||||||
sender.send(DrawMessage::Recalc).unwrap();
|
sender.send(DrawMessage::Recalc).unwrap();
|
||||||
sender.send(DrawMessage::Flush).unwrap();
|
sender.send(DrawMessage::Flush).unwrap();
|
||||||
image.redraw();
|
image.redraw();
|
||||||
|
|
@ -396,6 +439,7 @@ impl MainWindow {
|
||||||
self.layer_green.set_callback(move |f| {
|
self.layer_green.set_callback(move |f| {
|
||||||
let mut prop = properties.write().unwrap();
|
let mut prop = properties.write().unwrap();
|
||||||
prop.rgba[1] = f.value() as u8;
|
prop.rgba[1] = f.value() as u8;
|
||||||
|
prop.is_saved = false;
|
||||||
sender.send(DrawMessage::Recalc).unwrap();
|
sender.send(DrawMessage::Recalc).unwrap();
|
||||||
sender.send(DrawMessage::Flush).unwrap();
|
sender.send(DrawMessage::Flush).unwrap();
|
||||||
image.redraw();
|
image.redraw();
|
||||||
|
|
@ -407,6 +451,7 @@ impl MainWindow {
|
||||||
self.layer_blue.set_callback(move |f| {
|
self.layer_blue.set_callback(move |f| {
|
||||||
let mut prop = properties.write().unwrap();
|
let mut prop = properties.write().unwrap();
|
||||||
prop.rgba[2] = f.value() as u8;
|
prop.rgba[2] = f.value() as u8;
|
||||||
|
prop.is_saved = false;
|
||||||
sender.send(DrawMessage::Recalc).unwrap();
|
sender.send(DrawMessage::Recalc).unwrap();
|
||||||
sender.send(DrawMessage::Flush).unwrap();
|
sender.send(DrawMessage::Flush).unwrap();
|
||||||
image.redraw();
|
image.redraw();
|
||||||
|
|
@ -418,6 +463,7 @@ impl MainWindow {
|
||||||
self.layer_alpha.set_callback(move |f| {
|
self.layer_alpha.set_callback(move |f| {
|
||||||
let mut prop = properties.write().unwrap();
|
let mut prop = properties.write().unwrap();
|
||||||
prop.rgba[3] = f.value() as u8;
|
prop.rgba[3] = f.value() as u8;
|
||||||
|
prop.is_saved = false;
|
||||||
sender.send(DrawMessage::Recalc).unwrap();
|
sender.send(DrawMessage::Recalc).unwrap();
|
||||||
sender.send(DrawMessage::Flush).unwrap();
|
sender.send(DrawMessage::Flush).unwrap();
|
||||||
image.redraw();
|
image.redraw();
|
||||||
|
|
|
||||||
92
src/utils.rs
92
src/utils.rs
|
|
@ -1,4 +1,8 @@
|
||||||
use std::sync::{Arc, RwLock};
|
use std::{
|
||||||
|
fs,
|
||||||
|
path::Path,
|
||||||
|
sync::{Arc, RwLock},
|
||||||
|
};
|
||||||
|
|
||||||
use image::{DynamicImage, GenericImageView, ImageBuffer};
|
use image::{DynamicImage, GenericImageView, ImageBuffer};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
@ -176,6 +180,92 @@ impl ImageContainer {
|
||||||
|
|
||||||
self.buffer = tmp;
|
self.buffer = tmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn save(&self) {
|
||||||
|
let prop = self.properties.read().unwrap();
|
||||||
|
|
||||||
|
let path_original = match &prop.path {
|
||||||
|
Some(p) => Path::new(p),
|
||||||
|
None => return,
|
||||||
|
};
|
||||||
|
let path_conf = path_original.with_extension("conf");
|
||||||
|
let export = path_original
|
||||||
|
.parent()
|
||||||
|
.unwrap()
|
||||||
|
.join("export")
|
||||||
|
.join(path_original.file_name().unwrap().to_str().unwrap());
|
||||||
|
|
||||||
|
fs::write(&path_conf, serde_json::to_string(&*prop).unwrap()).unwrap();
|
||||||
|
|
||||||
|
let mut img = image::open(&path_original).unwrap();
|
||||||
|
let (width, height): (f64, f64) = Coord::from(img.dimensions()).into();
|
||||||
|
let (crop_x, crop_y) = prop.crop_position.unwrap();
|
||||||
|
let (crop_width, crop_height) = get_4_5(width, height);
|
||||||
|
let mut img = img.crop(
|
||||||
|
crop_x as u32,
|
||||||
|
crop_y as u32,
|
||||||
|
crop_width as u32,
|
||||||
|
crop_height as u32,
|
||||||
|
);
|
||||||
|
|
||||||
|
let layer = DynamicImage::ImageRgba8(ImageBuffer::from_fn(
|
||||||
|
crop_width as u32,
|
||||||
|
crop_height as u32,
|
||||||
|
|_, _| image::Rgba(prop.rgba),
|
||||||
|
));
|
||||||
|
image::imageops::overlay(&mut img, &layer, 0, 0);
|
||||||
|
|
||||||
|
let size = quote_from_height(crop_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 img,
|
||||||
|
image::Rgba([255, 255, 255, 255]),
|
||||||
|
((crop_width - text_width) / 2.0) as u32,
|
||||||
|
((prop.quote_position * crop_height) / prop.original_dimension.1
|
||||||
|
+ (text_height / 2.0)
|
||||||
|
+ index as f64 * (text_height * 1.2)) as u32,
|
||||||
|
rusttype::Scale::uniform(size as f32),
|
||||||
|
&properties::FONT_QUOTE,
|
||||||
|
line,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
let size = tag_from_height(crop_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 img,
|
||||||
|
image::Rgba([255, 255, 255, 255]),
|
||||||
|
(crop_width * 0.99 - text_width) as u32,
|
||||||
|
((prop.tag_position * crop_height) / prop.original_dimension.1
|
||||||
|
+ (text_height / 2.0)
|
||||||
|
+ index as f64 * (text_height * 1.2)) as u32,
|
||||||
|
rusttype::Scale::uniform(size as f32),
|
||||||
|
&properties::FONT_TAG,
|
||||||
|
line,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
image::save_buffer(
|
||||||
|
export,
|
||||||
|
img.as_rgb8().unwrap().as_raw(),
|
||||||
|
crop_width as u32,
|
||||||
|
crop_height as u32,
|
||||||
|
image::ColorType::Rgb8,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug)]
|
#[derive(Serialize, Deserialize, Debug)]
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue