Skip to content

Commit e969b05

Browse files
authored
Update to resvg 0.42 (#72)
1 parent 8d95917 commit e969b05

50 files changed

Lines changed: 782 additions & 462 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

Cargo.lock

Lines changed: 693 additions & 273 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -13,24 +13,24 @@ license = "MIT OR Apache-2.0"
1313

1414
[workspace.dependencies]
1515
log = "0.4.20"
16-
svg2pdf = { path = ".", default-features = false, version = "0.9.1" }
16+
svg2pdf = { path = ".", default-features = false }
1717
clap = { version = "4.4.2", features = ["derive"] }
1818
clap_complete = "4.4.3"
1919
clap_mangen = "0.2.14"
20-
fontdb = "0.16.1"
21-
image = { version = "0.24", default-features = false, features = ["jpeg", "png", "gif"] }
20+
fontdb = "0.18.0"
21+
image = { version = "0.25.1", default-features = false, features = ["jpeg", "png", "gif"] }
2222
miniz_oxide = "0.7"
2323
once_cell = "1.18.0"
2424
oxipng = { version = "9", default-features = false, features = ["filetime", "parallel", "zopfli"] }
25-
pdf-writer = "0.9"
25+
pdf-writer = "0.10"
2626
pdfium-render = "0.8.6"
2727
termcolor = "1.2"
28-
usvg = { version = "0.41", default-features = false }
28+
usvg = { version = "0.42.0", default-features = false }
2929
tiny-skia = "0.11.4"
3030
unicode-properties = "0.1.1"
31-
resvg = { version = "0.41", default-features = false }
31+
resvg = { version = "0.42.0", default-features = false }
3232
subsetter = "0.1.1"
33-
ttf-parser = { version = "0.20.0" }
33+
ttf-parser = { version = "0.21.1" }
3434
siphasher = { version = "1.0.1"}
3535

3636
[package]

cli/src/convert.rs

Lines changed: 13 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
use std::path::{Path, PathBuf};
2+
#[cfg(feature = "text")]
3+
use std::sync::Arc;
24
use svg2pdf::{ConversionOptions, PageOptions};
35

46
pub fn convert_(
@@ -11,7 +13,6 @@ pub fn convert_(
1113
log::set_max_level(log::LevelFilter::Warn);
1214
}
1315

14-
// Prepare the font database.
1516
let mut fontdb = fontdb::Database::new();
1617
fontdb.load_system_fonts();
1718

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

25+
#[cfg(feature = "text")]
26+
let options = usvg::Options {
27+
fontdb: Arc::new(fontdb),
28+
..usvg::Options::default()
29+
};
30+
31+
#[cfg(not(feature = "text"))]
32+
let options = usvg::Options::default();
33+
2434
// Convert the file.
2535
let name = Path::new(input.file_name().ok_or("Input path does not point to a file")?);
2636
let output = output.unwrap_or_else(|| name.with_extension("pdf"));
2737

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

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

32-
let tree = usvg::Tree::from_str(
33-
&svg,
34-
&options,
35-
#[cfg(feature = "text")]
36-
&fontdb,
37-
)
38-
.map_err(|err| err.to_string())?;
39-
40-
let pdf = svg2pdf::to_pdf(
41-
&tree,
42-
conversion_options,
43-
page_options,
44-
#[cfg(feature = "text")]
45-
&fontdb,
46-
);
42+
let pdf = svg2pdf::to_pdf(&tree, conversion_options, page_options);
4743

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

src/lib.rs

Lines changed: 19 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -16,17 +16,17 @@ This example reads an SVG file and writes the corresponding PDF back to the disk
1616
# fn main() -> Result<(), Box<dyn std::error::Error>> {
1717
use svg2pdf::usvg::fontdb;
1818
use svg2pdf::{ConversionOptions, PageOptions};
19+
use std::sync::Arc;
1920
2021
let input = "tests/svg/custom/integration/matplotlib/stairs.svg";
2122
let output = "target/stairs.pdf";
2223
2324
let svg = std::fs::read_to_string(input)?;
24-
let options = svg2pdf::usvg::Options::default();
25-
let mut db = fontdb::Database::new();
26-
db.load_system_fonts();
27-
let tree = svg2pdf::usvg::Tree::from_str(&svg, &options, &db)?;
25+
let mut options = svg2pdf::usvg::Options::default();
26+
options.fontdb_mut().load_system_fonts();
27+
let tree = svg2pdf::usvg::Tree::from_str(&svg, &options)?;
2828
29-
let pdf = svg2pdf::to_pdf(&tree, ConversionOptions::default(), PageOptions::default(), &db);
29+
let pdf = svg2pdf::to_pdf(&tree, ConversionOptions::default(), PageOptions::default());
3030
std::fs::write(output, pdf)?;
3131
# Ok(()) }
3232
```
@@ -60,8 +60,6 @@ pub use usvg;
6060

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

6765
use crate::render::{tree_to_stream, tree_to_xobject};
@@ -120,7 +118,7 @@ pub struct ConversionOptions {
120118
impl Default for ConversionOptions {
121119
fn default() -> Self {
122120
Self {
123-
compress: false,
121+
compress: true,
124122
raster_scale: 1.5,
125123
embed_text: true,
126124
}
@@ -129,9 +127,6 @@ impl Default for ConversionOptions {
129127

130128
/// Convert a [`usvg` tree](Tree) into a standalone PDF buffer.
131129
///
132-
/// IMPORTANT: The fontdb that is passed to this function needs to be the
133-
/// same one that was used to convert the SVG string into a [`usvg` tree](Tree)!
134-
///
135130
/// ## Example
136131
/// The example below reads an SVG file, processes text within it, then converts
137132
/// it into a PDF and finally writes it back to the file system.
@@ -140,34 +135,27 @@ impl Default for ConversionOptions {
140135
/// # fn main() -> Result<(), Box<dyn std::error::Error>> {
141136
/// use svg2pdf::usvg::fontdb;
142137
/// use svg2pdf::{ConversionOptions, PageOptions};
138+
/// use std::sync::Arc;
143139
///
144140
/// let input = "tests/svg/custom/integration/matplotlib/stairs.svg";
145141
/// let output = "target/stairs.pdf";
146142
///
147143
/// let svg = std::fs::read_to_string(input)?;
148-
/// let options = svg2pdf::usvg::Options::default();
149-
/// let mut db = fontdb::Database::new();
150-
/// db.load_system_fonts();
151-
/// let mut tree = svg2pdf::usvg::Tree::from_str(&svg, &options, &db)?;
144+
/// let mut options = svg2pdf::usvg::Options::default();
145+
/// options.fontdb_mut().load_system_fonts();
146+
/// let mut tree = svg2pdf::usvg::Tree::from_str(&svg, &options)?;
152147
///
153148
///
154-
/// let pdf = svg2pdf::to_pdf(&tree, ConversionOptions::default(), PageOptions::default(), &db);
149+
/// let pdf = svg2pdf::to_pdf(&tree, ConversionOptions::default(), PageOptions::default());
155150
/// std::fs::write(output, pdf)?;
156151
/// # Ok(()) }
157152
/// ```
158153
pub fn to_pdf(
159154
tree: &Tree,
160155
conversion_options: ConversionOptions,
161156
page_options: PageOptions,
162-
#[cfg(feature = "text")] fontdb: &fontdb::Database,
163157
) -> Vec<u8> {
164-
let mut ctx = Context::new(
165-
#[cfg(feature = "text")]
166-
tree,
167-
conversion_options,
168-
#[cfg(feature = "text")]
169-
fontdb,
170-
);
158+
let mut ctx = Context::new(tree, conversion_options);
171159
let mut pdf = Pdf::new();
172160

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

226214
/// Convert a [Tree] into a [`Chunk`].
227215
///
228-
/// IMPORTANT: The fontdb that is passed to this function needs to be the
229-
/// same one that was used to convert the SVG string into a [`usvg` tree](Tree)!
230-
///
231216
/// This method is intended for use in an existing [`pdf-writer`] workflow. It
232217
/// will always produce a chunk that contains all the necessary objects
233218
/// to embed the SVG into an existing chunk. This method returns the chunk that
@@ -245,6 +230,7 @@ pub fn to_pdf(
245230
/// ```
246231
/// # fn main() -> Result<(), Box<dyn std::error::Error>> {
247232
/// use std::collections::HashMap;
233+
/// use std::sync::Arc;
248234
/// use svg2pdf;
249235
/// use pdf_writer::{Content, Finish, Name, Pdf, Rect, Ref, Str};
250236
/// use svg2pdf::usvg::fontdb;
@@ -262,10 +248,10 @@ pub fn to_pdf(
262248
/// // Let's first convert the SVG into an independent chunk.
263249
/// let path = "tests/svg/custom/integration/wikimedia/coat_of_the_arms_of_edinburgh_city_council.svg";
264250
/// let svg = std::fs::read_to_string(path)?;
265-
/// let mut db = fontdb::Database::new();
266-
/// db.load_system_fonts();
267-
/// let tree = svg2pdf::usvg::Tree::from_str(&svg, &svg2pdf::usvg::Options::default(), &db)?;
268-
/// let (mut svg_chunk, svg_id) = svg2pdf::to_chunk(&tree, svg2pdf::ConversionOptions::default(), &db);
251+
/// let mut options = svg2pdf::usvg::Options::default();
252+
/// options.fontdb_mut().load_system_fonts();
253+
/// let tree = svg2pdf::usvg::Tree::from_str(&svg, &options)?;
254+
/// let (mut svg_chunk, svg_id) = svg2pdf::to_chunk(&tree, svg2pdf::ConversionOptions::default());
269255
///
270256
/// // Renumber the chunk so that we can embed it into our existing workflow, and also make sure
271257
/// // to update `svg_id`.
@@ -320,20 +306,10 @@ pub fn to_pdf(
320306
/// std::fs::write("target/embedded.pdf", pdf.finish())?;
321307
/// # Ok(()) }
322308
/// ```
323-
pub fn to_chunk(
324-
tree: &Tree,
325-
conversion_options: ConversionOptions,
326-
#[cfg(feature = "text")] fontdb: &fontdb::Database,
327-
) -> (Chunk, Ref) {
309+
pub fn to_chunk(tree: &Tree, conversion_options: ConversionOptions) -> (Chunk, Ref) {
328310
let mut chunk = Chunk::new();
329311

330-
let mut ctx = Context::new(
331-
#[cfg(feature = "text")]
332-
tree,
333-
conversion_options,
334-
#[cfg(feature = "text")]
335-
fontdb,
336-
);
312+
let mut ctx = Context::new(tree, conversion_options);
337313
let x_ref = tree_to_xobject(tree, &mut chunk, &mut ctx);
338314
ctx.write_global_objects(&mut chunk);
339315
(chunk, x_ref)

src/render/clip_path.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use pdf_writer::types::MaskType;
22
use pdf_writer::{Chunk, Content, Filter, Finish, Ref};
33
use usvg::tiny_skia_path::PathSegment;
4-
use usvg::{ClipPath, FillRule, Group, Node, Transform, Visibility};
4+
use usvg::{ClipPath, FillRule, Group, Node, Transform};
55

66
use super::group;
77
use super::path::draw_path;
@@ -127,7 +127,7 @@ fn extend_segments_from_group(
127127
for child in group.children() {
128128
match child {
129129
Node::Path(ref path) => {
130-
if path.visibility() != Visibility::Hidden {
130+
if path.is_visible() {
131131
path.data().segments().for_each(|segment| match segment {
132132
PathSegment::MoveTo(mut p) => {
133133
transform.map_point(&mut p);

src/render/filter.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use crate::util::resources::ResourceContainer;
44
use pdf_writer::{Chunk, Content};
55
use std::sync::Arc;
66
use tiny_skia::{Size, Transform};
7-
use usvg::{AspectRatio, Group, ImageKind, Node, ViewBox, Visibility};
7+
use usvg::{Group, ImageKind, Node};
88

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

4848
image::render(
49-
Visibility::Visible,
49+
true,
5050
&ImageKind::PNG(Arc::new(encoded_image)),
51-
ViewBox { rect: layer_bbox, aspect: AspectRatio::default() },
51+
Some(layer_bbox.to_rect()),
5252
chunk,
5353
content,
5454
ctx,

src/render/image.rs

Lines changed: 13 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -3,25 +3,24 @@ use std::rc::Rc;
33
use image::{ColorType, DynamicImage, ImageFormat, Luma, Rgb, Rgba};
44
use miniz_oxide::deflate::{compress_to_vec_zlib, CompressionLevel};
55
use pdf_writer::{Chunk, Content, Filter, Finish};
6-
use usvg::{ImageKind, Size, Transform, Tree, ViewBox, Visibility};
6+
use usvg::{ImageKind, Rect, Size, Transform, Tree};
77

88
use crate::render::tree_to_xobject;
99
use crate::util::context::Context;
10-
use crate::util::helper;
11-
use crate::util::helper::{image_rect, NameExt, TransformExt};
10+
use crate::util::helper::{NameExt, TransformExt};
1211
use crate::util::resources::ResourceContainer;
1312

1413
/// Render an image into a content stream.
1514
pub fn render(
16-
visibility: Visibility,
15+
is_visible: bool,
1716
kind: &ImageKind,
18-
view_box: ViewBox,
17+
view_box: Option<Rect>,
1918
chunk: &mut Chunk,
2019
content: &mut Content,
2120
ctx: &mut Context,
2221
rc: &mut ResourceContainer,
2322
) {
24-
if visibility != Visibility::Visible {
23+
if !is_visible {
2524
return;
2625
}
2726

@@ -79,29 +78,26 @@ pub fn render(
7978
ImageKind::SVG(tree) => create_svg_image(tree, chunk, ctx, rc),
8079
};
8180

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

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

9287
// Account for the x/y of the viewbox.
9388
content.transform(
94-
Transform::from_translate(image_rect.x(), image_rect.y()).to_pdf_transform(),
89+
Transform::from_translate(view_box.x(), view_box.y()).to_pdf_transform(),
9590
);
91+
9692
// Scale the image from 1x1 to the actual dimensions.
9793
content.transform(
9894
Transform::from_row(
99-
image_rect.width(),
95+
view_box.width(),
10096
0.0,
10197
0.0,
102-
-image_rect.height(),
98+
-view_box.height(),
10399
0.0,
104-
image_rect.height(),
100+
view_box.height(),
105101
)
106102
.to_pdf_transform(),
107103
);

src/render/mod.rs

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -29,11 +29,9 @@ pub fn tree_to_stream(
2929
) {
3030
content.save_state();
3131

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

3836
content.transform(initial_transform.to_pdf_transform());
3937

@@ -98,9 +96,9 @@ impl Render for Node {
9896
}
9997
#[cfg(feature = "image")]
10098
Node::Image(ref image) => image::render(
101-
image.visibility(),
99+
image.is_visible(),
102100
image.kind(),
103-
image.view_box(),
101+
None,
104102
chunk,
105103
content,
106104
ctx,

src/render/path.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@ use pdf_writer::types::ColorSpaceOperand;
22
use pdf_writer::types::ColorSpaceOperand::Pattern;
33
use pdf_writer::{Chunk, Content, Finish};
44
use usvg::tiny_skia_path::PathSegment;
5+
use usvg::Path;
56
use usvg::{Fill, FillRule, Opacity, Paint, PaintOrder, Rect};
6-
use usvg::{Path, Visibility};
77
use usvg::{Stroke, Transform};
88

99
use super::{gradient, pattern};
@@ -20,7 +20,7 @@ pub fn render(
2020
rc: &mut ResourceContainer,
2121
accumulated_transform: Transform,
2222
) {
23-
if path.visibility() != Visibility::Visible {
23+
if !path.is_visible() {
2424
return;
2525
}
2626

0 commit comments

Comments
 (0)