use crate::core::{PlottingError, Result};
use std::path::Path;
#[cfg(feature = "pdf")]
pub fn svg_to_pdf(svg_data: &str) -> Result<Vec<u8>> {
use svg2pdf::usvg;
let mut fontdb = usvg::fontdb::Database::new();
fontdb.load_system_fonts();
let options = usvg::Options {
fontdb: std::sync::Arc::new(fontdb),
..Default::default()
};
let tree = usvg::Tree::from_str(svg_data, &options)
.map_err(|e| PlottingError::RenderError(format!("Failed to parse SVG: {}", e)))?;
let pdf_data = svg2pdf::to_pdf(
&tree,
svg2pdf::ConversionOptions::default(),
svg2pdf::PageOptions::default(),
)
.map_err(|e| PlottingError::RenderError(format!("Failed to convert SVG to PDF: {:?}", e)))?;
Ok(pdf_data)
}
#[cfg(feature = "pdf")]
pub fn svg_to_pdf_file<P: AsRef<Path>>(svg_data: &str, path: P) -> Result<()> {
let pdf_data = svg_to_pdf(svg_data)?;
crate::export::write_bytes_atomic(path, &pdf_data)
}
pub mod page_sizes {
pub const A4: (f64, f64) = (210.0, 297.0);
pub const A4_LANDSCAPE: (f64, f64) = (297.0, 210.0);
pub const LETTER: (f64, f64) = (215.9, 279.4);
pub const LETTER_LANDSCAPE: (f64, f64) = (279.4, 215.9);
pub const PLOT_DEFAULT: (f64, f64) = (160.0, 120.0);
pub fn mm_to_px(mm: f64) -> f32 {
(mm * 96.0 / 25.4) as f32
}
pub fn px_to_mm(px: f32) -> f64 {
px as f64 * 25.4 / 96.0
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
#[cfg(feature = "pdf")]
fn test_svg_to_pdf_basic() {
let svg = r#"<?xml version="1.0" encoding="UTF-8"?>
<svg width="200" height="150" xmlns="http://www.w3.org/2000/svg">
<rect width="100%" height="100%" fill="white"/>
<line x1="10" y1="10" x2="190" y2="140" stroke="black" stroke-width="2"/>
<text x="100" y="75" text-anchor="middle" font-family="sans-serif" font-size="14">Test</text>
</svg>"#;
let result = svg_to_pdf(svg);
assert!(result.is_ok());
let pdf_data = result.unwrap();
assert!(pdf_data.starts_with(b"%PDF-"));
}
#[test]
fn test_page_size_conversion() {
let px = page_sizes::mm_to_px(25.4);
assert!((px - 96.0).abs() < 0.1);
let mm = page_sizes::px_to_mm(96.0);
assert!((mm - 25.4).abs() < 0.1);
}
}