diff --git a/XP.ReportEngine/Documents/FontFilesGuidance.md b/XP.ReportEngine/Documents/FontFilesGuidance.md
new file mode 100644
index 0000000..767ae02
--- /dev/null
+++ b/XP.ReportEngine/Documents/FontFilesGuidance.md
@@ -0,0 +1,54 @@
+# 字体文件目录 | Font Files Directory
+
+## 所需字体文件 | Required Font Files
+
+请将以下字体文件手动添加到 `XP.ReportEngine/Fonts/` 目录:
+
+1. **NotoSansCJKsc-Regular.otf** — 中文字体(CJK 字符支持)| Chinese font (CJK character support)
+2. **NotoSans-Regular.ttf** — 西文字体 | Western font
+
+## 下载地址 | Download Links
+
+- Noto Sans CJK: https://github.com/googlefonts/noto-cjk/releases
+ - 下载 `NotoSansCJKsc-Regular.otf`(简体中文版本)
+ - 文件大小约 16MB
+- Noto Sans: https://fonts.google.com/noto/specimen/Noto+Sans
+ - 下载 Regular 字重的 TTF 文件
+ - 文件大小约 500KB
+
+## 下载步骤 | Download Steps
+
+### NotoSansCJKsc-Regular.otf
+
+1. 访问 https://github.com/googlefonts/noto-cjk/releases
+2. 找到最新 Release,展开 Assets
+3. 下载 `NotoSansCJKsc-Regular.otf`(或从 Sans 包中提取)
+4. 将文件放入 `XP.ReportEngine/Fonts/` 目录
+
+### NotoSans-Regular.ttf
+
+1. 访问 https://fonts.google.com/noto/specimen/Noto+Sans
+2. 点击 "Download family"
+3. 解压后找到 `NotoSans-Regular.ttf`
+4. 将文件放入 `XP.ReportEngine/Fonts/` 目录
+
+## 配置说明 | Configuration Notes
+
+字体文件已在 `.csproj` 中配置为嵌入资源(EmbeddedResource),添加文件后无需额外配置。
+Font files are configured as EmbeddedResource in .csproj, no additional configuration needed after adding files.
+
+```xml
+
+
+
+
+```
+
+## 后备机制 | Fallback Mechanism
+
+如果字体文件缺失,ITextPdfRenderer 会按以下顺序降级:
+1. 尝试加载嵌入的 CJK 字体和西文字体
+2. 加载失败时记录警告日志
+3. 最终使用 iText 内置 Helvetica 字体(不支持中文字符)
+
+因此,如果需要生成包含中文内容的报告,**必须**添加 NotoSansCJKsc-Regular.otf 字体文件。
diff --git a/XP.ReportEngine/Documents/README.md b/XP.ReportEngine/Documents/README.md
new file mode 100644
index 0000000..f4c63ac
--- /dev/null
+++ b/XP.ReportEngine/Documents/README.md
@@ -0,0 +1,214 @@
+# XP.ReportEngine — PDF 报告生成引擎
+
+## 概述
+
+XP.ReportEngine 是 XplorePlane 平面 CT 检测系统的 PDF 报告生成模块。负责将 XP.ImageProcessing 的检测分析结果(距离测量、BGA 气泡率、空隙测量、通孔填锡率)转换为结构化的 PDF 检测报告。
+
+模块采用管线式架构(Pipeline),将报告生成过程分解为五个独立阶段:
+**模板加载 → 数据适配 → 数据绑定 → 排版计算 → PDF 渲染**
+
+## 技术栈
+
+| 依赖 | 版本 | 用途 |
+|------|------|------|
+| .NET 8.0 | net8.0-windows7.0 | 运行时 |
+| itext7 | 8.0.5 | PDF 文档生成核心库 |
+| itext7.bouncy-castle-adapter | 8.0.5 | iText 7 加密支持 |
+| Newtonsoft.Json | 13.0.3 | JSON 模板反序列化 |
+| Prism.Wpf | 9.0.537 | 模块化框架与 DI |
+
+## 项目结构
+
+```
+XP.ReportEngine/
+├── Interfaces/ # 核心接口定义
+│ ├── IReportGenerator.cs
+│ ├── IReportGeneratorFactory.cs
+│ ├── ITemplateEngine.cs
+│ ├── IDataBinder.cs
+│ ├── ILayoutEngine.cs
+│ ├── IPdfRenderer.cs
+│ └── IReportDataAdapter.cs
+├── Models/ # 数据模型
+│ ├── ReportContext.cs
+│ ├── ImageData.cs
+│ ├── ReportTemplate.cs
+│ ├── TemplateElement.cs
+│ ├── LayoutPage.cs
+│ ├── ReportResult.cs
+│ ├── ReportGenerationOptions.cs
+│ └── ProcessorOutput.cs
+├── Services/ # 服务实现
+│ ├── PdfReportGenerator.cs # 管线协调器
+│ ├── ReportGeneratorFactory.cs # 工厂
+│ ├── JsonTemplateEngine.cs # JSON 模板加载与验证
+│ ├── ExpressionDataBinder.cs # ${} 表达式数据绑定
+│ ├── PageLayoutEngine.cs # 分页与排版
+│ ├── ITextPdfRenderer.cs # iText 7 PDF 渲染
+│ ├── ProcessorDataAdapter.cs # 处理器数据适配
+│ └── ReportIdGenerator.cs # 报告编号生成
+├── Fonts/ # 嵌入字体文件(需手动添加)
+├── Templates/ # JSON 报告模板
+│ └── StandardReportTemplate.json
+├── Resources/ # 多语言资源文件
+│ ├── Resources.resx
+│ ├── Resources.zh-CN.resx
+│ ├── Resources.zh-TW.resx
+│ └── Resources.en-US.resx
+├── Documents/ # 项目文档
+├── ReportEngineModule.cs # Prism 模块入口
+└── XP.ReportEngine.csproj
+```
+
+## 快速开始
+
+### 1. 添加字体文件
+
+将以下字体文件放入 `Fonts/` 目录(详见 `Documents/字体文件说明.md`):
+- `NotoSansCJKsc-Regular.otf` — 中文 CJK 字体
+- `NotoSans-Regular.ttf` — 西文字体
+
+### 2. 通过 DI 容器调用
+
+模块通过 `ReportEngineModule` 自动注册到 Prism DI 容器,其他模块可直接注入 `IReportGenerator` 使用:
+
+```csharp
+public class MyService
+{
+ private readonly IReportGenerator _reportGenerator;
+
+ public MyService(IReportGenerator reportGenerator)
+ {
+ _reportGenerator = reportGenerator;
+ }
+
+ public async Task GenerateReport()
+ {
+ var context = new ReportContext
+ {
+ Metadata = new ReportMetadata
+ {
+ ReportId = "RPT-20250511-001",
+ InspectionDate = DateTime.Now,
+ SampleName = "PCB-001",
+ OperatorName = "张三"
+ },
+ Properties = new Dictionary
+ {
+ ["sampleName"] = "PCB-001"
+ }
+ };
+
+ var options = new ReportGenerationOptions
+ {
+ TemplatePath = "Templates/StandardReportTemplate.json",
+ OutputFilePath = @"D:\Reports\report.pdf",
+ Format = ReportOutputFormat.Pdf
+ };
+
+ var result = await _reportGenerator.GenerateAsync(context, options);
+
+ if (result.IsSuccess)
+ {
+ // PDF 已保存到 OutputFilePath
+ }
+ else
+ {
+ // result.ErrorMessage 包含错误信息
+ }
+ }
+}
+```
+
+### 3. 使用数据适配器
+
+将 XP.ImageProcessing 处理器输出转换为 ReportContext:
+
+```csharp
+var adapter = container.Resolve();
+
+var processorOutputs = new List
+{
+ new ProcessorOutput
+ {
+ ProcessorType = "BgaVoidRateProcessor",
+ OutputData = new Dictionary
+ {
+ ["BgaCount"] = 120,
+ ["VoidRate"] = 0.035,
+ ["Classification"] = "Pass"
+ }
+ }
+};
+
+var metadata = new ReportMetadata
+{
+ ReportId = "RPT-20250511-001",
+ InspectionDate = DateTime.Now,
+ SampleName = "PCB-001",
+ OperatorName = "张三"
+};
+
+ReportContext context = adapter.Adapt(processorOutputs, metadata);
+```
+
+## 核心接口
+
+| 接口 | 实现类 | 职责 |
+|------|--------|------|
+| `IReportGenerator` | `PdfReportGenerator` | 协调管线各阶段,生成 PDF |
+| `IReportGeneratorFactory` | `ReportGeneratorFactory` | 根据格式创建对应生成器 |
+| `ITemplateEngine` | `JsonTemplateEngine` | JSON 模板加载、反序列化、验证 |
+| `IDataBinder` | `ExpressionDataBinder` | `${}` 表达式解析与数据绑定 |
+| `ILayoutEngine` | `PageLayoutEngine` | 分页、元素定位、表格跨页 |
+| `IPdfRenderer` | `ITextPdfRenderer` | 使用 iText 7 渲染 PDF |
+| `IReportDataAdapter` | `ProcessorDataAdapter` | OutputData → ReportContext 转换 |
+
+## 数据绑定表达式
+
+模板中支持以下绑定语法:
+
+| 语法 | 说明 | 示例 |
+|------|------|------|
+| `${propertyName}` | 简单属性绑定 | `${sampleName}` |
+| `${object.property}` | 嵌套属性路径 | `${metadata.reportId}` |
+| `${list[index]}` | 列表索引访问 | `${bgaBalls[0].voidRate}` |
+| `${functionName(param)}` | 格式化函数 | `${formatDate(inspectionDate)}` |
+| `${loc:ResourceKey}` | 本地化键解析 | `${loc:Report_Title}` |
+
+内置格式化函数:
+- `formatDate(value)` — 根据当前语言格式化日期
+- `formatNumber(value, decimals)` — 根据当前语言格式化数字
+- `formatPercent(value)` — 格式化百分比
+
+## 多语言支持
+
+支持三种语言:简体中文(zh-CN)、繁体中文(zh-TW)、英文(en-US)。
+
+通过 `ILocalizationService` 自动解析 `${loc:Key}` 表达式为当前语言文本。模块在初始化时注册资源源到 Fallback Chain。
+
+## 模板定义
+
+标准模板位于 `Templates/StandardReportTemplate.json`,包含以下页面类型:
+- `homepage` — 报告首页(元数据 + 摘要表格)
+- `metricData` — 距离测量数据页
+- `bgaInspection` — BGA 焊球检测页(含数据表格)
+- `voidInspection` — 空隙检测页(含数据表格)
+- `viaFillInspection` — 通孔填锡检测页
+
+模板 JSON 结构需包含三个必需顶层字段:`document`、`pages`、`styles`。
+
+## 错误处理
+
+模块采用结果对象模式(Result Pattern),所有公共方法返回 `ReportResult` 而非抛出异常:
+- `ReportResult.Success(stream)` — 成功,包含 PDF MemoryStream
+- `ReportResult.Failure(message, ex)` — 失败,包含错误信息和可选异常
+
+非致命性问题(缺失属性、未定义样式、图像缺失)会记录警告日志并继续执行,不会中断报告生成。
+
+## 构建
+
+```bash
+cd XplorePlane
+dotnet build XP.ReportEngine/XP.ReportEngine.csproj
+```
diff --git a/XP.ReportEngine/Documents/XP.ReportEngine 项目规划.md b/XP.ReportEngine/Documents/XP.ReportEngineDesign.md
similarity index 100%
rename from XP.ReportEngine/Documents/XP.ReportEngine 项目规划.md
rename to XP.ReportEngine/Documents/XP.ReportEngineDesign.md
diff --git a/XP.ReportEngine/Documents/XP.ReportEngine 模板定义.md b/XP.ReportEngine/Documents/XP.ReportEngineModelDefine.md
similarity index 100%
rename from XP.ReportEngine/Documents/XP.ReportEngine 模板定义.md
rename to XP.ReportEngine/Documents/XP.ReportEngineModelDefine.md
diff --git a/XP.ReportEngine/Fonts/NotoSans-Regular.ttf b/XP.ReportEngine/Fonts/NotoSans-Regular.ttf
new file mode 100644
index 0000000..4bac02f
Binary files /dev/null and b/XP.ReportEngine/Fonts/NotoSans-Regular.ttf differ
diff --git a/XP.ReportEngine/Fonts/NotoSerifCJKtc-Regular.otf b/XP.ReportEngine/Fonts/NotoSerifCJKtc-Regular.otf
new file mode 100644
index 0000000..a59de8d
Binary files /dev/null and b/XP.ReportEngine/Fonts/NotoSerifCJKtc-Regular.otf differ
diff --git a/XP.ReportEngine/Fonts/NotoSerifSC-Regular.otf b/XP.ReportEngine/Fonts/NotoSerifSC-Regular.otf
new file mode 100644
index 0000000..be55fbd
Binary files /dev/null and b/XP.ReportEngine/Fonts/NotoSerifSC-Regular.otf differ
diff --git a/XP.ReportEngine/Fonts/README.md b/XP.ReportEngine/Fonts/README.md
deleted file mode 100644
index 0c24001..0000000
--- a/XP.ReportEngine/Fonts/README.md
+++ /dev/null
@@ -1,18 +0,0 @@
-# 字体文件目录 | Font Files Directory
-
-## 所需字体文件 | Required Font Files
-
-请将以下字体文件手动添加到此目录:
-
-1. **NotoSansCJKsc-Regular.otf** — 中文字体(CJK 字符支持)| Chinese font (CJK character support)
-2. **NotoSans-Regular.ttf** — 西文字体 | Western font
-
-## 下载地址 | Download Links
-
-- Noto Sans CJK: https://github.com/googlefonts/noto-cjk/releases
-- Noto Sans: https://fonts.google.com/noto/specimen/Noto+Sans
-
-## 配置说明 | Configuration Notes
-
-字体文件已在 .csproj 中配置为嵌入资源(EmbeddedResource),添加文件后无需额外配置。
-Font files are configured as EmbeddedResource in .csproj, no additional configuration needed after adding files.
diff --git a/XP.ReportEngine/Services/ITextPdfRenderer.cs b/XP.ReportEngine/Services/ITextPdfRenderer.cs
index 784d6f9..87a0ebd 100644
--- a/XP.ReportEngine/Services/ITextPdfRenderer.cs
+++ b/XP.ReportEngine/Services/ITextPdfRenderer.cs
@@ -59,7 +59,8 @@ namespace XP.ReportEngine.Services
///
private const string EvenRowBackgroundColor = "#F5F5F5";
- private PdfFont _cjkFont;
+ private PdfFont _cjkScFont;
+ private PdfFont _cjkTcFont;
private PdfFont _westernFont;
public ITextPdfRenderer(ILoggerService logger, ILocalizationService localizationService)
@@ -255,17 +256,31 @@ namespace XP.ReportEngine.Services
///
private void InitializeFonts()
{
+ // 加载简体中文字体 | Load Simplified Chinese font
try
{
- _cjkFont = LoadEmbeddedFont("XP.ReportEngine.Fonts.NotoSansCJKsc-Regular.otf");
- _logger.Info("CJK 字体加载成功 | CJK font loaded successfully");
+ _cjkScFont = LoadEmbeddedFont("XP.ReportEngine.Fonts.NotoSerifSC-Regular.otf");
+ _logger.Info("简体中文字体加载成功 | Simplified Chinese font loaded successfully");
}
catch (Exception ex)
{
- _logger.Warn("CJK 嵌入字体加载失败,将使用后备字体 | CJK embedded font load failed, will use fallback: {Message}", ex.Message);
- _cjkFont = null;
+ _logger.Warn("简体中文嵌入字体加载失败,将使用后备字体 | SC embedded font load failed, will use fallback: {Message}", ex.Message);
+ _cjkScFont = null;
}
+ // 加载繁体中文字体 | Load Traditional Chinese font
+ try
+ {
+ _cjkTcFont = LoadEmbeddedFont("XP.ReportEngine.Fonts.NotoSerifCJKtc-Regular.otf");
+ _logger.Info("繁体中文字体加载成功 | Traditional Chinese font loaded successfully");
+ }
+ catch (Exception ex)
+ {
+ _logger.Warn("繁体中文嵌入字体加载失败,将使用后备字体 | TC embedded font load failed, will use fallback: {Message}", ex.Message);
+ _cjkTcFont = null;
+ }
+
+ // 加载西文字体 | Load Western font
try
{
_westernFont = LoadEmbeddedFont("XP.ReportEngine.Fonts.NotoSans-Regular.ttf");
@@ -278,7 +293,7 @@ namespace XP.ReportEngine.Services
}
// 如果嵌入字体都不可用,使用 iText 内置 Helvetica | If embedded fonts unavailable, use built-in Helvetica
- if (_cjkFont == null && _westernFont == null)
+ if (_cjkScFont == null && _cjkTcFont == null && _westernFont == null)
{
_logger.Warn("所有嵌入字体不可用,使用 Helvetica 后备字体 | All embedded fonts unavailable, using Helvetica fallback");
}
@@ -309,7 +324,7 @@ namespace XP.ReportEngine.Services
///
/// 根据当前语言获取合适的字体 | Get appropriate font based on current language
- /// zh-CN、zh-TW → CJK 字体;en-US → 西文字体
+ /// zh-CN → 简体中文字体;zh-TW → 繁体中文字体;en-US → 西文字体
///
/// PDF 字体 | PDF font
private PdfFont GetFontForCurrentLanguage()
@@ -320,8 +335,10 @@ namespace XP.ReportEngine.Services
switch (language)
{
case SupportedLanguage.ZhCN:
+ selectedFont = _cjkScFont;
+ break;
case SupportedLanguage.ZhTW:
- selectedFont = _cjkFont;
+ selectedFont = _cjkTcFont ?? _cjkScFont; // 繁体优先,简体后备 | TC preferred, SC fallback
break;
case SupportedLanguage.EnUS:
default:
@@ -335,8 +352,9 @@ namespace XP.ReportEngine.Services
return selectedFont;
}
- // 尝试使用另一种嵌入字体 | Try the other embedded font
- if (_cjkFont != null) return _cjkFont;
+ // 尝试使用其他嵌入字体 | Try other embedded fonts
+ if (_cjkScFont != null) return _cjkScFont;
+ if (_cjkTcFont != null) return _cjkTcFont;
if (_westernFont != null) return _westernFont;
// 最终后备:使用 iText 内置 Helvetica | Final fallback: use built-in Helvetica