Skip to main content

chartml_render/
lib.rs

1//! Server-side ChartML rendering: spec → ChartElement → SVG → PNG.
2//!
3//! This crate provides the final rendering step for chartml-rs,
4//! converting ChartElement trees into static PNG images without
5//! requiring a browser, DOM, or JavaScript runtime.
6//!
7//! # Features
8//!
9//! - **SVG serialization** (always available): converts `ChartElement` trees to SVG strings
10//! - **PNG rasterization** (requires `rasterize` feature, enabled by default): converts SVG to PNG
11//!
12//! # Usage
13//!
14//! ```rust,no_run
15//! use chartml_core::ChartML;
16//! use chartml_render::render_to_png;
17//!
18//! let chartml = ChartML::new();
19//! // ... register renderers ...
20//!
21//! let yaml = r#"
22//! type: chart
23//! version: 1
24//! data:
25//!   provider: inline
26//!   rows:
27//!     - { x: "A", y: 10 }
28//!     - { x: "B", y: 20 }
29//! visualize:
30//!   type: bar
31//!   columns: x
32//!   rows: y
33//! "#;
34//!
35//! let png_bytes = render_to_png(&chartml, yaml, 800, 400, 72).unwrap();
36//! ```
37
38pub mod error;
39#[cfg(feature = "rasterize")]
40pub mod rasterize;
41pub mod svg;
42
43pub use error::RenderError;
44#[cfg(feature = "rasterize")]
45pub use rasterize::svg_to_png;
46pub use svg::element_to_svg;
47
48#[cfg(feature = "rasterize")]
49use chartml_core::ChartML;
50
51/// Default padding in CSS pixels around the chart.
52#[cfg(feature = "rasterize")]
53const DEFAULT_PADDING: u32 = 16;
54
55/// White background color.
56#[cfg(feature = "rasterize")]
57const WHITE: [u8; 3] = [255, 255, 255];
58
59/// Render a ChartML YAML spec to PNG bytes (synchronous).
60///
61/// Runs the full pipeline: parse YAML → render ChartElement → SVG → PNG.
62/// Use this for specs with inline data and no async transforms (sql/forecast).
63///
64/// # Arguments
65/// * `chartml` — configured ChartML instance with renderers registered
66/// * `yaml` — ChartML YAML specification string
67/// * `width` — chart width in CSS pixels
68/// * `height` — chart height in CSS pixels
69/// * `density` — DPI (72 = 1x, 144 = 2x for PDF)
70#[cfg(feature = "rasterize")]
71pub fn render_to_png(
72    chartml: &ChartML,
73    yaml: &str,
74    width: u32,
75    height: u32,
76    density: u32,
77) -> Result<Vec<u8>, RenderError> {
78    let element = chartml.render_from_yaml_with_size(
79        yaml,
80        Some(width as f64),
81        Some(height as f64),
82    )?;
83
84    let svg_str = element_to_svg(&element, width as f64, height as f64);
85    svg_to_png(&svg_str, width, height, density, DEFAULT_PADDING, WHITE)
86}
87
88/// Render a ChartML YAML spec to PNG bytes (async).
89///
90/// Runs the full pipeline: parse YAML → transform (DataFusion) → render → SVG → PNG.
91/// Use this for specs that require async transforms (sql, aggregate, forecast).
92///
93/// # Arguments
94/// * `chartml` — configured ChartML instance with renderers and transform middleware registered
95/// * `yaml` — ChartML YAML specification string
96/// * `width` — chart width in CSS pixels
97/// * `height` — chart height in CSS pixels
98/// * `density` — DPI (72 = 1x, 144 = 2x for PDF)
99#[cfg(feature = "rasterize")]
100pub async fn render_to_png_async(
101    chartml: &ChartML,
102    yaml: &str,
103    width: u32,
104    height: u32,
105    density: u32,
106) -> Result<Vec<u8>, RenderError> {
107    let element = chartml.render_from_yaml_with_params_async(
108        yaml,
109        Some(width as f64),
110        Some(height as f64),
111        None,
112    ).await?;
113
114    let svg_str = element_to_svg(&element, width as f64, height as f64);
115    svg_to_png(&svg_str, width, height, density, DEFAULT_PADDING, WHITE)
116}
117
118/// Render a pre-built ChartElement tree to PNG bytes.
119///
120/// Use this when you already have a ChartElement (e.g. from a custom rendering pipeline).
121#[cfg(feature = "rasterize")]
122pub fn element_to_png(
123    element: &chartml_core::ChartElement,
124    width: u32,
125    height: u32,
126    density: u32,
127) -> Result<Vec<u8>, RenderError> {
128    let svg_str = element_to_svg(element, width as f64, height as f64);
129    svg_to_png(&svg_str, width, height, density, DEFAULT_PADDING, WHITE)
130}