1#![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
28pub 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
52pub 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}