pub use pixmap::{PixmapDocumentGenerator, PixmapRenderer};
pub use svg::{SvgDocumentGenerator, SvgRenderer};
pub use pdf::{PdfDocumentGenerator, PdfRenderer};
use vello_cpu::kurbo::{BezPath, Point, Rect};
use crate::visual::{FillStrokeStyle, GradientDef, Stroke, StrokeStyle, Transform, VisualElement};
mod pixmap;
mod svg;
pub mod pdf;
pub trait PageRenderer {
fn draw_rect(&mut self, rect: Rect, style: &FillStrokeStyle);
fn draw_circle(&mut self, center: Point, radius: f64, style: &FillStrokeStyle);
fn draw_line(&mut self, start: Point, end: Point, style: &StrokeStyle);
fn draw_polyline(&mut self, points: &[Point], style: &StrokeStyle);
fn draw_path(&mut self, path: &BezPath, style: &FillStrokeStyle);
fn draw_gradient_path(&mut self, path: &BezPath, gradient: &GradientDef, stroke: Option<&Stroke>);
fn draw_text_run(
&mut self,
run: &crate::text::TextRun,
position: Point,
);
fn draw_image(
&mut self,
data: &[u8],
format: &str,
position: Point,
size: (f64, f64),
);
fn begin_group(&mut self, transform: Option<&Transform>);
fn end_group(&mut self);
fn render_elements(&mut self, elements: &[VisualElement])
where
Self: Sized,
{
let mut flat: Vec<(i32, &VisualElement)> = Vec::new();
for element in elements {
match element {
VisualElement::ZGroup { z_index, children } => {
for child in children {
flat.push((*z_index, child));
}
}
other => {
flat.push((0, other));
}
}
}
flat.sort_by_key(|(z, _)| *z);
for (_, element) in flat {
self.render_element(element);
}
}
fn render_element(&mut self, element: &VisualElement)
where
Self: Sized,
{
match element {
VisualElement::Rect { rect, style } => {
self.draw_rect(*rect, style);
}
VisualElement::Circle {
center,
radius,
style,
} => {
self.draw_circle(*center, *radius, style);
}
VisualElement::Line { start, end, style } => {
self.draw_line(*start, *end, style);
}
VisualElement::Polyline { points, style } => {
self.draw_polyline(points, style);
}
VisualElement::Path { path, style } => {
self.draw_path(path, style);
}
VisualElement::GradientPath { path, gradient, stroke } => {
self.draw_gradient_path(path, gradient, stroke.as_ref());
}
VisualElement::TextLine { runs, bounds, line_height: _ } => {
let position = bounds.origin();
for run in runs {
self.draw_text_run(run, position);
}
}
VisualElement::Group {
children,
transform,
} => {
self.begin_group(transform.as_ref());
self.render_elements(children);
self.end_group();
}
VisualElement::Image {
position,
size,
pixel_size: _,
data,
format,
alt: _,
} => {
self.draw_image(data, format, *position, (size.x, size.y));
}
VisualElement::ZGroup { children, .. } => {
self.render_elements(children);
}
}
}
}