Skip to main content

aster/media/
svg.rs

1//! SVG 渲染模块
2//!
3//! 注:实际渲染需要 resvg 库,这里提供基础验证功能
4
5#![allow(unexpected_cfgs)]
6
7use std::fs;
8use std::path::Path;
9
10#[allow(dead_code)]
11#[cfg(feature = "svg_render")]
12use super::image::ImageResult;
13
14/// SVG 渲染选项
15#[derive(Debug, Clone, Default)]
16pub struct SvgRenderOptions {
17    pub width: Option<u32>,
18    pub height: Option<u32>,
19    pub dpi: Option<u32>,
20    pub background: Option<String>,
21}
22
23/// 默认 DPI
24pub const DEFAULT_SVG_DPI: u32 = 96;
25
26/// 检查是否启用 SVG 渲染
27pub fn is_svg_render_enabled() -> bool {
28    std::env::var("ASTER_SVG_RENDER")
29        .map(|v| v != "false")
30        .unwrap_or(true)
31}
32
33/// 验证 SVG 文件
34pub fn validate_svg_file(file_path: &Path) -> Result<(), String> {
35    if !file_path.exists() {
36        return Err("File does not exist".to_string());
37    }
38
39    let metadata =
40        fs::metadata(file_path).map_err(|e| format!("Failed to read metadata: {}", e))?;
41
42    if metadata.len() == 0 {
43        return Err("SVG file is empty".to_string());
44    }
45
46    let content =
47        fs::read_to_string(file_path).map_err(|e| format!("Failed to read file: {}", e))?;
48
49    if !content.contains("<svg") && !content.contains("<?xml") {
50        return Err("File does not appear to be a valid SVG".to_string());
51    }
52
53    Ok(())
54}
55
56/// 获取 SVG 文件的原始尺寸
57pub fn get_svg_dimensions(svg_path: &Path) -> Option<(u32, u32)> {
58    let content = fs::read_to_string(svg_path).ok()?;
59
60    // 使用正则提取 width 和 height 属性
61    let width = extract_dimension(&content, "width");
62    let height = extract_dimension(&content, "height");
63
64    match (width, height) {
65        (Some(w), Some(h)) => Some((w, h)),
66        _ => None,
67    }
68}
69
70fn extract_dimension(content: &str, attr: &str) -> Option<u32> {
71    let pattern = format!(r#"{}=["'](\d+(?:\.\d+)?)"#, attr);
72    let re = regex::Regex::new(&pattern).ok()?;
73    let caps = re.captures(content)?;
74    caps.get(1)?.as_str().parse::<f64>().ok().map(|v| v as u32)
75}
76
77/// 读取 SVG 文件内容
78pub fn read_svg_file(file_path: &Path) -> Result<String, String> {
79    validate_svg_file(file_path)?;
80    fs::read_to_string(file_path).map_err(|e| format!("Failed to read SVG file: {}", e))
81}
82
83/// SVG 渲染结果(占位实现)
84/// 实际渲染需要 resvg 库
85#[allow(unexpected_cfgs)]
86#[cfg(feature = "svg_render")]
87pub fn render_svg_to_png(
88    svg_path: &Path,
89    _options: SvgRenderOptions,
90) -> Result<ImageResult, String> {
91    use base64::{engine::general_purpose::STANDARD, Engine};
92
93    let content = read_svg_file(svg_path)?;
94    let original_size = content.len() as u64;
95
96    // 这里需要 resvg 库进行实际渲染
97    // 目前返回占位实现
98    Err("SVG rendering requires resvg feature".to_string())
99}
100
101/// 从 SVG 字符串渲染为 PNG(占位实现)
102#[allow(unexpected_cfgs)]
103#[cfg(feature = "svg_render")]
104pub fn render_svg_string_to_png(
105    _svg_string: &str,
106    _options: SvgRenderOptions,
107) -> Result<ImageResult, String> {
108    Err("SVG rendering requires resvg feature".to_string())
109}