Skip to content

Commit

Permalink
resvg next
Browse files Browse the repository at this point in the history
  • Loading branch information
LaurenzV committed Apr 9, 2024
1 parent b9f1513 commit 6bdf75a
Show file tree
Hide file tree
Showing 24 changed files with 53 additions and 100 deletions.
6 changes: 2 additions & 4 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,10 @@ oxipng = { version = "9", default-features = false, features = ["filetime", "par
pdf-writer = "0.9"
pdfium-render = "0.8.6"
termcolor = "1.2"
usvg = { version = "0.41", default-features = false }
usvg = { git = "https://github.com/RazrFalcon/resvg", default-features = false }
tiny-skia = "0.11.4"
unicode-properties = "0.1.1"
resvg = { version = "0.41", default-features = false }
resvg = { git = "https://github.com/RazrFalcon/resvg", default-features = false }
subsetter = "0.1.1"
ttf-parser = { version = "0.20.0" }
siphasher = { version = "1.0.1"}
Expand Down
4 changes: 2 additions & 2 deletions src/render/filter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use crate::util::resources::ResourceContainer;
use pdf_writer::{Chunk, Content};
use std::sync::Arc;
use tiny_skia::{Size, Transform};
use usvg::{AspectRatio, Group, ImageKind, Node, ViewBox, Visibility};
use usvg::{Group, ImageKind, Node, Visibility};

/// Render a group with filters as an image.
pub fn render(
Expand Down Expand Up @@ -48,7 +48,7 @@ pub fn render(
image::render(
Visibility::Visible,
&ImageKind::PNG(Arc::new(encoded_image)),
ViewBox { rect: layer_bbox, aspect: AspectRatio::default() },
Some(layer_bbox.to_rect()),
chunk,
content,
ctx,
Expand Down
26 changes: 11 additions & 15 deletions src/render/image.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,18 @@ use std::rc::Rc;
use image::{ColorType, DynamicImage, ImageFormat, Luma, Rgb, Rgba};
use miniz_oxide::deflate::{compress_to_vec_zlib, CompressionLevel};
use pdf_writer::{Chunk, Content, Filter, Finish};
use usvg::{ImageKind, Size, Transform, Tree, ViewBox, Visibility};
use usvg::{ImageKind, Rect, Size, Transform, Tree, Visibility};

use crate::render::tree_to_xobject;
use crate::util::context::Context;
use crate::util::helper;
use crate::util::helper::{image_rect, NameExt, TransformExt};
use crate::util::helper::{NameExt, TransformExt};
use crate::util::resources::ResourceContainer;

/// Render an image into a content stream.
pub fn render(
visibility: Visibility,
kind: &ImageKind,
view_box: ViewBox,
view_box: Option<Rect>,
chunk: &mut Chunk,
content: &mut Content,
ctx: &mut Context,
Expand Down Expand Up @@ -79,29 +78,26 @@ pub fn render(
ImageKind::SVG(tree) => create_svg_image(tree, chunk, ctx, rc),
};

// Get the dimensions of the actual rect that is needed to scale the image into the image view
// box. If the keepAspectRatio is slice, this rect will exceed the actual image view box, but
// it will be clipped further below so that it always stays within the bounds of the actual image
// rect.
let image_rect = image_rect(&view_box, image_size);
let view_box = view_box.unwrap_or(
Rect::from_xywh(0.0, 0.0, image_size.width(), image_size.height()).unwrap(),
);

content.save_state();
// Clip the image so just the part inside of the view box is actually visible.
helper::clip_to_rect(view_box.rect, content);

// Account for the x/y of the viewbox.
content.transform(
Transform::from_translate(image_rect.x(), image_rect.y()).to_pdf_transform(),
Transform::from_translate(view_box.x(), view_box.y()).to_pdf_transform(),
);

// Scale the image from 1x1 to the actual dimensions.
content.transform(
Transform::from_row(
image_rect.width(),
view_box.width(),
0.0,
0.0,
-image_rect.height(),
-view_box.height(),
0.0,
image_rect.height(),
view_box.height(),
)
.to_pdf_transform(),
);
Expand Down
8 changes: 3 additions & 5 deletions src/render/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,9 @@ pub fn tree_to_stream(
) {
content.save_state();

// From PDF coordinate system to SVG coordinate system
let initial_transform =
// From PDF coordinate system to SVG coordinate system
Transform::from_row(1.0, 0.0, 0.0, -1.0, 0.0, tree.size().height())
// Account for view box of tree.
.pre_concat(tree.view_box().to_transform(tree.size()));
Transform::from_row(1.0, 0.0, 0.0, -1.0, 0.0, tree.size().height());

content.transform(initial_transform.to_pdf_transform());

Expand Down Expand Up @@ -100,7 +98,7 @@ impl Render for Node {
Node::Image(ref image) => image::render(
image.visibility(),
image.kind(),
image.view_box(),
None,
chunk,
content,
ctx,
Expand Down
13 changes: 1 addition & 12 deletions src/render/pattern.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use std::sync::Arc;

use pdf_writer::types::{PaintType, TilingType};
use pdf_writer::{Chunk, Content, Filter, Ref};
use usvg::{Opacity, Pattern, Size, Transform};
use usvg::{Opacity, Pattern, Transform};

use super::group;
use crate::util::context::Context;
Expand All @@ -27,15 +27,6 @@ pub fn create(
);

let mut content = Content::new();
content.save_state();

if let Some(view_box) = pattern.view_box() {
let view_box_transform = view_box.to_transform(
Size::from_wh(pattern_rect.width(), pattern_rect.height()).unwrap(),
);
content.transform(view_box_transform.to_pdf_transform());
}

group::render(
pattern.root(),
chunk,
Expand All @@ -46,8 +37,6 @@ pub fn create(
&mut rc,
);

content.restore_state();

let content_stream = ctx.finish_content(content);

let mut tiling_pattern = chunk.tiling_pattern(pattern_ref, &content_stream);
Expand Down
34 changes: 0 additions & 34 deletions src/util/helper.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
use pdf_writer::types::{BlendMode, LineCapStyle, LineJoinStyle, MaskType};
use pdf_writer::{Content, Name, Rect};
#[cfg(feature = "image")]
use usvg::Size;
use usvg::{LineCap, LineJoin, NonZeroRect, Transform};

use crate::render::gradient::Stop;
Expand Down Expand Up @@ -165,38 +163,6 @@ pub fn bbox_to_non_zero_rect(rect: Option<usvg::Rect>) -> NonZeroRect {
.unwrap_or(NonZeroRect::from_xywh(0.0, 0.0, 1.0, 1.0).unwrap())
}

// Taken from resvg
/// Calculate the rect of an image after it is scaled using a view box.
#[cfg(feature = "image")]
pub fn image_rect(view_box: &usvg::ViewBox, img_size: Size) -> NonZeroRect {
let new_size = fit_view_box(img_size, view_box);
let (x, y) = usvg::utils::aligned_pos(
view_box.aspect.align,
view_box.rect.x(),
view_box.rect.y(),
view_box.rect.width() - new_size.width(),
view_box.rect.height() - new_size.height(),
);

new_size.to_non_zero_rect(x, y)
}

// Taken from resvg
/// Calculate the new size of a view box that is the result of applying a view box
/// to a certain size.
#[cfg(feature = "image")]
pub fn fit_view_box(size: Size, vb: &usvg::ViewBox) -> usvg::Size {
let s = vb.rect.size();

if vb.aspect.align == usvg::Align::None {
s
} else if vb.aspect.slice {
size.expand_to(s)
} else {
size.scale_to(s)
}
}

/// Compress data using the deflate algorithm.
pub fn deflate(data: &[u8]) -> Vec<u8> {
const COMPRESSION_LEVEL: u8 = 6;
Expand Down
Binary file modified tests/ref/api/to_chunk.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified tests/ref/custom/integration/matplotlib/bar_label.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified tests/ref/custom/integration/matplotlib/multi_colored_lines.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified tests/ref/custom/integration/matplotlib/signals.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified tests/ref/custom/integration/matplotlib/tripcolor.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified tests/ref/custom/structure/image/image-2.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified tests/ref/resvg/filters/feImage/with-subregion-5.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified tests/ref/resvg/filters/filter/on-a-thin-rect.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified tests/ref/resvg/filters/filter/with-multiple-transforms-1.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified tests/ref/resvg/structure/image/embedded-svg-with-text.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified tests/ref/resvg/structure/image/with-transform.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
16 changes: 7 additions & 9 deletions tests/src/api.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,19 @@
use crate::create_fontdb;
use once_cell::sync::Lazy;
#[allow(unused_imports)]
use {
crate::render_pdf,
crate::{convert_svg, run_test_impl},
crate::{render_pdf, FONTDB},
pdf_writer::{Content, Finish, Name, Pdf, Rect, Ref, Str},
std::collections::HashMap,
std::path::Path,
svg2pdf::ConversionOptions,
svg2pdf::PageOptions,
};

#[allow(dead_code)]
static FONTDB3: Lazy<std::sync::Mutex<fontdb::Database>> = Lazy::new(|| create_fontdb());

#[test]
fn text_to_paths() {
let options = ConversionOptions { embed_text: false, ..ConversionOptions::default() };
Expand Down Expand Up @@ -46,7 +51,7 @@ fn to_chunk() {
let path =
"svg/custom/integration/wikimedia/coat_of_the_arms_of_edinburgh_city_council.svg";
let svg = std::fs::read_to_string(path).unwrap();
let db = FONTDB.lock().unwrap();
let db = FONTDB3.lock().unwrap();
let tree =
svg2pdf::usvg::Tree::from_str(&svg, &svg2pdf::usvg::Options::default(), &db)
.unwrap();
Expand Down Expand Up @@ -76,13 +81,6 @@ fn to_chunk() {
pdf.type1_font(font_id).base_font(Name(b"Times-Roman"));

let mut content = Content::new();
// We don't include the text because it causes issue in CI since it's OS-dependent
// content
// .begin_text()
// .set_font(font_name, 16.0)
// .next_line(108.0, 734.0)
// .show(Str(b"Look at my wonderful (distorted) vector graphic!"))
// .end_text();

content
.transform([300.0, 0.0, 0.0, 300.0, 200.0, 400.0])
Expand Down
40 changes: 23 additions & 17 deletions tests/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,19 +16,8 @@ use usvg::Tree;

use svg2pdf::{ConversionOptions, PageOptions};

/// The global fontdb instance.
static FONTDB: Lazy<std::sync::Mutex<fontdb::Database>> = Lazy::new(|| {
let mut fontdb = fontdb::Database::new();
fontdb.load_fonts_dir("fonts");

fontdb.set_serif_family("Noto Serif");
fontdb.set_sans_serif_family("Noto Sans");
fontdb.set_cursive_family("Yellowtail");
fontdb.set_fantasy_family("Sedgwick Ave Display");
fontdb.set_monospace_family("Noto Mono");

std::sync::Mutex::new(fontdb)
});
static FONTDB1: Lazy<std::sync::Mutex<fontdb::Database>> = Lazy::new(|| create_fontdb());
static FONTDB2: Lazy<std::sync::Mutex<fontdb::Database>> = Lazy::new(|| create_fontdb());

/// The global pdfium instance.
static PDFIUM: Lazy<std::sync::Mutex<Pdfium>> = Lazy::new(|| {
Expand Down Expand Up @@ -62,10 +51,23 @@ pub fn render_pdf(pdf: &[u8]) -> RgbaImage {
result
}

pub fn create_fontdb() -> std::sync::Mutex<fontdb::Database> {
let mut fontdb = fontdb::Database::new();
fontdb.load_fonts_dir("fonts");

fontdb.set_serif_family("Noto Serif");
fontdb.set_sans_serif_family("Noto Sans");
fontdb.set_cursive_family("Yellowtail");
fontdb.set_fantasy_family("Sedgwick Ave Display");
fontdb.set_monospace_family("Noto Mono");

std::sync::Mutex::new(fontdb)
}

/// Converts an SVG string into a usvg Tree
pub fn read_svg(svg_string: &str) -> Tree {
let options = usvg::Options::default();
Tree::from_str(svg_string, &options, &FONTDB.lock().unwrap()).unwrap()
Tree::from_str(svg_string, &options, &FONTDB1.lock().unwrap()).unwrap()
}

/// Converts an image into a PDF and returns the PDF as well as a rendered version
Expand All @@ -77,8 +79,12 @@ pub fn convert_svg(
) -> (Vec<u8>, RgbaImage) {
let svg = fs::read_to_string(svg_path).unwrap();
let tree = read_svg(&svg);
let pdf =
svg2pdf::to_pdf(&tree, conversion_options, page_options, &FONTDB.lock().unwrap());
let pdf = svg2pdf::to_pdf(
&tree,
conversion_options,
page_options,
&FONTDB2.lock().unwrap(),
);
let image = render_pdf(pdf.as_slice());
(pdf, image)
}
Expand Down Expand Up @@ -107,7 +113,7 @@ fn is_pix_diff(pixel1: &Rgba<u8>, pixel2: &Rgba<u8>) -> bool {
|| pixel1.0[3] != pixel2.0[3]
}

const REPLACE: bool = false;
const REPLACE: bool = true;
const PDF: bool = false;

pub fn get_diff(
Expand Down
2 changes: 2 additions & 0 deletions tests/src/render.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1743,6 +1743,7 @@ pub fn run_test(test_name: &str) -> i32 {
#[test] fn custom_paint_servers_linearGradient_linear_gradient_1() {assert_eq!(run_test("custom/paint-servers/linearGradient/linear-gradient-1"), 0)}
#[test] fn custom_paint_servers_linearGradient_linear_gradient_4() {assert_eq!(run_test("custom/paint-servers/linearGradient/linear-gradient-4"), 0)}
#[test] fn custom_paint_servers_linearGradient_linear_gradient_5() {assert_eq!(run_test("custom/paint-servers/linearGradient/linear-gradient-5"), 0)}
#[test] fn custom_paint_servers_linearGradient_linear_gradient_7() {assert_eq!(run_test("custom/paint-servers/linearGradient/linear-gradient-7"), 0)}
#[test] fn custom_paint_servers_linearGradient_linear_gradient_6() {assert_eq!(run_test("custom/paint-servers/linearGradient/linear-gradient-6"), 0)}
#[test] fn custom_paint_servers_linearGradient_linear_gradient_18() {assert_eq!(run_test("custom/paint-servers/linearGradient/linear-gradient-18"), 0)}
#[test] fn custom_paint_servers_linearGradient_linear_gradient_19() {assert_eq!(run_test("custom/paint-servers/linearGradient/linear-gradient-19"), 0)}
Expand All @@ -1754,6 +1755,7 @@ pub fn run_test(test_name: &str) -> i32 {
#[test] fn custom_paint_servers_linearGradient_linear_gradient_13() {assert_eq!(run_test("custom/paint-servers/linearGradient/linear-gradient-13"), 0)}
#[test] fn custom_paint_servers_linearGradient_linear_gradient_11() {assert_eq!(run_test("custom/paint-servers/linearGradient/linear-gradient-11"), 0)}
#[test] fn custom_paint_servers_linearGradient_linear_gradient_10() {assert_eq!(run_test("custom/paint-servers/linearGradient/linear-gradient-10"), 0)}
#[test] fn custom_paint_servers_linearGradient_linear_gradient_8() {assert_eq!(run_test("custom/paint-servers/linearGradient/linear-gradient-8"), 0)}
#[test] fn custom_paint_servers_linearGradient_linear_gradient_9() {assert_eq!(run_test("custom/paint-servers/linearGradient/linear-gradient-9"), 0)}
#[test] fn custom_paint_servers_pattern_patterns_10() {assert_eq!(run_test("custom/paint-servers/pattern/patterns-10"), 0)}
#[test] fn custom_paint_servers_pattern_patterns_11() {assert_eq!(run_test("custom/paint-servers/pattern/patterns-11"), 0)}
Expand Down

0 comments on commit 6bdf75a

Please sign in to comment.