Skip to content

Commit

Permalink
Expose loading fonts (#5)
Browse files Browse the repository at this point in the history
* add

* Update lib.rs
  • Loading branch information
baseplate-admin authored Apr 10, 2024
1 parent c0d7516 commit 478a401
Showing 1 changed file with 80 additions and 18 deletions.
98 changes: 80 additions & 18 deletions src/rust/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,28 +9,71 @@ use pyo3::prelude::*;
use resvg;
use resvg::usvg;

#[derive(Clone, Copy, PartialEq, Debug)]
enum FitTo {
/// Keep original size.
Original,
/// Scale to width.
Width(u32),
/// Scale to height.
Height(u32),
/// Scale to size.
Size(u32, u32),
/// Zoom by factor.
Zoom(f32),
}

impl FitTo {
fn fit_to_size(&self, size: tiny_skia::IntSize) -> Option<tiny_skia::IntSize> {
match *self {
FitTo::Original => Some(size),
FitTo::Width(w) => size.scale_to_width(w),
FitTo::Height(h) => size.scale_to_height(h),
FitTo::Size(w, h) => tiny_skia::IntSize::from_wh(w, h).map(|s| size.scale_to(s)),
FitTo::Zoom(z) => size.scale_by(z),
}
}

fn fit_to_transform(&self, size: tiny_skia::IntSize) -> tiny_skia::Transform {
let size1 = size.to_size();
let size2 = match self.fit_to_size(size) {
Some(v) => v.to_size(),
None => return tiny_skia::Transform::default(),
};
tiny_skia::Transform::from_scale(
size2.width() / size1.width(),
size2.height() / size1.height(),
)
}
}
struct Opts {
fit_to: FitTo,
font_family: Option<String>,
font_size: u32,
// font_size: u32,
serif_family: Option<String>,
sans_serif_family: Option<String>,
cursive_family: Option<String>,
fantasy_family: Option<String>,
monospace_family: Option<String>,
font_files: Vec<String>,
font_dirs: Vec<String>,
skip_system_fonts: bool,

font_files: Option<Vec<String>>,
font_dirs: Option<Vec<String>>,
// skip_system_fonts: bool,
}

fn load_fonts(options: &mut Opts, fontdb: &mut usvg::fontdb::Database) {
for path in &options.font_files {
if let Err(e) = fontdb.load_font_file(path) {
println!("Failed to load '{}' cause {}.", path.to_string(), e);
if let Some(font_files) = (&options.font_files) {
for path in font_files {
if let Err(e) = fontdb.load_font_file(path) {
println!("Failed to load '{}' cause {}.", path.to_string(), e);
}
}
}

for path in &options.font_dirs {
fontdb.load_fonts_dir(path);
if let Some(font_dirs) = (&options.font_dirs) {
for path in font_dirs {
fontdb.load_fonts_dir(path);
}
}

let take_or =
Expand All @@ -43,13 +86,13 @@ fn load_fonts(options: &mut Opts, fontdb: &mut usvg::fontdb::Database) {
fontdb.set_monospace_family(take_or(options.monospace_family.take(), "Courier New"));
}

fn render_svg(tree: &usvg::Tree) -> Result<tiny_skia::Pixmap, String> {
fn render_svg(mut options: Opts, tree: &usvg::Tree) -> Result<tiny_skia::Pixmap, String> {
let mut pixmap = tiny_skia::Pixmap::new(
tree.size().to_int_size().width(),
tree.size().to_int_size().height(),
)
.unwrap();
let ts = tree.view_box().to_transform(tree.size());
let ts = options.fit_to.fit_to_transform(tree.size().to_int_size());
resvg::render(tree, ts, &mut pixmap.as_mut());

Ok(pixmap)
Expand Down Expand Up @@ -78,13 +121,18 @@ fn resvg_magic(mut options: Opts, svg_string: String) -> Result<Vec<u8>, String>
.map_err(|e| e.to_string())
}
.unwrap();
let img: Vec<u8> = render_svg(&tree).unwrap().encode_png().unwrap();
let img: Vec<u8> = render_svg(options, &tree).unwrap().encode_png().unwrap();
Ok(img)
}

#[pyfunction]
fn svg_to_base64(
svg_string: String,
// Control width, height, zoom
width: Option<u32>,
height: Option<u32>,
zoom: Option<u32>,
// Fonts
font_family: Option<String>,
serif_family: Option<String>,
sans_serif_family: Option<String>,
Expand All @@ -94,20 +142,34 @@ fn svg_to_base64(
font_files: Option<Vec<String>>,
font_dirs: Option<Vec<String>>,
) -> PyResult<String> {
//let string = svg_string;
let mut fit_to = FitTo::Original;
let mut default_size = usvg::Size::from_wh(100.0, 100.0).unwrap();

if let (Some(w), Some(h)) = (width, height) {
default_size = usvg::Size::from_wh(w as f32, h as f32).unwrap();
fit_to = FitTo::Size(w, h);
} else if let Some(w) = width {
default_size = usvg::Size::from_wh(w as f32, 100.0).unwrap();
fit_to = FitTo::Width(w);
} else if let Some(h) = height {
default_size = usvg::Size::from_wh(100.0, h as f32).unwrap();
fit_to = FitTo::Height(h);
} else if let Some(z) = zoom {
fit_to = FitTo::Zoom(z as f32);
}

let options = Opts {
fit_to,
font_family: font_family,
font_size: todo!(),
serif_family,
sans_serif_family,
cursive_family,
fantasy_family,
monospace_family,
font_files: font_files.unwrap(),
font_dirs: font_dirs.unwrap(),
skip_system_fonts: todo!(),
font_files: font_files,
font_dirs: font_dirs,
};
let pixmap = resvg_magic(options, String::from(svg_string)).unwrap();
let pixmap = resvg_magic(options, svg_string).unwrap();
Ok(general_purpose::STANDARD.encode(&pixmap))
}

Expand Down

0 comments on commit 478a401

Please sign in to comment.