1 | // This Source Code Form is subject to the terms of the Mozilla Public |
2 | // License, v. 2.0. If a copy of the MPL was not distributed with this |
3 | // file, You can obtain one at http://mozilla.org/MPL/2.0/. |
4 | |
5 | /*! |
6 | [resvg](https://github.com/RazrFalcon/resvg) is an SVG rendering library. |
7 | */ |
8 | |
9 | #![forbid (unsafe_code)] |
10 | #![warn (missing_docs)] |
11 | #![allow (clippy::field_reassign_with_default)] |
12 | #![allow (clippy::identity_op)] |
13 | #![allow (clippy::too_many_arguments)] |
14 | #![allow (clippy::uninlined_format_args)] |
15 | #![allow (clippy::upper_case_acronyms)] |
16 | #![allow (clippy::wrong_self_convention)] |
17 | |
18 | pub use tiny_skia; |
19 | pub use usvg; |
20 | |
21 | mod clip; |
22 | mod filter; |
23 | mod geom; |
24 | mod image; |
25 | mod mask; |
26 | mod path; |
27 | mod render; |
28 | |
29 | /// Renders a tree onto the pixmap. |
30 | /// |
31 | /// `transform` will be used as a root transform. |
32 | /// Can be used to position SVG inside the `pixmap`. |
33 | /// |
34 | /// The produced content is in the sRGB color space. |
35 | pub fn render( |
36 | tree: &usvg::Tree, |
37 | transform: tiny_skia::Transform, |
38 | pixmap: &mut tiny_skia::PixmapMut, |
39 | ) { |
40 | let target_size: IntSize = tiny_skia::IntSize::from_wh(pixmap.width(), pixmap.height()).unwrap(); |
41 | let max_bbox: IntRect = tiny_skiaOption::IntRect::from_xywh( |
42 | -(target_size.width() as i32) * 2, |
43 | -(target_size.height() as i32) * 2, |
44 | width:target_size.width() * 4, |
45 | height:target_size.height() * 4, |
46 | ) |
47 | .unwrap(); |
48 | |
49 | let ts: Transform = tree.view_box().to_transform(img_size:tree.size()); |
50 | let root_transform: Transform = transform.pre_concat(ts); |
51 | |
52 | let ctx: Context = render::Context { max_bbox }; |
53 | render::render_nodes(parent:tree.root(), &ctx, root_transform, pixmap); |
54 | } |
55 | |
56 | /// Renders a node onto the pixmap. |
57 | /// |
58 | /// `transform` will be used as a root transform. |
59 | /// Can be used to position SVG inside the `pixmap`. |
60 | /// |
61 | /// The expected pixmap size can be retrieved from `usvg::Node::abs_layer_bounding_box()`. |
62 | /// |
63 | /// Returns `None` when `node` has a zero size. |
64 | /// |
65 | /// The produced content is in the sRGB color space. |
66 | pub fn render_node( |
67 | node: &usvg::Node, |
68 | mut transform: tiny_skia::Transform, |
69 | pixmap: &mut tiny_skia::PixmapMut, |
70 | ) -> Option<()> { |
71 | let bbox: NonZeroRect = node.abs_layer_bounding_box()?; |
72 | |
73 | let target_size: IntSize = tiny_skia::IntSize::from_wh(pixmap.width(), pixmap.height()).unwrap(); |
74 | let max_bbox: IntRect = tiny_skiaOption::IntRect::from_xywh( |
75 | -(target_size.width() as i32) * 2, |
76 | -(target_size.height() as i32) * 2, |
77 | width:target_size.width() * 4, |
78 | height:target_size.height() * 4, |
79 | ) |
80 | .unwrap(); |
81 | |
82 | transform = transform.pre_translate(-bbox.x(), -bbox.y()); |
83 | |
84 | let ctx: Context = render::Context { max_bbox }; |
85 | render::render_node(node, &ctx, transform, pixmap); |
86 | |
87 | Some(()) |
88 | } |
89 | |
90 | pub(crate) trait OptionLog { |
91 | fn log_none<F: FnOnce()>(self, f: F) -> Self; |
92 | } |
93 | |
94 | impl<T> OptionLog for Option<T> { |
95 | #[inline ] |
96 | fn log_none<F: FnOnce()>(self, f: F) -> Self { |
97 | self.or_else(|| { |
98 | f(); |
99 | None |
100 | }) |
101 | } |
102 | } |
103 | |