Skip to content

Commit

Permalink
Update to resvg 0.42 (#72)
Browse files Browse the repository at this point in the history
  • Loading branch information
LaurenzV authored Jun 1, 2024
1 parent 8d95917 commit e969b05
Show file tree
Hide file tree
Showing 50 changed files with 782 additions and 462 deletions.
966 changes: 693 additions & 273 deletions Cargo.lock

Large diffs are not rendered by default.

14 changes: 7 additions & 7 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,24 +13,24 @@ license = "MIT OR Apache-2.0"

[workspace.dependencies]
log = "0.4.20"
svg2pdf = { path = ".", default-features = false, version = "0.9.1" }
svg2pdf = { path = ".", default-features = false }
clap = { version = "4.4.2", features = ["derive"] }
clap_complete = "4.4.3"
clap_mangen = "0.2.14"
fontdb = "0.16.1"
image = { version = "0.24", default-features = false, features = ["jpeg", "png", "gif"] }
fontdb = "0.18.0"
image = { version = "0.25.1", default-features = false, features = ["jpeg", "png", "gif"] }
miniz_oxide = "0.7"
once_cell = "1.18.0"
oxipng = { version = "9", default-features = false, features = ["filetime", "parallel", "zopfli"] }
pdf-writer = "0.9"
pdf-writer = "0.10"
pdfium-render = "0.8.6"
termcolor = "1.2"
usvg = { version = "0.41", default-features = false }
usvg = { version = "0.42.0", default-features = false }
tiny-skia = "0.11.4"
unicode-properties = "0.1.1"
resvg = { version = "0.41", default-features = false }
resvg = { version = "0.42.0", default-features = false }
subsetter = "0.1.1"
ttf-parser = { version = "0.20.0" }
ttf-parser = { version = "0.21.1" }
siphasher = { version = "1.0.1"}

[package]
Expand Down
30 changes: 13 additions & 17 deletions cli/src/convert.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
use std::path::{Path, PathBuf};
#[cfg(feature = "text")]
use std::sync::Arc;
use svg2pdf::{ConversionOptions, PageOptions};

pub fn convert_(
Expand All @@ -11,7 +13,6 @@ pub fn convert_(
log::set_max_level(log::LevelFilter::Warn);
}

// Prepare the font database.
let mut fontdb = fontdb::Database::new();
fontdb.load_system_fonts();

Expand All @@ -21,29 +22,24 @@ pub fn convert_(
fontdb.set_fantasy_family("Impact");
fontdb.set_monospace_family("Courier New");

#[cfg(feature = "text")]
let options = usvg::Options {
fontdb: Arc::new(fontdb),
..usvg::Options::default()
};

#[cfg(not(feature = "text"))]
let options = usvg::Options::default();

// Convert the file.
let name = Path::new(input.file_name().ok_or("Input path does not point to a file")?);
let output = output.unwrap_or_else(|| name.with_extension("pdf"));

let svg = std::fs::read_to_string(input).map_err(|_| "Failed to load SVG file")?;

let options = usvg::Options::default();
let tree = usvg::Tree::from_str(&svg, &options).map_err(|err| err.to_string())?;

let tree = usvg::Tree::from_str(
&svg,
&options,
#[cfg(feature = "text")]
&fontdb,
)
.map_err(|err| err.to_string())?;

let pdf = svg2pdf::to_pdf(
&tree,
conversion_options,
page_options,
#[cfg(feature = "text")]
&fontdb,
);
let pdf = svg2pdf::to_pdf(&tree, conversion_options, page_options);

std::fs::write(output, pdf).map_err(|_| "Failed to write PDF file")?;

Expand Down
62 changes: 19 additions & 43 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,17 +16,17 @@ This example reads an SVG file and writes the corresponding PDF back to the disk
# fn main() -> Result<(), Box<dyn std::error::Error>> {
use svg2pdf::usvg::fontdb;
use svg2pdf::{ConversionOptions, PageOptions};
use std::sync::Arc;
let input = "tests/svg/custom/integration/matplotlib/stairs.svg";
let output = "target/stairs.pdf";
let svg = std::fs::read_to_string(input)?;
let options = svg2pdf::usvg::Options::default();
let mut db = fontdb::Database::new();
db.load_system_fonts();
let tree = svg2pdf::usvg::Tree::from_str(&svg, &options, &db)?;
let mut options = svg2pdf::usvg::Options::default();
options.fontdb_mut().load_system_fonts();
let tree = svg2pdf::usvg::Tree::from_str(&svg, &options)?;
let pdf = svg2pdf::to_pdf(&tree, ConversionOptions::default(), PageOptions::default(), &db);
let pdf = svg2pdf::to_pdf(&tree, ConversionOptions::default(), PageOptions::default());
std::fs::write(output, pdf)?;
# Ok(()) }
```
Expand Down Expand Up @@ -60,8 +60,6 @@ pub use usvg;

use once_cell::sync::Lazy;
use pdf_writer::{Chunk, Content, Filter, Finish, Pdf, Ref, TextStr};
#[cfg(feature = "text")]
use usvg::fontdb;
use usvg::{Size, Transform, Tree};

use crate::render::{tree_to_stream, tree_to_xobject};
Expand Down Expand Up @@ -120,7 +118,7 @@ pub struct ConversionOptions {
impl Default for ConversionOptions {
fn default() -> Self {
Self {
compress: false,
compress: true,
raster_scale: 1.5,
embed_text: true,
}
Expand All @@ -129,9 +127,6 @@ impl Default for ConversionOptions {

/// Convert a [`usvg` tree](Tree) into a standalone PDF buffer.
///
/// IMPORTANT: The fontdb that is passed to this function needs to be the
/// same one that was used to convert the SVG string into a [`usvg` tree](Tree)!
///
/// ## Example
/// The example below reads an SVG file, processes text within it, then converts
/// it into a PDF and finally writes it back to the file system.
Expand All @@ -140,34 +135,27 @@ impl Default for ConversionOptions {
/// # fn main() -> Result<(), Box<dyn std::error::Error>> {
/// use svg2pdf::usvg::fontdb;
/// use svg2pdf::{ConversionOptions, PageOptions};
/// use std::sync::Arc;
///
/// let input = "tests/svg/custom/integration/matplotlib/stairs.svg";
/// let output = "target/stairs.pdf";
///
/// let svg = std::fs::read_to_string(input)?;
/// let options = svg2pdf::usvg::Options::default();
/// let mut db = fontdb::Database::new();
/// db.load_system_fonts();
/// let mut tree = svg2pdf::usvg::Tree::from_str(&svg, &options, &db)?;
/// let mut options = svg2pdf::usvg::Options::default();
/// options.fontdb_mut().load_system_fonts();
/// let mut tree = svg2pdf::usvg::Tree::from_str(&svg, &options)?;
///
///
/// let pdf = svg2pdf::to_pdf(&tree, ConversionOptions::default(), PageOptions::default(), &db);
/// let pdf = svg2pdf::to_pdf(&tree, ConversionOptions::default(), PageOptions::default());
/// std::fs::write(output, pdf)?;
/// # Ok(()) }
/// ```
pub fn to_pdf(
tree: &Tree,
conversion_options: ConversionOptions,
page_options: PageOptions,
#[cfg(feature = "text")] fontdb: &fontdb::Database,
) -> Vec<u8> {
let mut ctx = Context::new(
#[cfg(feature = "text")]
tree,
conversion_options,
#[cfg(feature = "text")]
fontdb,
);
let mut ctx = Context::new(tree, conversion_options);
let mut pdf = Pdf::new();

let dpi_ratio = 72.0 / page_options.dpi;
Expand Down Expand Up @@ -225,9 +213,6 @@ pub fn to_pdf(

/// Convert a [Tree] into a [`Chunk`].
///
/// IMPORTANT: The fontdb that is passed to this function needs to be the
/// same one that was used to convert the SVG string into a [`usvg` tree](Tree)!
///
/// This method is intended for use in an existing [`pdf-writer`] workflow. It
/// will always produce a chunk that contains all the necessary objects
/// to embed the SVG into an existing chunk. This method returns the chunk that
Expand All @@ -245,6 +230,7 @@ pub fn to_pdf(
/// ```
/// # fn main() -> Result<(), Box<dyn std::error::Error>> {
/// use std::collections::HashMap;
/// use std::sync::Arc;
/// use svg2pdf;
/// use pdf_writer::{Content, Finish, Name, Pdf, Rect, Ref, Str};
/// use svg2pdf::usvg::fontdb;
Expand All @@ -262,10 +248,10 @@ pub fn to_pdf(
/// // Let's first convert the SVG into an independent chunk.
/// let path = "tests/svg/custom/integration/wikimedia/coat_of_the_arms_of_edinburgh_city_council.svg";
/// let svg = std::fs::read_to_string(path)?;
/// let mut db = fontdb::Database::new();
/// db.load_system_fonts();
/// let tree = svg2pdf::usvg::Tree::from_str(&svg, &svg2pdf::usvg::Options::default(), &db)?;
/// let (mut svg_chunk, svg_id) = svg2pdf::to_chunk(&tree, svg2pdf::ConversionOptions::default(), &db);
/// let mut options = svg2pdf::usvg::Options::default();
/// options.fontdb_mut().load_system_fonts();
/// let tree = svg2pdf::usvg::Tree::from_str(&svg, &options)?;
/// let (mut svg_chunk, svg_id) = svg2pdf::to_chunk(&tree, svg2pdf::ConversionOptions::default());
///
/// // Renumber the chunk so that we can embed it into our existing workflow, and also make sure
/// // to update `svg_id`.
Expand Down Expand Up @@ -320,20 +306,10 @@ pub fn to_pdf(
/// std::fs::write("target/embedded.pdf", pdf.finish())?;
/// # Ok(()) }
/// ```
pub fn to_chunk(
tree: &Tree,
conversion_options: ConversionOptions,
#[cfg(feature = "text")] fontdb: &fontdb::Database,
) -> (Chunk, Ref) {
pub fn to_chunk(tree: &Tree, conversion_options: ConversionOptions) -> (Chunk, Ref) {
let mut chunk = Chunk::new();

let mut ctx = Context::new(
#[cfg(feature = "text")]
tree,
conversion_options,
#[cfg(feature = "text")]
fontdb,
);
let mut ctx = Context::new(tree, conversion_options);
let x_ref = tree_to_xobject(tree, &mut chunk, &mut ctx);
ctx.write_global_objects(&mut chunk);
(chunk, x_ref)
Expand Down
4 changes: 2 additions & 2 deletions src/render/clip_path.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use pdf_writer::types::MaskType;
use pdf_writer::{Chunk, Content, Filter, Finish, Ref};
use usvg::tiny_skia_path::PathSegment;
use usvg::{ClipPath, FillRule, Group, Node, Transform, Visibility};
use usvg::{ClipPath, FillRule, Group, Node, Transform};

use super::group;
use super::path::draw_path;
Expand Down Expand Up @@ -127,7 +127,7 @@ fn extend_segments_from_group(
for child in group.children() {
match child {
Node::Path(ref path) => {
if path.visibility() != Visibility::Hidden {
if path.is_visible() {
path.data().segments().for_each(|segment| match segment {
PathSegment::MoveTo(mut p) => {
transform.map_point(&mut p);
Expand Down
6 changes: 3 additions & 3 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};

/// Render a group with filters as an image.
pub fn render(
Expand Down Expand Up @@ -46,9 +46,9 @@ pub fn render(
let encoded_image = pixmap.encode_png().ok()?;

image::render(
Visibility::Visible,
true,
&ImageKind::PNG(Arc::new(encoded_image)),
ViewBox { rect: layer_bbox, aspect: AspectRatio::default() },
Some(layer_bbox.to_rect()),
chunk,
content,
ctx,
Expand Down
30 changes: 13 additions & 17 deletions src/render/image.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,25 +3,24 @@ 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};

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,
is_visible: bool,
kind: &ImageKind,
view_box: ViewBox,
view_box: Option<Rect>,
chunk: &mut Chunk,
content: &mut Content,
ctx: &mut Context,
rc: &mut ResourceContainer,
) {
if visibility != Visibility::Visible {
if !is_visible {
return;
}

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
10 changes: 4 additions & 6 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 @@ -98,9 +96,9 @@ impl Render for Node {
}
#[cfg(feature = "image")]
Node::Image(ref image) => image::render(
image.visibility(),
image.is_visible(),
image.kind(),
image.view_box(),
None,
chunk,
content,
ctx,
Expand Down
4 changes: 2 additions & 2 deletions src/render/path.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ use pdf_writer::types::ColorSpaceOperand;
use pdf_writer::types::ColorSpaceOperand::Pattern;
use pdf_writer::{Chunk, Content, Finish};
use usvg::tiny_skia_path::PathSegment;
use usvg::Path;
use usvg::{Fill, FillRule, Opacity, Paint, PaintOrder, Rect};
use usvg::{Path, Visibility};
use usvg::{Stroke, Transform};

use super::{gradient, pattern};
Expand All @@ -20,7 +20,7 @@ pub fn render(
rc: &mut ResourceContainer,
accumulated_transform: Transform,
) {
if path.visibility() != Visibility::Visible {
if !path.is_visible() {
return;
}

Expand Down
Loading

0 comments on commit e969b05

Please sign in to comment.