diff --git a/ReportEngine/renderers/html_renderer.py b/ReportEngine/renderers/html_renderer.py index 97ca48d..72198b1 100644 --- a/ReportEngine/renderers/html_renderer.py +++ b/ReportEngine/renderers/html_renderer.py @@ -10,6 +10,7 @@ import html import json import os import re +import base64 from pathlib import Path from typing import Any, Dict, List from loguru import logger @@ -74,6 +75,7 @@ class HTMLRenderer: self.toc_rendered = False self.hero_kpi_signature: tuple | None = None self._lib_cache: Dict[str, str] = {} + self._pdf_font_base64: str | None = None # 初始化图表验证和修复器 self.chart_validator = create_chart_validator() @@ -97,6 +99,11 @@ class HTMLRenderer: """获取第三方库文件的目录路径""" return Path(__file__).parent / "libs" + @staticmethod + def _get_font_path() -> Path: + """返回PDF导出所需字体的路径""" + return Path(__file__).parent / "assets" / "fonts" / "SourceHanSerifSC-Medium.otf" + def _load_lib(self, filename: str) -> str: """ 加载指定的第三方库文件内容 @@ -123,6 +130,22 @@ class HTMLRenderer: print(f"警告: 读取库文件 {filename} 时出错: {e}") return "" + def _load_pdf_font_data(self) -> str: + """加载PDF字体的Base64数据,避免重复读取大型文件""" + if self._pdf_font_base64 is not None: + return self._pdf_font_base64 + font_path = self._get_font_path() + try: + data = font_path.read_bytes() + self._pdf_font_base64 = base64.b64encode(data).decode("ascii") + return self._pdf_font_base64 + except FileNotFoundError: + logger.warning("PDF字体文件缺失:%s", font_path) + except Exception as exc: + logger.warning("读取PDF字体文件失败:%s (%s)", font_path, exc) + self._pdf_font_base64 = "" + return self._pdf_font_base64 + # ====== 公共入口 ====== def render(self, document_ir: Dict[str, Any]) -> str: @@ -221,6 +244,8 @@ class HTMLRenderer: str: head片段HTML。 """ css = self._build_css(theme_tokens) + pdf_font_b64 = self._load_pdf_font_data() + pdf_font_literal = json.dumps(pdf_font_b64) # 加载第三方库 chartjs = self._load_lib("chart.js") @@ -262,6 +287,10 @@ class HTMLRenderer: +