update slides and songs to generate strokes and shadows in text_svg
Some checks are pending
/ test (push) Waiting to run
Some checks are pending
/ test (push) Waiting to run
This commit is contained in:
parent
3b960c5a17
commit
4bd8cf04d4
5 changed files with 193 additions and 80 deletions
|
|
@ -1,6 +1,4 @@
|
|||
use cosmic::{
|
||||
cosmic_theme::palette::rgb::Rgba, widget::image::Handle,
|
||||
};
|
||||
use cosmic::widget::image::Handle;
|
||||
// use cosmic::dialog::ashpd::url::Url;
|
||||
use crisp::types::{Keyword, Symbol, Value};
|
||||
use iced_video_player::Video;
|
||||
|
|
@ -12,7 +10,7 @@ use std::{
|
|||
};
|
||||
use tracing::error;
|
||||
|
||||
use crate::ui::text_svg::{Shadow, Stroke, TextSvg};
|
||||
use crate::ui::text_svg::{Color, Font, Shadow, Stroke, TextSvg};
|
||||
|
||||
use super::songs::Song;
|
||||
|
||||
|
|
@ -23,11 +21,12 @@ pub struct Slide {
|
|||
id: i32,
|
||||
pub(crate) background: Background,
|
||||
text: String,
|
||||
font: String,
|
||||
font: Option<Font>,
|
||||
font_size: i32,
|
||||
stroke: Option<Stroke>,
|
||||
shadow: Option<Shadow>,
|
||||
text_alignment: TextAlignment,
|
||||
text_color: Option<Color>,
|
||||
audio: Option<PathBuf>,
|
||||
video_loop: bool,
|
||||
video_start_time: f32,
|
||||
|
|
@ -280,7 +279,7 @@ impl Slide {
|
|||
}
|
||||
|
||||
pub fn set_font(mut self, font: impl AsRef<str>) -> Self {
|
||||
self.font = font.as_ref().into();
|
||||
self.font = Some(font.as_ref().into());
|
||||
self
|
||||
}
|
||||
|
||||
|
|
@ -315,7 +314,7 @@ impl Slide {
|
|||
self.font_size
|
||||
}
|
||||
|
||||
pub fn font(&self) -> String {
|
||||
pub fn font(&self) -> Option<Font> {
|
||||
self.font.clone()
|
||||
}
|
||||
|
||||
|
|
@ -331,6 +330,18 @@ impl Slide {
|
|||
self.pdf_page.clone()
|
||||
}
|
||||
|
||||
pub fn text_color(&self) -> Option<Color> {
|
||||
self.text_color.clone()
|
||||
}
|
||||
|
||||
pub fn stroke(&self) -> Option<Stroke> {
|
||||
self.stroke.clone()
|
||||
}
|
||||
|
||||
pub fn shadow(&self) -> Option<Shadow> {
|
||||
self.shadow.clone()
|
||||
}
|
||||
|
||||
pub const fn pdf_index(&self) -> u32 {
|
||||
self.pdf_index
|
||||
}
|
||||
|
|
@ -543,9 +554,12 @@ pub fn lisp_to_background(lisp: &Value) -> Background {
|
|||
pub struct SlideBuilder {
|
||||
background: Option<Background>,
|
||||
text: Option<String>,
|
||||
font: Option<String>,
|
||||
font: Option<Font>,
|
||||
font_size: Option<i32>,
|
||||
audio: Option<PathBuf>,
|
||||
stroke: Option<Stroke>,
|
||||
shadow: Option<Shadow>,
|
||||
text_color: Option<Color>,
|
||||
text_alignment: Option<TextAlignment>,
|
||||
video_loop: Option<bool>,
|
||||
video_start_time: Option<f32>,
|
||||
|
|
@ -584,12 +598,20 @@ impl SlideBuilder {
|
|||
self
|
||||
}
|
||||
|
||||
pub(crate) fn text_color(
|
||||
mut self,
|
||||
text_color: impl Into<Color>,
|
||||
) -> Self {
|
||||
let _ = self.text_color.insert(text_color.into());
|
||||
self
|
||||
}
|
||||
|
||||
pub(crate) fn audio(mut self, audio: impl Into<PathBuf>) -> Self {
|
||||
let _ = self.audio.insert(audio.into());
|
||||
self
|
||||
}
|
||||
|
||||
pub(crate) fn font(mut self, font: impl Into<String>) -> Self {
|
||||
pub(crate) fn font(mut self, font: impl Into<Font>) -> Self {
|
||||
let _ = self.font.insert(font.into());
|
||||
self
|
||||
}
|
||||
|
|
@ -599,6 +621,27 @@ impl SlideBuilder {
|
|||
self
|
||||
}
|
||||
|
||||
pub(crate) fn color(mut self, color: impl Into<Color>) -> Self {
|
||||
let _ = self.text_color.insert(color.into());
|
||||
self
|
||||
}
|
||||
|
||||
pub(crate) fn stroke(
|
||||
mut self,
|
||||
stroke: impl Into<Stroke>,
|
||||
) -> Self {
|
||||
let _ = self.stroke.insert(stroke.into());
|
||||
self
|
||||
}
|
||||
|
||||
pub(crate) fn shadow(
|
||||
mut self,
|
||||
shadow: impl Into<Shadow>,
|
||||
) -> Self {
|
||||
let _ = self.shadow.insert(shadow.into());
|
||||
self
|
||||
}
|
||||
|
||||
pub(crate) fn text_alignment(
|
||||
mut self,
|
||||
text_alignment: TextAlignment,
|
||||
|
|
@ -656,9 +699,6 @@ impl SlideBuilder {
|
|||
let Some(text) = self.text else {
|
||||
return Err(miette!("No text"));
|
||||
};
|
||||
let Some(font) = self.font else {
|
||||
return Err(miette!("No font"));
|
||||
};
|
||||
let Some(font_size) = self.font_size else {
|
||||
return Err(miette!("No font_size"));
|
||||
};
|
||||
|
|
@ -677,10 +717,13 @@ impl SlideBuilder {
|
|||
Ok(Slide {
|
||||
background,
|
||||
text,
|
||||
font,
|
||||
font: self.font,
|
||||
font_size,
|
||||
text_alignment,
|
||||
audio: self.audio,
|
||||
stroke: self.stroke,
|
||||
shadow: self.shadow,
|
||||
text_color: self.text_color,
|
||||
video_loop,
|
||||
video_start_time,
|
||||
video_end_time,
|
||||
|
|
@ -710,7 +753,7 @@ mod test {
|
|||
text: "This is frodo".to_string(),
|
||||
background: Background::try_from("~/pics/frodo.jpg")
|
||||
.unwrap(),
|
||||
font: "Quicksand".to_string(),
|
||||
font: Some("Quicksand".to_string().into()),
|
||||
font_size: 140,
|
||||
..Default::default()
|
||||
}
|
||||
|
|
@ -723,7 +766,7 @@ mod test {
|
|||
"~/vids/test/camprules2024.mp4",
|
||||
)
|
||||
.unwrap(),
|
||||
font: "Quicksand".to_string(),
|
||||
font: Some("Quicksand".to_string().into()),
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ use std::{
|
|||
};
|
||||
|
||||
use cosmic::{
|
||||
cosmic_theme::palette::rgb::Rgba,
|
||||
cosmic_theme::palette::{IntoColor, Srgb, rgb::Rgba},
|
||||
iced::clipboard::mime::AsMimeTypes,
|
||||
};
|
||||
use crisp::types::{Keyword, Symbol, Value};
|
||||
|
|
@ -16,7 +16,11 @@ use sqlx::{
|
|||
};
|
||||
use tracing::{debug, error};
|
||||
|
||||
use crate::{Slide, SlideBuilder, core::slide};
|
||||
use crate::{
|
||||
Slide, SlideBuilder,
|
||||
core::slide,
|
||||
ui::text_svg::{self, Color, Font, Stroke, shadow, stroke},
|
||||
};
|
||||
|
||||
use super::{
|
||||
content::Content,
|
||||
|
|
@ -41,11 +45,12 @@ pub struct Song {
|
|||
pub text_alignment: Option<TextAlignment>,
|
||||
pub font: Option<String>,
|
||||
pub font_size: Option<i32>,
|
||||
pub stroke_size: Option<i32>,
|
||||
pub stroke_color: Option<Rgba>,
|
||||
pub shadow_size: Option<i32>,
|
||||
pub shadow_offset: Option<(i32, i32)>,
|
||||
pub shadow_color: Option<Rgba>,
|
||||
pub text_color: Option<Srgb>,
|
||||
pub stroke_size: Option<u16>,
|
||||
pub stroke_color: Option<Srgb>,
|
||||
pub shadow_size: Option<u16>,
|
||||
pub shadow_offset: Option<(i16, i16)>,
|
||||
pub shadow_color: Option<Srgb>,
|
||||
pub verses: Option<Vec<VerseName>>,
|
||||
pub verse_map: Option<HashMap<VerseName, String>>,
|
||||
}
|
||||
|
|
@ -283,15 +288,58 @@ impl ServiceTrait for Song {
|
|||
let slides: Vec<Slide> = lyrics
|
||||
.iter()
|
||||
.filter_map(|l| {
|
||||
SlideBuilder::new()
|
||||
let font =
|
||||
Font::default()
|
||||
.name(
|
||||
self.font
|
||||
.clone()
|
||||
.unwrap_or_else(|| "Calibri".into()),
|
||||
)
|
||||
.size(self.font_size.unwrap_or_else(|| 100)
|
||||
as u8);
|
||||
let stroke_size =
|
||||
self.stroke_size.unwrap_or_default();
|
||||
let stroke: Stroke = stroke(
|
||||
stroke_size,
|
||||
self.stroke_color
|
||||
.map(|color| Color::from(color))
|
||||
.unwrap_or_default(),
|
||||
);
|
||||
let shadow_size =
|
||||
self.shadow_size.unwrap_or_default();
|
||||
let shadow = shadow(
|
||||
self.shadow_offset.unwrap_or_default().0,
|
||||
self.shadow_offset.unwrap_or_default().1,
|
||||
shadow_size,
|
||||
self.shadow_color
|
||||
.map(|color| Color::from(color))
|
||||
.unwrap_or_default(),
|
||||
);
|
||||
let builder = SlideBuilder::new();
|
||||
let builder = if shadow_size > 0 {
|
||||
builder.shadow(shadow)
|
||||
} else {
|
||||
builder
|
||||
};
|
||||
let builder = if stroke_size > 0 {
|
||||
builder.stroke(stroke)
|
||||
} else {
|
||||
builder
|
||||
};
|
||||
builder
|
||||
.background(
|
||||
self.background.clone().unwrap_or_default(),
|
||||
)
|
||||
.font(self.font.clone().unwrap_or_default())
|
||||
.font(font)
|
||||
.font_size(self.font_size.unwrap_or_default())
|
||||
.text_alignment(
|
||||
self.text_alignment.unwrap_or_default(),
|
||||
)
|
||||
.text_color(
|
||||
self.text_color.unwrap_or_else(|| {
|
||||
Srgb::new(1.0, 1.0, 1.0)
|
||||
}),
|
||||
)
|
||||
.audio(self.audio.clone().unwrap_or_default())
|
||||
.video_loop(true)
|
||||
.video_start_time(0.0)
|
||||
|
|
|
|||
|
|
@ -458,8 +458,12 @@ impl Presenter {
|
|||
// self.current_slide_index = slide;
|
||||
debug!("cloning slide...");
|
||||
self.current_slide = slide.clone();
|
||||
let _ =
|
||||
self.update(Message::ChangeFont(slide.font()));
|
||||
let font = if let Some(font) = slide.font() {
|
||||
font.get_name()
|
||||
} else {
|
||||
"".into()
|
||||
};
|
||||
let _ = self.update(Message::ChangeFont(font));
|
||||
debug!("changing video now...");
|
||||
if !backgrounds_match {
|
||||
if let Some(video) = &mut self.video {
|
||||
|
|
|
|||
|
|
@ -81,7 +81,7 @@ pub struct SongEditor {
|
|||
song_slides: Option<Vec<Slide>>,
|
||||
slide_state: SlideEditor,
|
||||
stroke_sizes: combo_box::State<i32>,
|
||||
stroke_size: i32,
|
||||
stroke_size: u16,
|
||||
stroke_open: bool,
|
||||
#[debug(skip)]
|
||||
stroke_color_model: ColorPickerModel,
|
||||
|
|
@ -117,7 +117,7 @@ pub enum Message {
|
|||
None,
|
||||
ChangeAuthor(String),
|
||||
PauseVideo,
|
||||
UpdateStrokeSize(i32),
|
||||
UpdateStrokeSize(u16),
|
||||
UpdateStrokeColor(ColorPickerUpdate),
|
||||
OpenStroke,
|
||||
CloseStroke,
|
||||
|
|
@ -310,7 +310,7 @@ impl SongEditor {
|
|||
if let Some(song) = &mut self.song {
|
||||
song.font = Some(font);
|
||||
let song = song.to_owned();
|
||||
return self.update_song(song);
|
||||
return Action::Task(self.update_song(song));
|
||||
}
|
||||
}
|
||||
Message::ChangeFontSize(size) => {
|
||||
|
|
@ -318,7 +318,7 @@ impl SongEditor {
|
|||
if let Some(song) = &mut self.song {
|
||||
song.font_size = Some(size as i32);
|
||||
let song = song.to_owned();
|
||||
return self.update_song(song);
|
||||
return Action::Task(self.update_song(song));
|
||||
}
|
||||
}
|
||||
Message::ChangeTitle(title) => {
|
||||
|
|
@ -326,7 +326,7 @@ impl SongEditor {
|
|||
if let Some(song) = &mut self.song {
|
||||
song.title = title;
|
||||
let song = song.to_owned();
|
||||
return self.update_song(song);
|
||||
return Action::Task(self.update_song(song));
|
||||
}
|
||||
}
|
||||
Message::ChangeVerseOrder(verse_order) => {
|
||||
|
|
@ -337,7 +337,7 @@ impl SongEditor {
|
|||
.map(std::borrow::ToOwned::to_owned)
|
||||
.collect();
|
||||
song.verse_order = Some(verse_order);
|
||||
return self.update_song(song);
|
||||
return Action::Task(self.update_song(song));
|
||||
}
|
||||
}
|
||||
Message::ChangeLyrics(action) => {
|
||||
|
|
@ -347,7 +347,7 @@ impl SongEditor {
|
|||
|
||||
if let Some(mut song) = self.song.clone() {
|
||||
song.lyrics = Some(lyrics);
|
||||
return self.update_song(song);
|
||||
return Action::Task(self.update_song(song));
|
||||
}
|
||||
}
|
||||
Message::Edit(edit) => {
|
||||
|
|
@ -359,7 +359,7 @@ impl SongEditor {
|
|||
self.author = author.clone();
|
||||
if let Some(mut song) = self.song.clone() {
|
||||
song.author = Some(author);
|
||||
return self.update_song(song);
|
||||
return Action::Task(self.update_song(song));
|
||||
}
|
||||
}
|
||||
Message::ChangeBackground(Ok(path)) => {
|
||||
|
|
@ -368,7 +368,7 @@ impl SongEditor {
|
|||
let background = Background::try_from(path).ok();
|
||||
self.background_video(&background);
|
||||
song.background = background;
|
||||
return self.update_song(song);
|
||||
return Action::Task(self.update_song(song));
|
||||
}
|
||||
}
|
||||
Message::ChangeBackground(Err(error)) => {
|
||||
|
|
@ -394,19 +394,21 @@ impl SongEditor {
|
|||
song.stroke_size = Some(size);
|
||||
}
|
||||
let song = song.to_owned();
|
||||
return self.update_song(song);
|
||||
return Action::Task(self.update_song(song));
|
||||
}
|
||||
}
|
||||
Message::UpdateStrokeColor(update) => {
|
||||
let task = self.stroke_color_model.update(update);
|
||||
if let Some(song) = self.song.as_mut()
|
||||
let mut tasks = Vec::with_capacity(2);
|
||||
tasks.push(self.stroke_color_model.update(update));
|
||||
if let Some(mut song) = self.song.clone()
|
||||
&& let Some(color) =
|
||||
self.stroke_color_model.get_applied_color()
|
||||
{
|
||||
debug!(?color);
|
||||
song.stroke_color = Some(color.into());
|
||||
tasks.push(self.update_song(song));
|
||||
}
|
||||
return Action::Task(task);
|
||||
return Action::Task(Task::batch(tasks));
|
||||
}
|
||||
Message::UpdateSlides(slides) => {
|
||||
self.song_slides = Some(slides);
|
||||
|
|
@ -473,7 +475,9 @@ impl SongEditor {
|
|||
&old_verse_name,
|
||||
);
|
||||
|
||||
return self.update_song(song);
|
||||
return Action::Task(
|
||||
self.update_song(song),
|
||||
);
|
||||
}
|
||||
}
|
||||
verse_editor::Action::UpdateVerse((
|
||||
|
|
@ -486,14 +490,18 @@ impl SongEditor {
|
|||
// song.update_verse(
|
||||
// index, verse, lyric,
|
||||
// );
|
||||
return self.update_song(song);
|
||||
return Action::Task(
|
||||
self.update_song(song),
|
||||
);
|
||||
}
|
||||
}
|
||||
verse_editor::Action::DeleteVerse(verse) => {
|
||||
if let Some(mut song) = self.song.clone()
|
||||
{
|
||||
song.delete_verse(verse);
|
||||
return self.update_song(song);
|
||||
return Action::Task(
|
||||
self.update_song(song),
|
||||
);
|
||||
};
|
||||
}
|
||||
verse_editor::Action::None => (),
|
||||
|
|
@ -517,7 +525,7 @@ impl SongEditor {
|
|||
}
|
||||
if let Some(mut song) = self.song.clone() {
|
||||
song.add_verse(verse, lyric);
|
||||
return self.update_song(song);
|
||||
return Action::Task(self.update_song(song));
|
||||
}
|
||||
}
|
||||
Message::RemoveVerse(index) => {
|
||||
|
|
@ -528,7 +536,7 @@ impl SongEditor {
|
|||
verses.remove(index);
|
||||
},
|
||||
);
|
||||
return self.update_song(song);
|
||||
return Action::Task(self.update_song(song));
|
||||
}
|
||||
}
|
||||
Message::ChipHovered(index) => {
|
||||
|
|
@ -546,7 +554,9 @@ impl SongEditor {
|
|||
{
|
||||
verses.insert(index, verse);
|
||||
let song = song.clone();
|
||||
return self.update_song(song);
|
||||
return Action::Task(
|
||||
self.update_song(song),
|
||||
);
|
||||
}
|
||||
error!("No verses in this song?");
|
||||
} else {
|
||||
|
|
@ -567,7 +577,9 @@ impl SongEditor {
|
|||
{
|
||||
verses.push(verse);
|
||||
let song = song.clone();
|
||||
return self.update_song(song);
|
||||
return Action::Task(
|
||||
self.update_song(song),
|
||||
);
|
||||
} else {
|
||||
error!(
|
||||
"No verses in this song or no song here"
|
||||
|
|
@ -592,7 +604,7 @@ impl SongEditor {
|
|||
let verse = verses.remove(index);
|
||||
verses.insert(target_index, verse);
|
||||
debug!(?verses);
|
||||
return self.update_song(song);
|
||||
return Action::Task(self.update_song(song));
|
||||
}
|
||||
}
|
||||
draggable::DragEvent::Canceled { index } => (),
|
||||
|
|
@ -606,7 +618,7 @@ impl SongEditor {
|
|||
Message::SetTextAlignment(alignment) => {
|
||||
if let Some(mut song) = self.song.clone() {
|
||||
song.text_alignment = Some(alignment);
|
||||
return self.update_song(song);
|
||||
return Action::Task(self.update_song(song));
|
||||
}
|
||||
}
|
||||
Message::None => (),
|
||||
|
|
@ -1147,7 +1159,7 @@ impl SongEditor {
|
|||
dropdown(
|
||||
&["0", "1", "2", "3", "4", "5", "6", "7"],
|
||||
Some(self.stroke_size as usize),
|
||||
|i| Message::UpdateStrokeSize(i as i32),
|
||||
|i| Message::UpdateStrokeSize(i as u16),
|
||||
)
|
||||
.gap(5.0),
|
||||
]
|
||||
|
|
@ -1389,11 +1401,11 @@ impl SongEditor {
|
|||
self.editing
|
||||
}
|
||||
|
||||
fn update_song(&mut self, song: Song) -> Action {
|
||||
use cosmic::iced_futures::futures::stream;
|
||||
fn update_song(&mut self, song: Song) -> Task<Message> {
|
||||
// use cosmic::iced_futures::futures::stream;
|
||||
// use cosmic::iced_futures::futures::{Stream, StreamExt};
|
||||
// use cosmic::iced_futures::stream::channel;
|
||||
use cosmic::task::stream;
|
||||
// use cosmic::task::stream;
|
||||
let font_db = Arc::clone(&self.font_db);
|
||||
// need to test to see which of these methods yields faster
|
||||
// text_svg slide creation. There is a small thought in me that
|
||||
|
|
@ -1464,7 +1476,7 @@ impl SongEditor {
|
|||
}
|
||||
tasks.push(Task::done(Message::UpdateSong(song)));
|
||||
|
||||
Action::Task(Task::batch(tasks))
|
||||
Task::batch(tasks)
|
||||
}
|
||||
|
||||
fn background_video(&mut self, background: &Option<Background>) {
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ use resvg::{
|
|||
usvg::{Tree, fontdb},
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use tracing::error;
|
||||
use tracing::{debug, error};
|
||||
|
||||
use crate::TextAlignment;
|
||||
|
||||
|
|
@ -378,7 +378,11 @@ impl TextSvg {
|
|||
stroke.color, stroke.size
|
||||
));
|
||||
}
|
||||
final_svg.push_str(" style=\"filter:url(#shadow);\">");
|
||||
|
||||
if self.shadow.is_some() {
|
||||
final_svg.push_str(" style=\"filter:url(#shadow);\"");
|
||||
}
|
||||
final_svg.push_str(">");
|
||||
|
||||
let text: String = self
|
||||
.text
|
||||
|
|
@ -496,20 +500,7 @@ pub fn text_svg_generator(
|
|||
slide: &mut crate::core::slide::Slide,
|
||||
fontdb: Arc<fontdb::Database>,
|
||||
) {
|
||||
if !slide.text().is_empty() {
|
||||
let text_svg = TextSvg::new(slide.text())
|
||||
.alignment(slide.text_alignment())
|
||||
.fill("#fff")
|
||||
.shadow(shadow(2, 2, 5, "#000000"))
|
||||
.stroke(stroke(3, "#000"))
|
||||
.font(
|
||||
Font::from(slide.font())
|
||||
.size(slide.font_size().try_into().unwrap()),
|
||||
)
|
||||
.fontdb(Arc::clone(&fontdb))
|
||||
.build(Size::new(1280.0, 720.0), true);
|
||||
slide.text_svg = Some(text_svg);
|
||||
}
|
||||
text_svg_generator_with_cache(slide, fontdb, true);
|
||||
}
|
||||
|
||||
pub fn text_svg_generator_with_cache(
|
||||
|
|
@ -518,17 +509,31 @@ pub fn text_svg_generator_with_cache(
|
|||
cache: bool,
|
||||
) {
|
||||
if !slide.text().is_empty() {
|
||||
let font = if let Some(font) = slide.font() {
|
||||
font
|
||||
} else {
|
||||
Font::default()
|
||||
};
|
||||
let text_svg = TextSvg::new(slide.text())
|
||||
.alignment(slide.text_alignment())
|
||||
.fill("#fff")
|
||||
.shadow(shadow(2, 2, 5, "#000000"))
|
||||
.stroke(stroke(3, "#000"))
|
||||
.font(
|
||||
Font::from(slide.font())
|
||||
.size(slide.font_size().try_into().unwrap()),
|
||||
)
|
||||
.fontdb(Arc::clone(&fontdb))
|
||||
.build(Size::new(1280.0, 720.0), cache);
|
||||
.fill(
|
||||
slide.text_color().unwrap_or_else(|| "#fff".into()),
|
||||
);
|
||||
let text_svg = if let Some(stroke) = slide.stroke() {
|
||||
text_svg.stroke(stroke)
|
||||
} else {
|
||||
text_svg
|
||||
};
|
||||
let text_svg = if let Some(shadow) = slide.shadow() {
|
||||
text_svg.shadow(shadow)
|
||||
} else {
|
||||
text_svg
|
||||
};
|
||||
let text_svg =
|
||||
text_svg.font(font).fontdb(Arc::clone(&fontdb));
|
||||
debug!(fill = ?text_svg.fill, font = ?text_svg.font, stroke = ?text_svg.stroke, shadow = ?text_svg.shadow, text = ?text_svg.text);
|
||||
let text_svg =
|
||||
text_svg.build(Size::new(1280.0, 720.0), cache);
|
||||
slide.text_svg = Some(text_svg);
|
||||
}
|
||||
}
|
||||
|
|
@ -538,6 +543,7 @@ mod tests {
|
|||
use crate::core::slide::Slide;
|
||||
|
||||
use super::*;
|
||||
use rayon::iter::{IntoParallelIterator, ParallelIterator};
|
||||
use resvg::usvg::fontdb::Database;
|
||||
|
||||
#[test]
|
||||
|
|
@ -547,12 +553,12 @@ mod tests {
|
|||
let mut fontdb = Database::new();
|
||||
fontdb.load_system_fonts();
|
||||
let fontdb = Arc::new(fontdb);
|
||||
(0..100).for_each(|index| {
|
||||
(0..40).into_par_iter().for_each(|_| {
|
||||
let mut slide = slide
|
||||
.clone()
|
||||
.set_font_size(120)
|
||||
.set_font("Quicksand")
|
||||
.set_text(index.to_string());
|
||||
.set_text("This is the first slide of text\nAnd we are singing\nTo save the world!");
|
||||
text_svg_generator_with_cache(
|
||||
&mut slide,
|
||||
Arc::clone(&fontdb),
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue