resvg/
lib.rs

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
17pub use tiny_skia;
18pub use usvg;
19
20mod clip;
21mod filter;
22mod geom;
23mod image;
24mod mask;
25mod path;
26mod 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.
34pub fn render(
35    tree: &usvg::Tree,
36    transform: tiny_skia::Transform,
37    pixmap: &mut tiny_skia::PixmapMut,
38) {
39    let target_size = tiny_skia::IntSize::from_wh(pixmap.width(), pixmap.height()).unwrap();
40    let max_bbox = tiny_skia::IntRect::from_xywh(
41        -(target_size.width() as i32) * 2,
42        -(target_size.height() as i32) * 2,
43        target_size.width() * 5,
44        target_size.height() * 5,
45    )
46    .unwrap();
47
48    let ctx = render::Context { max_bbox };
49    render::render_nodes(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.
62pub fn render_node(
63    node: &usvg::Node,
64    mut transform: tiny_skia::Transform,
65    pixmap: &mut tiny_skia::PixmapMut,
66) -> Option<()> {
67    let bbox = node.abs_layer_bounding_box()?;
68
69    let target_size = tiny_skia::IntSize::from_wh(pixmap.width(), pixmap.height()).unwrap();
70    let max_bbox = tiny_skia::IntRect::from_xywh(
71        -(target_size.width() as i32) * 2,
72        -(target_size.height() as i32) * 2,
73        target_size.width() * 5,
74        target_size.height() * 5,
75    )
76    .unwrap();
77
78    transform = transform.pre_translate(-bbox.x(), -bbox.y());
79
80    let ctx = render::Context { max_bbox };
81    render::render_node(node, &ctx, transform, pixmap);
82
83    Some(())
84}
85
86pub(crate) trait OptionLog {
87    fn log_none<F: FnOnce()>(self, f: F) -> Self;
88}
89
90impl<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}