aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorRuben Beltran del Rio <jj@r.bdr.sh>2025-12-16 11:09:49 +0100
committerRuben Beltran del Rio <jj@r.bdr.sh>2025-12-16 11:15:32 +0100
commit6deeee3848e291dee61e239f104dc29bb26f4608 (patch)
treee97308fc347e2abef2272942a7e5d71e56ac0469 /src
parentf08648e4b5a9f7855a2ed9068a386e2f3c596322 (diff)
Benchmark with example, and raw rendering
Diffstat (limited to 'src')
-rw-r--r--src/lib.rs20
-rw-r--r--src/renderer.rs84
2 files changed, 72 insertions, 32 deletions
diff --git a/src/lib.rs b/src/lib.rs
index b56c670..de4146d 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -19,6 +19,7 @@ pub use configuration::{
pub use stage_type::StageType;
use thiserror::Error;
+use cairo::ImageSurface;
/// Error types for rendering
#[derive(Debug, Error)]
@@ -86,6 +87,25 @@ pub fn render_to_svg(
renderer::render_to_svg(map, stage_type, config)
}
+/// Renders a Wardley map to a cairo context.
+///
+/// # Arguments
+///
+/// * `map` - The parsed Wardley map
+/// * `stage_type` - The stage type to use for axis labels
+/// * `config` - Configuration options
+///
+/// # Returns
+///
+/// A string containing the SVG data
+pub fn render_to_surface(
+ map: &Map,
+ stage_type: StageType,
+ config: &Configuration,
+) -> Result<ImageSurface, RenderError> {
+ renderer::render_to_surface(map, stage_type, config)
+}
+
#[cfg(test)]
mod tests {
use super::*;
diff --git a/src/renderer.rs b/src/renderer.rs
index 9991d56..8ac025b 100644
--- a/src/renderer.rs
+++ b/src/renderer.rs
@@ -5,6 +5,7 @@ use crate::configuration::Configuration;
use crate::stage_type::StageType;
use crate::utils::{percent_to_pixel, set_color};
use crate::RenderError;
+use cairo::{Context, Error, FontSlant, FontWeight, Format, ImageSurface, LineCap, LineJoin, Operator, SvgSurface};
/// Renders a map to PNG format
pub fn render_to_png(
@@ -17,8 +18,8 @@ pub fn render_to_png(
+ config.theme.sizes.padding
+ config.theme.sizes.bottom_padding) as i32;
- let surface = cairo::ImageSurface::create(cairo::Format::ARgb32, total_width, total_height)?;
- let ctx = cairo::Context::new(&surface)?;
+ let surface = ImageSurface::create(Format::ARgb32, total_width, total_height)?;
+ let ctx = Context::new(&surface)?;
render(&ctx, map, stage_type, config)?;
@@ -27,6 +28,25 @@ pub fn render_to_png(
Ok(buffer.into_inner())
}
+/// Renders a map to the context
+pub fn render_to_surface(
+ map: &Map,
+ stage_type: StageType,
+ config: &Configuration,
+) -> Result<ImageSurface, RenderError> {
+ let total_width = (config.theme.sizes.map_width + config.theme.sizes.padding * 2.0) as i32;
+ let total_height = (config.theme.sizes.map_height
+ + config.theme.sizes.padding
+ + config.theme.sizes.bottom_padding) as i32;
+
+ let surface = ImageSurface::create(Format::ARgb32, total_width, total_height)?;
+ let ctx = Context::new(&surface)?;
+
+ render(&ctx, map, stage_type, config)?;
+
+ Ok(surface)
+}
+
/// Renders a map to SVG format
pub fn render_to_svg(
map: &Map,
@@ -47,8 +67,8 @@ pub fn render_to_svg(
.to_str()
.ok_or_else(|| RenderError::InvalidConfig("Failed to create temp file path".to_string()))?;
- let surface = cairo::SvgSurface::new(total_width, total_height, Some(path))?;
- let ctx = cairo::Context::new(&surface)?;
+ let surface = SvgSurface::new(total_width, total_height, Some(path))?;
+ let ctx = Context::new(&surface)?;
render(&ctx, map, stage_type, config)?;
@@ -61,7 +81,7 @@ pub fn render_to_svg(
/// Core rendering function
fn render(
- ctx: &cairo::Context,
+ ctx: &Context,
map: &Map,
stage_type: StageType,
config: &Configuration,
@@ -91,7 +111,7 @@ fn render(
Ok(())
}
-fn draw_background(ctx: &cairo::Context, config: &Configuration) -> Result<(), RenderError> {
+fn draw_background(ctx: &Context, config: &Configuration) -> Result<(), RenderError> {
ctx.save()?;
set_color(ctx, &config.theme.colors.background);
ctx.paint()?;
@@ -100,7 +120,7 @@ fn draw_background(ctx: &cairo::Context, config: &Configuration) -> Result<(), R
}
fn draw_stage_patterns(
- ctx: &cairo::Context,
+ ctx: &Context,
_stage_type: StageType,
map: &Map,
config: &Configuration,
@@ -173,7 +193,7 @@ fn draw_stage_patterns(
}
fn draw_axes(
- ctx: &cairo::Context,
+ ctx: &Context,
stage_type: StageType,
map: &Map,
config: &Configuration,
@@ -197,8 +217,8 @@ fn draw_axes(
set_color(ctx, &config.theme.colors.label);
ctx.select_font_face(
"sans-serif",
- cairo::FontSlant::Normal,
- cairo::FontWeight::Normal,
+ FontSlant::Normal,
+ FontWeight::Normal,
);
ctx.set_font_size(fonts.axis_label);
ctx.set_line_width(1.0);
@@ -267,7 +287,7 @@ fn draw_axes(
}
fn draw_stage_dividers(
- ctx: &cairo::Context,
+ ctx: &Context,
map: &Map,
config: &Configuration,
) -> Result<(), RenderError> {
@@ -289,7 +309,7 @@ fn draw_stage_dividers(
}
fn draw_dependencies(
- ctx: &cairo::Context,
+ ctx: &Context,
map: &Map,
config: &Configuration,
) -> Result<(), RenderError> {
@@ -365,7 +385,7 @@ fn draw_dependencies(
Ok(())
}
-fn draw_groups(ctx: &cairo::Context, map: &Map, config: &Configuration) -> Result<(), RenderError> {
+fn draw_groups(ctx: &Context, map: &Map, config: &Configuration) -> Result<(), RenderError> {
use geo::{ConcaveHull, LineString, Point};
use std::collections::HashMap;
use std::f64::consts::PI;
@@ -381,8 +401,8 @@ fn draw_groups(ctx: &cairo::Context, map: &Map, config: &Configuration) -> Resul
// Create offscreen surface for opacity handling
let width = (config.theme.sizes.map_width + config.theme.sizes.vertex_size) as i32;
let height = (config.theme.sizes.map_height + config.theme.sizes.vertex_size) as i32;
- let offscreen = cairo::ImageSurface::create(cairo::Format::ARgb32, width, height)?;
- let offscreen_ctx = cairo::Context::new(&offscreen)?;
+ let offscreen = ImageSurface::create(Format::ARgb32, width, height)?;
+ let offscreen_ctx = Context::new(&offscreen)?;
// Translate to account for vertex width/height
offscreen_ctx.translate(
@@ -435,9 +455,9 @@ fn draw_groups(ctx: &cairo::Context, map: &Map, config: &Configuration) -> Resul
}
// Clear offscreen canvas
- offscreen_ctx.set_operator(cairo::Operator::Clear);
+ offscreen_ctx.set_operator(Operator::Clear);
offscreen_ctx.paint()?;
- offscreen_ctx.set_operator(cairo::Operator::Over);
+ offscreen_ctx.set_operator(Operator::Over);
// Draw path
set_color(&offscreen_ctx, color);
@@ -454,8 +474,8 @@ fn draw_groups(ctx: &cairo::Context, map: &Map, config: &Configuration) -> Resul
// Draw stroke with round caps and joins for smoother appearance
offscreen_ctx.set_line_width(config.theme.sizes.vertex_size * 1.75);
- offscreen_ctx.set_line_cap(cairo::LineCap::Round);
- offscreen_ctx.set_line_join(cairo::LineJoin::Round);
+ offscreen_ctx.set_line_cap(LineCap::Round);
+ offscreen_ctx.set_line_join(LineJoin::Round);
offscreen_ctx.stroke()?;
// Composite onto main context with opacity
@@ -469,7 +489,7 @@ fn draw_groups(ctx: &cairo::Context, map: &Map, config: &Configuration) -> Resul
}
fn draw_vertices(
- ctx: &cairo::Context,
+ ctx: &Context,
map: &Map,
config: &Configuration,
) -> Result<(), RenderError> {
@@ -497,7 +517,7 @@ fn draw_vertices(
}
fn draw_vertex_labels(
- ctx: &cairo::Context,
+ ctx: &Context,
map: &Map,
config: &Configuration,
) -> Result<(), RenderError> {
@@ -505,8 +525,8 @@ fn draw_vertex_labels(
set_color(ctx, &config.theme.colors.label);
ctx.select_font_face(
"sans-serif",
- cairo::FontSlant::Normal,
- cairo::FontWeight::Normal,
+ FontSlant::Normal,
+ FontWeight::Normal,
);
ctx.set_font_size(config.theme.fonts.vertex_label);
@@ -546,7 +566,7 @@ fn draw_vertex_labels(
}
fn draw_inertias(
- ctx: &cairo::Context,
+ ctx: &Context,
map: &Map,
config: &Configuration,
) -> Result<(), RenderError> {
@@ -584,13 +604,13 @@ fn draw_inertias(
}
fn draw_rounded_rect(
- ctx: &cairo::Context,
+ ctx: &Context,
x: f64,
y: f64,
width: f64,
height: f64,
radius: f64,
-) -> Result<(), cairo::Error> {
+) -> Result<(), Error> {
let r = radius;
ctx.new_path();
ctx.arc(
@@ -627,10 +647,10 @@ fn draw_rounded_rect(
/// Wraps text to fit within a given width, breaking at word boundaries
fn wrap_text(
- ctx: &cairo::Context,
+ ctx: &Context,
text: &str,
max_width: f64,
-) -> Result<Vec<String>, cairo::Error> {
+) -> Result<Vec<String>, Error> {
let words: Vec<&str> = text.split_whitespace().collect();
let mut lines = Vec::new();
let mut current_line = String::new();
@@ -667,7 +687,7 @@ fn wrap_text(
}
fn draw_evolutions(
- ctx: &cairo::Context,
+ ctx: &Context,
map: &Map,
config: &Configuration,
) -> Result<(), RenderError> {
@@ -739,15 +759,15 @@ fn draw_evolutions(
Ok(())
}
-fn draw_notes(ctx: &cairo::Context, map: &Map, config: &Configuration) -> Result<(), RenderError> {
+fn draw_notes(ctx: &Context, map: &Map, config: &Configuration) -> Result<(), RenderError> {
let padding = 5.0;
let max_width = 400.0;
ctx.save()?;
ctx.select_font_face(
"sans-serif",
- cairo::FontSlant::Normal,
- cairo::FontWeight::Normal,
+ FontSlant::Normal,
+ FontWeight::Normal,
);
ctx.set_font_size(config.theme.fonts.note);