* Added support for blured box around quotes

* Removed useless ttf and added opensans
* Cleaned global and grouped all fonts together in one function
This commit is contained in:
Piyush मिश्रः 2022-08-17 20:00:26 +05:30
parent 55d394380d
commit 90d72f9d4e
12 changed files with 475 additions and 296 deletions

470
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,6 @@
[package]
name = "post_maker"
version = "0.5.0-alpha.1"
version = "0.6.0-alpha.1"
edition = "2021"
description = "Post Maker helps you to make post for Instagram and other Social Media apps easily."
authors = ["PiyushXCoder <https://piyushxcoder.in>"]

BIN
assets/OpenSans-Regular.ttf Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -132,6 +132,7 @@ pub(crate) struct ConfigFile {
pub(crate) color_layer: [u8; 4],
pub(crate) minimum_width_limit: f64, // for export of image
pub(crate) maximum_width_limit: f64, // for export of image
pub(crate) draw_box_around_quote: bool,
pub(crate) image_format: ImageType,
}
@ -155,10 +156,11 @@ impl Default for ConfigFile {
tag_y_position_ratio: 0.5,
tag2_position_ratio: 0.95,
image_ratio: (4.0, 5.0),
color_layer: [20, 22, 25, 197],
color_layer: [20, 22, 25, 80],
minimum_width_limit: 650.0,
maximum_width_limit: 1080.0,
image_format: ImageType::Png,
draw_box_around_quote: true,
image_format: ImageType::Jpeg,
}
}
}

View File

@ -23,7 +23,7 @@ use crate::{
use fltk::{
app,
browser::{Browser, BrowserType},
button::{Button, RadioRoundButton},
button::{Button, CheckButton, RadioRoundButton},
dialog::{FileDialogOptions, NativeFileChooser},
enums::{self, Align, Event, Font},
frame::Frame,
@ -65,6 +65,7 @@ pub(crate) struct ConfigWindow {
pub(crate) tag2_position_ratio: ValueInput,
pub(crate) image_ratio_width: ValueInput,
pub(crate) image_ratio_height: ValueInput,
pub(crate) draw_box_around_quote: CheckButton,
pub(crate) minimum_width_limit: ValueInput,
pub(crate) maximum_width_limit: ValueInput,
/// RGB value of top translucent layer
@ -389,6 +390,18 @@ impl ConfigWindow {
image_ratio_grp.end();
col.set_size(&image_ratio_grp, 30);
// Draw box around Quote
let mut label = Frame::default().with_label("Draw Box:");
label.set_label_font(enums::Font::HelveticaBold);
col.set_size(&label, 15);
let mut draw_box_around_quote_flex = Flex::default().row();
draw_box_around_quote_flex.set_size(&Frame::default(), 20);
let mut draw_box_around_quote = CheckButton::default().with_label("Draw box around text");
draw_box_around_quote.set_value(true);
draw_box_around_quote_flex.end();
col.set_size(&draw_box_around_quote_flex, 30);
let mut label = Frame::default().with_label("Image with limits:");
label.set_label_font(enums::Font::HelveticaBold);
col.set_size(&label, 15);
@ -505,6 +518,7 @@ impl ConfigWindow {
tag2_position_ratio,
image_ratio_width,
image_ratio_height,
draw_box_around_quote,
minimum_width_limit,
maximum_width_limit,
translucent_layer_rgb,
@ -561,6 +575,8 @@ impl ConfigWindow {
.set_value(config.tag2_position_ratio);
self.image_ratio_width.set_value(config.image_ratio.0);
self.image_ratio_height.set_value(config.image_ratio.1);
self.draw_box_around_quote
.set_checked(config.draw_box_around_quote);
self.minimum_width_limit
.set_value(config.minimum_width_limit);
self.maximum_width_limit
@ -611,6 +627,7 @@ impl ConfigWindow {
let mut tag2_position_ratio = self.tag2_position_ratio.clone();
let mut image_ratio_width = self.image_ratio_width.clone();
let mut image_ratio_height = self.image_ratio_height.clone();
let draw_box_around_quote = self.draw_box_around_quote.clone();
let mut minimum_width_limit = self.minimum_width_limit.clone();
let mut maximum_width_limit = self.maximum_width_limit.clone();
let mut layer_rgb = self.translucent_layer_rgb.clone();
@ -657,6 +674,7 @@ impl ConfigWindow {
tag2_position_ratio.set_value(conf.tag2_position_ratio);
image_ratio_width.set_value(conf.image_ratio.0);
image_ratio_height.set_value(conf.image_ratio.1);
draw_box_around_quote.set_checked(conf.draw_box_around_quote);
minimum_width_limit.set_value(conf.minimum_width_limit);
maximum_width_limit.set_value(conf.maximum_width_limit);
utils::set_color_btn_rgba(conf.color_layer, &mut layer_rgb);
@ -687,6 +705,7 @@ impl ConfigWindow {
let mut tag2_position_ratio = self.tag2_position_ratio.clone();
let mut image_ratio_width = self.image_ratio_width.clone();
let mut image_ratio_height = self.image_ratio_height.clone();
let draw_box_around_quote = self.draw_box_around_quote.clone();
let mut minimum_width_limit = self.minimum_width_limit.clone();
let mut maximum_width_limit = self.maximum_width_limit.clone();
let mut layer_rgb = self.translucent_layer_rgb.clone();
@ -732,6 +751,7 @@ impl ConfigWindow {
tag2_position_ratio.set_value(conf.tag2_position_ratio);
image_ratio_width.set_value(conf.image_ratio.0);
image_ratio_height.set_value(conf.image_ratio.1);
draw_box_around_quote.set_checked(conf.draw_box_around_quote);
minimum_width_limit.set_value(conf.minimum_width_limit);
maximum_width_limit.set_value(conf.maximum_width_limit);
utils::set_color_btn_rgba(conf.color_layer, &mut layer_rgb);
@ -759,6 +779,7 @@ impl ConfigWindow {
let mut tag2_position_ratio = self.tag2_position_ratio.clone();
let mut image_ratio_width = self.image_ratio_width.clone();
let mut image_ratio_height = self.image_ratio_height.clone();
let draw_box_around_quote = self.draw_box_around_quote.clone();
let mut minimum_width_limit = self.minimum_width_limit.clone();
let mut maximum_width_limit = self.maximum_width_limit.clone();
let mut layer_rgb = self.translucent_layer_rgb.clone();
@ -794,6 +815,7 @@ impl ConfigWindow {
tag2_position_ratio.set_value(conf.tag2_position_ratio);
image_ratio_width.set_value(conf.image_ratio.0);
image_ratio_height.set_value(conf.image_ratio.1);
draw_box_around_quote.set_checked(conf.draw_box_around_quote);
minimum_width_limit.set_value(conf.minimum_width_limit);
maximum_width_limit.set_value(conf.maximum_width_limit);
utils::set_color_btn_rgba(conf.color_layer, &mut layer_rgb);
@ -1108,6 +1130,18 @@ impl ConfigWindow {
true
});
let browse = self.browse.clone();
let configs = Rc::clone(&self.configs);
self.draw_box_around_quote.handle(move |f, _| {
if let Some(conf) = configs
.borrow_mut()
.get_mut(&browse.selected_text().unwrap())
{
conf.draw_box_around_quote = f.value();
}
true
});
// Minimum Width Limit
let browse = self.browse.clone();
let configs = Rc::clone(&self.configs);
@ -1225,6 +1259,7 @@ impl ConfigWindow {
let mut tag2_position_ratio = self.tag2_position_ratio.clone();
let mut image_ratio_width = self.image_ratio_width.clone();
let mut image_ratio_height = self.image_ratio_height.clone();
let draw_box_around_quote = self.draw_box_around_quote.clone();
let mut minimum_width_limit = self.minimum_width_limit.clone();
let mut maximum_width_limit = self.maximum_width_limit.clone();
let mut layer_rgb = self.translucent_layer_rgb.clone();
@ -1253,13 +1288,23 @@ impl ConfigWindow {
tag2_position_ratio.set_value(conf.tag2_position_ratio);
image_ratio_width.set_value(conf.image_ratio.0);
image_ratio_height.set_value(conf.image_ratio.1);
draw_box_around_quote.set_checked(conf.draw_box_around_quote);
minimum_width_limit.set_value(conf.minimum_width_limit);
maximum_width_limit.set_value(conf.maximum_width_limit);
utils::set_color_btn_rgba(conf.color_layer, &mut layer_rgb);
layer_rgb.redraw();
layer_alpha.set_value(conf.color_layer[3] as f64);
match conf.image_format {
ImageType::Png => {
png_format.set_value(true);
jpeg_format.set_value(false);
}
ImageType::Jpeg => {
png_format.set_value(false);
jpeg_format.set_value(true);
}
_ => {}
}
configs
.borrow_mut()
.insert(browse.selected_text().unwrap(), conf);

View File

@ -18,5 +18,5 @@ pub(crate) fn message_default(txt: &str) {
pub(crate) fn choice_default(txt: &str, b0: &str, b1: &str) -> i32 {
let (x, y) = get_mouse();
dialog::choice(x, y, txt, b0, b1, "")
dialog::choice2(x, y, txt, b0, b1, "").unwrap_or(-1)
}

View File

@ -33,85 +33,19 @@ lazy_static! {
pub(crate) static ref MAIN_SENDER: RwLock<Option<fltk::app::Sender<crate::AppMessage>>> = RwLock::new(None);
/// TTF Font for Quote
pub(crate) static ref FONT_QUOTE: Font<'static> = {
let mut buffer = Vec::new();
if let Ok(mut file) = std::fs::File::open(rw_read!(CONFIG).quote_font.as_str()) {
if let Ok(_) = file.read_to_end(&mut buffer) {
if let Some(out) = rusttype::Font::try_from_vec(buffer) {
return out;
}
}
}
rusttype::Font::try_from_vec(
include_bytes!("../assets/fonts/ReenieBeanie-Regular.ttf").to_vec(),
)
.unwrap()
};
pub(crate) static ref FONT_QUOTE: Font<'static> = load_font(rw_read!(CONFIG).quote_font.as_str());
/// TTF Font for Subquote
pub(crate) static ref FONT_SUBQUOTE: Font<'static> = {
let mut buffer = Vec::new();
if let Ok(mut file) = std::fs::File::open(rw_read!(CONFIG).subquote_font.as_str())
{
if let Ok(_) = file.read_to_end(&mut buffer) {
if let Some(out) = rusttype::Font::try_from_vec(buffer) {
return out;
}
}
}
rusttype::Font::try_from_vec(
include_bytes!("../assets/fonts/ReenieBeanie-Regular.ttf").to_vec(),
)
.unwrap()
};
pub(crate) static ref FONT_SUBQUOTE: Font<'static> = load_font(rw_read!(CONFIG).subquote_font.as_str());
/// TTF Font for Subquote 2
pub(crate) static ref FONT_SUBQUOTE2: Font<'static> = {
let mut buffer = Vec::new();
if let Ok(mut file) =
std::fs::File::open(rw_read!(CONFIG).subquote2_font.as_str())
{
if let Ok(_) = file.read_to_end(&mut buffer) {
if let Some(out) = rusttype::Font::try_from_vec(buffer) {
return out;
}
}
}
rusttype::Font::try_from_vec(
include_bytes!("../assets/fonts/Rajdhani-Regular.ttf").to_vec(),
)
.unwrap()
};
pub(crate) static ref FONT_SUBQUOTE2: Font<'static> = load_font(rw_read!(CONFIG).subquote2_font.as_str());
/// TTF Font for Tag
pub(crate) static ref FONT_TAG: Font<'static> = {
let mut buffer = Vec::new();
if let Ok(mut file) = std::fs::File::open(&rw_read!(CONFIG).tag_font.as_str()) {
if let Ok(_) = file.read_to_end(&mut buffer) {
if let Some(out) = rusttype::Font::try_from_vec(buffer) {
return out;
}
}
}
rusttype::Font::try_from_vec(include_bytes!("../assets/fonts/Kalam-Regular.ttf").to_vec())
.unwrap()
};
pub(crate) static ref FONT_TAG: Font<'static> = load_font(rw_read!(CONFIG).tag_font.as_str());
/// TTF Font for Tag 2
pub(crate) static ref FONT_TAG2: Font<'static> = {
let mut buffer = Vec::new();
if let Ok(mut file) = std::fs::File::open(&rw_read!(CONFIG).tag2_font.as_str()) {
if let Ok(_) = file.read_to_end(&mut buffer) {
if let Some(out) = rusttype::Font::try_from_vec(buffer) {
return out;
}
}
}
rusttype::Font::try_from_vec(
include_bytes!("../assets/fonts/Rajdhani-Regular.ttf").to_vec(),
)
.unwrap()
};
pub(crate) static ref FONT_TAG2: Font<'static> = load_font(rw_read!(CONFIG).tag2_font.as_str());
/// Image to use for Window
pub(crate) static ref ICON: OsString = include_str!("../assets/icon.svg").into();
@ -128,3 +62,15 @@ lazy_static! {
img.into()
};
}
fn load_font(path: &str) -> Font<'static> {
let mut buffer = Vec::new();
if let Ok(mut file) = std::fs::File::open(path) {
if let Ok(_) = file.read_to_end(&mut buffer) {
if let Some(out) = rusttype::Font::try_from_vec(buffer) {
return out;
}
}
}
rusttype::Font::try_from_vec(include_bytes!("../assets/OpenSans-Regular.ttf").to_vec()).unwrap()
}

View File

@ -777,8 +777,8 @@ impl MainWindow {
self.next_btn.set_callback(move |_| {
let prop = rw_read!(properties);
if !prop.is_saved {
let save = fltk::dialog::choice_default("Save?", "yes", "no", "cancel");
match save {
let save = fltk::dialog::choice2_default("Save?", "yes", "no", "cancel");
match save.unwrap_or(-1) {
0 => sender.send_it(DrawMessage::Save),
1 => {}
_ => return,
@ -801,8 +801,8 @@ impl MainWindow {
self.back_btn.set_callback(move |_| {
let prop = rw_read!(properties);
if !prop.is_saved {
let save = fltk::dialog::choice_default("Save?", "yes", "no", "cancel");
match save {
let save = fltk::dialog::choice2_default("Save?", "yes", "no", "cancel");
match save.unwrap_or(-1) {
0 => sender.send_it(DrawMessage::Save),
1 => {}
_ => return,
@ -824,8 +824,8 @@ impl MainWindow {
self.file_choice.set_callback(move |_| {
let prop = rw_read!(properties);
if !prop.is_saved {
let save = fltk::dialog::choice_default("Save?", "yes", "no", "cancel");
match save {
let save = fltk::dialog::choice2_default("Save?", "yes", "no", "cancel");
match save.unwrap_or(-1) {
0 => sender.send_it(DrawMessage::Save),
1 => {}
_ => return,

View File

@ -20,7 +20,8 @@ use std::{
};
use fltk::{button::Button, enums, prelude::*};
use image::{DynamicImage, GenericImageView, ImageBuffer, ImageEncoder};
use image::{DynamicImage, GenericImageView, ImageBuffer, ImageEncoder, Pixel};
use imageproc::rect::Rect;
use serde::{Deserialize, Serialize};
use crate::globals;
@ -211,6 +212,7 @@ impl ImageContainer {
&prop.tag2,
prop.tag_position,
prop.tag2_position,
prop.original_dimension.0,
prop.original_dimension.1,
);
@ -275,6 +277,7 @@ impl ImageContainer {
&prop.tag2,
prop.tag_position,
prop.tag2_position,
prop.original_dimension.0,
prop.original_dimension.1,
);
@ -571,6 +574,7 @@ fn draw_layer_and_text(
tag2: &str,
tag_y_position: f64,
tag2_position: f64,
original_width: f64,
original_height: f64,
) {
let (width, height): (f64, f64) = Coord::from(tmp.dimensions()).into();
@ -586,16 +590,21 @@ fn draw_layer_and_text(
&globals::FONT_QUOTE,
size,
quote_position,
original_width,
original_height,
true,
quote,
);
let size = subquote_from_height(height);
draw_multiline_mid_string(
tmp,
&globals::FONT_SUBQUOTE,
size,
subquote_position,
original_width,
original_height,
true,
subquote,
);
let size = subquote2_from_height(height);
@ -604,7 +613,9 @@ fn draw_layer_and_text(
&globals::FONT_SUBQUOTE2,
size,
subquote2_position,
original_width,
original_height,
true,
subquote2,
);
@ -614,7 +625,9 @@ fn draw_layer_and_text(
&globals::FONT_TAG2,
size,
tag2_position,
original_width,
original_height,
false,
tag2,
);
@ -645,24 +658,137 @@ pub(crate) fn draw_multiline_mid_string(
font: &rusttype::Font,
size: f64,
position: f64,
original_width: f64,
original_height: f64,
boxed: bool,
text: &str,
) {
let (mut box_width, mut box_height) = (0.0, 0.0);
let (width, height): (f64, f64) = Coord::from(tmp.dimensions()).into();
for (index, line) in text.lines().enumerate() {
let (text_width, text_height) =
measure_line(font, line, rusttype::Scale::uniform(size as f32));
if text_width > box_width {
box_width = text_width;
}
box_height += text_height * 1.15;
let (x, y) = (
(width - text_width) / 2.0,
(position * height) / original_height + index as f64 * (text_height * 1.15),
);
if !boxed || !rw_read!(globals::CONFIG).draw_box_around_quote {
imageproc::drawing::draw_text_mut(
tmp,
image::Rgba([255, 255, 255, 255]),
((width - text_width) / 2.0) as i32,
((position * height) / original_height + index as f64 * (text_height * 1.15)) as i32,
image::Rgba([255, 255, 255, 100]),
x as i32,
y as i32,
rusttype::Scale::uniform(size as f32),
font,
line,
);
}
}
if boxed && rw_read!(globals::CONFIG).draw_box_around_quote {
draw_box(
tmp,
box_width,
box_height,
position,
original_width,
original_height,
);
let size = quote_from_height(height);
draw_multiline_mid_string(
tmp,
font,
size,
position,
original_width,
original_height,
false,
text,
);
}
}
/// Draws box around text.
fn draw_box(
tmp: &mut DynamicImage,
box_width: f64,
box_height: f64,
position: f64,
original_width: f64,
original_height: f64,
) {
if box_width <= 0.0 {
return;
}
let (width, height): (f64, f64) = Coord::from(tmp.dimensions()).into();
let (delta_x, delta_y) = (width / original_width, height / original_height);
let (x_gap, y_gap) = (8.0 * delta_x, 5.0 * delta_y);
let (x, y) = (
((width - box_width) / 2.0 - x_gap) as u32,
((position * height) / original_height - y_gap) as u32,
);
let (w, h) = (
(box_width + x_gap * 2.0) as u32,
(box_height + y_gap * 2.0) as u32,
);
if x >= width as u32 || y >= height as u32 {
return;
}
let mut buff = tmp.crop(x, y, w, h);
let layer = DynamicImage::ImageRgba8(ImageBuffer::from_fn(w, h, |_, _| {
image::Rgba([20, 22, 25, 80])
}));
image::imageops::overlay(&mut buff, &layer, 0, 0);
buff = buff.blur(15.0);
let (dx, dy) = (20.0 * delta_x, 20.0 * delta_y);
let mut shadow = DynamicImage::new_rgba8(w + (dx * 2.0) as u32, h + (dy * 2.0) as u32);
imageproc::drawing::draw_hollow_rect_mut(
&mut shadow,
Rect::at(dx as i32, dy as i32).of_size(w, h),
image::Rgba([30, 30, 30, 255]),
);
shadow = shadow.blur(5.0 * delta_x as f32);
image::imageops::overlay(tmp, &shadow, x as i64 - dx as i64, y as i64 - dy as i64);
image::imageops::overlay(tmp, &buff, x as i64, y as i64);
let mut color = buff.get_pixel(0, 0).to_rgba();
color.blend(&buff.get_pixel(0, buff.height() - 1).to_rgba());
color.blend(
&buff
.get_pixel(buff.width() - 1, buff.height() - 1)
.to_rgba(),
);
color.blend(&buff.get_pixel(buff.width() - 1, 0).to_rgba());
imageproc::drawing::draw_hollow_rect_mut(
tmp,
Rect::at(
x as i32 - (delta_x * 1.0) as i32,
y as i32 - (delta_x * 1.0) as i32,
)
.of_size(w + (delta_x * 2.0) as u32, h + (delta_x * 2.0) as u32),
color.clone(),
);
color.blend(&image::Rgba([0, 0, 0, 2]));
imageproc::drawing::draw_hollow_rect_mut(
tmp,
Rect::at(x as i32, y as i32).of_size(w, h),
color.clone(),
);
}
/// Get size of text to draw on image