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