trying to figure out a more performant way to do svgs
Some checks failed
/ test (push) Has been cancelled

This commit is contained in:
Chris Cochrun 2025-08-27 15:33:27 -05:00
parent 5f3d867ad7
commit 1446e35c58
5 changed files with 208 additions and 78 deletions

View file

@ -6,6 +6,7 @@ use std::sync::Arc;
use cosmic::iced::clipboard::mime::{AllowedMimeTypes, AsMimeTypes};
use crisp::types::{Keyword, Symbol, Value};
use miette::Result;
use resvg::usvg::fontdb;
use tracing::{debug, error};
use crate::Slide;
@ -17,7 +18,7 @@ use super::videos::Video;
use super::kinds::ServiceItemKind;
#[derive(Debug, PartialEq, Clone)]
#[derive(Debug, Clone, PartialEq)]
pub struct ServiceItem {
pub id: i32,
pub title: String,

View file

@ -2,10 +2,12 @@
use crisp::types::{Keyword, Symbol, Value};
use iced_video_player::Video;
use miette::{miette, Result};
use resvg::usvg::fontdb;
use serde::{Deserialize, Serialize};
use std::{
fmt::Display,
path::{Path, PathBuf},
sync::Arc,
};
use tracing::error;
@ -13,6 +15,40 @@ use crate::ui::text_svg::{self, TextSvg};
use super::songs::Song;
#[derive(
Clone, Debug, Default, PartialEq, Serialize, Deserialize,
)]
pub struct Slide {
id: i32,
background: Background,
text: String,
font: String,
font_size: i32,
text_alignment: TextAlignment,
audio: Option<PathBuf>,
video_loop: bool,
video_start_time: f32,
video_end_time: f32,
#[serde(skip)]
pub text_svg: TextSvg,
}
#[derive(
Clone, Copy, Debug, Default, PartialEq, Eq, Serialize, Deserialize,
)]
pub enum BackgroundKind {
#[default]
Image,
Video,
}
#[derive(Debug, Clone, Default)]
struct Image {
pub source: String,
pub fit: String,
pub children: Vec<String>,
}
#[derive(
Clone,
Copy,
@ -203,15 +239,6 @@ impl Display for ParseError {
}
}
#[derive(
Clone, Copy, Debug, Default, PartialEq, Eq, Serialize, Deserialize,
)]
pub enum BackgroundKind {
#[default]
Image,
Video,
}
impl From<String> for BackgroundKind {
fn from(value: String) -> Self {
if value == "image" {
@ -222,24 +249,6 @@ impl From<String> for BackgroundKind {
}
}
#[derive(
Clone, Debug, Default, PartialEq, Serialize, Deserialize,
)]
pub struct Slide {
id: i32,
background: Background,
text: String,
font: String,
font_size: i32,
text_alignment: TextAlignment,
audio: Option<PathBuf>,
video_loop: bool,
video_start_time: f32,
video_end_time: f32,
#[serde(skip)]
pub text_svg: TextSvg,
}
impl From<&Slide> for Value {
fn from(value: &Slide) -> Self {
Self::List(vec![Self::Symbol(Symbol("slide".into()))])
@ -656,13 +665,6 @@ impl SlideBuilder {
}
}
#[derive(Debug, Clone, Default)]
struct Image {
pub source: String,
pub fit: String,
pub children: Vec<String>,
}
impl Image {
fn new() -> Self {
Self {

View file

@ -1,22 +1,28 @@
use std::{
fmt::Display,
hash::{Hash, Hasher},
io::Read,
sync::Arc,
};
use colors_transform::Rgb;
use cosmic::{
iced::{
font::{Style, Weight},
Length, Size,
ContentFit, Length, Size,
},
prelude::*,
widget::{container, svg::Handle, Svg},
widget::{container, image::Handle, Image},
};
use tracing::error;
use resvg::{
tiny_skia::{self, Pixmap},
usvg::Tree,
};
use tracing::{debug, error};
use crate::TextAlignment;
#[derive(Clone, Debug, Default, PartialEq)]
#[derive(Clone, Debug, Default)]
pub struct TextSvg {
text: String,
font: Font,
@ -25,6 +31,19 @@ pub struct TextSvg {
fill: Color,
alignment: TextAlignment,
handle: Option<Handle>,
fontdb: Arc<resvg::usvg::fontdb::Database>,
}
impl PartialEq for TextSvg {
fn eq(&self, other: &Self) -> bool {
self.text == other.text
&& self.font == other.font
&& self.shadow == other.shadow
&& self.stroke == other.stroke
&& self.fill == other.fill
&& self.alignment == other.alignment
&& self.handle == other.handle
}
}
impl Hash for TextSvg {
@ -46,6 +65,27 @@ pub struct Font {
size: u8,
}
#[derive(Clone, Debug, Default, PartialEq, Hash)]
pub struct Shadow {
pub offset_x: i16,
pub offset_y: i16,
pub spread: u16,
pub color: Color,
}
#[derive(Clone, Debug, Default, PartialEq, Hash)]
pub struct Stroke {
size: u16,
color: Color,
}
pub enum Message {
None,
}
#[derive(Clone, Debug, PartialEq)]
pub struct Color(Rgb);
impl From<cosmic::font::Font> for Font {
fn from(value: cosmic::font::Font) -> Self {
Self {
@ -113,9 +153,6 @@ impl Font {
}
}
#[derive(Clone, Debug, PartialEq)]
pub struct Color(Rgb);
impl Hash for Color {
fn hash<H: Hasher>(&self, state: &mut H) {
self.0.to_css_hex_string().hash(state);
@ -158,24 +195,6 @@ impl Display for Color {
}
}
#[derive(Clone, Debug, Default, PartialEq, Hash)]
pub struct Shadow {
pub offset_x: i16,
pub offset_y: i16,
pub spread: u16,
pub color: Color,
}
#[derive(Clone, Debug, Default, PartialEq, Hash)]
pub struct Stroke {
size: u16,
color: Color,
}
pub enum Message {
None,
}
impl TextSvg {
pub fn new(text: impl Into<String>) -> Self {
Self {
@ -234,7 +253,7 @@ impl TextSvg {
} else {
"".into()
};
let size = Size::new(640.0, 360.0);
let size = Size::new(1920.0, 1080.0);
let total_lines = self.text.lines().count();
let half_lines = (total_lines / 2) as f32;
let middle_position = size.height / 2.0;
@ -266,20 +285,31 @@ impl TextSvg {
self.font.name,
self.font.size,
self.fill, stroke, text);
let handle = Handle::from_memory(
Box::leak(
<std::string::String as Clone>::clone(&final_svg)
.into_boxed_str(),
)
.as_bytes(),
);
debug!(?final_svg);
let resvg_tree = Tree::from_str(
&final_svg,
&resvg::usvg::Options {
fontdb: Arc::clone(&self.fontdb),
..Default::default()
},
)
.expect("Woops mama");
// debug!(?resvg_tree);
let transform = tiny_skia::Transform::default();
let mut pixmap =
Pixmap::new(size.width as u32, size.height as u32)
.expect("opops");
resvg::render(&resvg_tree, transform, &mut pixmap.as_mut());
// debug!(?pixmap);
let handle = Handle::from_bytes(pixmap.data().to_owned());
self.handle = Some(handle);
self
}
pub fn view<'a>(&self) -> Element<'a, Message> {
container(
Svg::new(self.handle.clone().unwrap())
Image::new(self.handle.clone().unwrap())
.content_fit(ContentFit::Contain)
.width(Length::Fill)
.height(Length::Fill),
)