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)),
|
||||
Recalc,
|
||||
Flush,
|
||||
Save,
|
||||
}
|
||||
|
||||
pub(crate) fn spawn_image_thread(
|
||||
|
|
@ -98,6 +99,13 @@ pub(crate) fn spawn_image_thread(
|
|||
DrawMessage::Flush => {
|
||||
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.tag_position = saved_prop.quote_position;
|
||||
prop.rgba = saved_prop.rgba;
|
||||
prop.is_saved = true;
|
||||
use_defaults = false;
|
||||
let saved = prop.is_saved;
|
||||
drop(prop);
|
||||
|
|
@ -173,7 +182,6 @@ fn load_image(
|
|||
if use_defaults {
|
||||
let mut prop = properties.write().unwrap();
|
||||
prop.quote = "".to_owned();
|
||||
|
||||
quote_position.set_range(0.0, prop.original_dimension.1);
|
||||
quote_position.set_value(prop.quote_position);
|
||||
tag_position.set_range(0.0, prop.original_dimension.1);
|
||||
|
|
@ -185,11 +193,18 @@ fn load_image(
|
|||
layer_blue.value() as u8,
|
||||
layer_alpha.value() as u8,
|
||||
];
|
||||
drop(prop);
|
||||
|
||||
match crop {
|
||||
Some((x, y)) => cont.apply_crop_pos(x, y),
|
||||
None => cont.apply_crop(),
|
||||
Some((x, y)) => {
|
||||
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(
|
||||
"&File/Save...\t",
|
||||
Shortcut::Ctrl | 's',
|
||||
menu::MenuFlag::Normal,
|
||||
|_| {},
|
||||
move |_| sender.send(DrawMessage::Save).unwrap(),
|
||||
);
|
||||
|
||||
self.menubar.add(
|
||||
|
|
@ -290,21 +291,37 @@ impl MainWindow {
|
|||
}
|
||||
|
||||
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 mut crop_win = CropWindow::new();
|
||||
let sender = self.sender.clone();
|
||||
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((x, y)) = crop_win.load_to_crop(path, prop.crop_position) {
|
||||
sender.send(DrawMessage::ChangeCrop((x, y))).unwrap();
|
||||
prop.is_saved = false;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
let mut file_choice = self.file_choice.clone();
|
||||
let sender = self.sender.clone();
|
||||
let properties = Arc::clone(&self.properties);
|
||||
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 {
|
||||
file_choice.set_value(0);
|
||||
} else {
|
||||
|
|
@ -315,7 +332,18 @@ impl MainWindow {
|
|||
|
||||
let mut file_choice = self.file_choice.clone();
|
||||
let sender = self.sender.clone();
|
||||
let properties = Arc::clone(&self.properties);
|
||||
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 {
|
||||
file_choice.set_value(file_choice.size() - 2);
|
||||
} else {
|
||||
|
|
@ -325,7 +353,17 @@ impl MainWindow {
|
|||
});
|
||||
|
||||
let sender = self.sender.clone();
|
||||
let properties = Arc::clone(&self.properties);
|
||||
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();
|
||||
});
|
||||
|
||||
|
|
@ -336,6 +374,7 @@ impl MainWindow {
|
|||
if ev == enums::Event::KeyUp {
|
||||
let mut prop = properties.write().unwrap();
|
||||
prop.quote = f.value();
|
||||
prop.is_saved = false;
|
||||
sender.send(DrawMessage::Recalc).unwrap();
|
||||
sender.send(DrawMessage::Flush).unwrap();
|
||||
image.redraw();
|
||||
|
|
@ -350,6 +389,7 @@ impl MainWindow {
|
|||
if ev == enums::Event::KeyUp {
|
||||
let mut prop = properties.write().unwrap();
|
||||
prop.tag = f.value();
|
||||
prop.is_saved = false;
|
||||
sender.send(DrawMessage::Recalc).unwrap();
|
||||
sender.send(DrawMessage::Flush).unwrap();
|
||||
image.redraw();
|
||||
|
|
@ -363,6 +403,7 @@ impl MainWindow {
|
|||
self.quote_position.set_callback(move |f| {
|
||||
let mut prop = properties.write().unwrap();
|
||||
prop.quote_position = f.value();
|
||||
prop.is_saved = false;
|
||||
sender.send(DrawMessage::Recalc).unwrap();
|
||||
sender.send(DrawMessage::Flush).unwrap();
|
||||
image.redraw();
|
||||
|
|
@ -374,6 +415,7 @@ impl MainWindow {
|
|||
self.tag_position.set_callback(move |f| {
|
||||
let mut prop = properties.write().unwrap();
|
||||
prop.tag_position = f.value();
|
||||
prop.is_saved = false;
|
||||
sender.send(DrawMessage::Recalc).unwrap();
|
||||
sender.send(DrawMessage::Flush).unwrap();
|
||||
image.redraw();
|
||||
|
|
@ -385,6 +427,7 @@ impl MainWindow {
|
|||
self.layer_red.set_callback(move |f| {
|
||||
let mut prop = properties.write().unwrap();
|
||||
prop.rgba[0] = f.value() as u8;
|
||||
prop.is_saved = false;
|
||||
sender.send(DrawMessage::Recalc).unwrap();
|
||||
sender.send(DrawMessage::Flush).unwrap();
|
||||
image.redraw();
|
||||
|
|
@ -396,6 +439,7 @@ impl MainWindow {
|
|||
self.layer_green.set_callback(move |f| {
|
||||
let mut prop = properties.write().unwrap();
|
||||
prop.rgba[1] = f.value() as u8;
|
||||
prop.is_saved = false;
|
||||
sender.send(DrawMessage::Recalc).unwrap();
|
||||
sender.send(DrawMessage::Flush).unwrap();
|
||||
image.redraw();
|
||||
|
|
@ -407,6 +451,7 @@ impl MainWindow {
|
|||
self.layer_blue.set_callback(move |f| {
|
||||
let mut prop = properties.write().unwrap();
|
||||
prop.rgba[2] = f.value() as u8;
|
||||
prop.is_saved = false;
|
||||
sender.send(DrawMessage::Recalc).unwrap();
|
||||
sender.send(DrawMessage::Flush).unwrap();
|
||||
image.redraw();
|
||||
|
|
@ -418,6 +463,7 @@ impl MainWindow {
|
|||
self.layer_alpha.set_callback(move |f| {
|
||||
let mut prop = properties.write().unwrap();
|
||||
prop.rgba[3] = f.value() as u8;
|
||||
prop.is_saved = false;
|
||||
sender.send(DrawMessage::Recalc).unwrap();
|
||||
sender.send(DrawMessage::Flush).unwrap();
|
||||
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 serde::{Deserialize, Serialize};
|
||||
|
|
@ -176,6 +180,92 @@ impl ImageContainer {
|
|||
|
||||
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)]
|
||||
|
|
|
|||
Loading…
Reference in New Issue