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 struct RenderOptions {
30 current_color: tiny_skia::Color,
31}
32
33impl RenderOptions {
34
35 pub fn set_color(&mut self, color: tiny_skia::Color) -> &mut Self {
37 self.current_color = color;
38 self
39 }
40}
41
42impl Default for RenderOptions {
43 fn default() -> Self {
44 Self {
45 current_color: tiny_skia::Color::from_rgba8(0, 0, 0, 255),
46 }
47 }
48
49}
50
51pub fn render(
58 tree: &usvg::Tree,
59 transform: tiny_skia::Transform,
60 pixmap: &mut tiny_skia::PixmapMut,
61 options: &RenderOptions,
62) {
63 let target_size = tiny_skia::IntSize::from_wh(pixmap.width(), pixmap.height()).unwrap();
64 let max_bbox = tiny_skia::IntRect::from_xywh(
65 -(target_size.width() as i32) * 2,
66 -(target_size.height() as i32) * 2,
67 target_size.width() * 5,
68 target_size.height() * 5,
69 )
70 .unwrap();
71
72 let ctx = render::Context { max_bbox };
73 render::render_nodes(tree.root(), &ctx, transform, pixmap, options);
74}
75
76pub fn render_node(
87 node: &usvg::Node,
88 mut transform: tiny_skia::Transform,
89 pixmap: &mut tiny_skia::PixmapMut,
90 options: &RenderOptions,
91) -> Option<()> {
92 let bbox = node.abs_layer_bounding_box()?;
93
94 let target_size = tiny_skia::IntSize::from_wh(pixmap.width(), pixmap.height()).unwrap();
95 let max_bbox = tiny_skia::IntRect::from_xywh(
96 -(target_size.width() as i32) * 2,
97 -(target_size.height() as i32) * 2,
98 target_size.width() * 5,
99 target_size.height() * 5,
100 )
101 .unwrap();
102
103 transform = transform.pre_translate(-bbox.x(), -bbox.y());
104
105 let ctx = render::Context { max_bbox };
106 render::render_node(node, &ctx, transform, pixmap, options);
107
108 Some(())
109}
110
111pub(crate) trait OptionLog {
112 fn log_none<F: FnOnce()>(self, f: F) -> Self;
113}
114
115impl<T> OptionLog for Option<T> {
116 #[inline]
117 fn log_none<F: FnOnce()>(self, f: F) -> Self {
118 self.or_else(|| {
119 f();
120 None
121 })
122 }
123}