上传源代码版本

This commit is contained in:
Im-Jenisson
2026-06-01 16:30:29 +08:00
commit b2a9b7d3c2
462 changed files with 104365 additions and 0 deletions

View File

@@ -0,0 +1,257 @@
# PDF页面渲染方案 - ConvertPdfFirstPageToBitmap改造
## 问题诊断
当前`ConvertPdfFirstPageToBitmap`方法只生成纯白色Bitmap未实现PDF页面的实际渲染导致条码识别时无法识别到PDF中的内容包括条码
## 关键需求更新 ⭐
1. **充分利用现有能力**项目代码中已有将PDF URL转换成字节流的功能此方案应与之集成
2. **确保缓存完整性**只要验证了PDF有效性不管是否成功提取条码都必须将PDF字节流缓存到数据库
3. **保障业务连续性**:缓存的目的是确保现场可以正常进行面单打印,条码识别是增强功能非必须功能
## 现有资源确认
- ✅ 项目已集成`DinkToPdf`库(通过`PdfConverterSingleton`
- ✅ 项目已有`System.Drawing``System.Drawing.Imaging`
- ✅ 项目已有PDF URL→字节流的转换能力在下载/上传流程中)
- ✅ 完整的CORE SDK支持
## 改进后的解决方案
### 核心逻辑调整
#### 原始流程(问题):
```
下载PDF → ConvertPdfFirstPageToBitmap(纯白) → 条码识别(失败) → 缓存PDF
```
#### 改进流程(推荐):
```
下载PDF已是字节流
验证PDF有效性 ✅ (关键点:必须执行)
├─ 有效 → 立即缓存PDF字节流到数据库 ⭐ (优先级:高)
└─ 无效 → 标记缓存失败,不阻塞业务
条码识别(可选功能)
├─ ConvertPdfFirstPageToBitmap渲染
├─ RecognizeBarcodeAsync识别
└─ 识别成功 → 更新缓存的条码字段(选择性)
└─ 识别失败 → 不影响已缓存的PDF数据 ⭐
```
### 关键设计原则
#### 原则1缓存优先保障业务
- **验证通过即缓存**PDF验证成功→立即缓存PDF字节流
- **条码是增强功能**条码识别失败不影响PDF缓存
- **现场打印保障**确保缓存的PDF数据始终可用于打印
#### 原则2充分利用现有能力
- **复用字节流处理**项目中已有的PDF URL→字节流转换逻辑
- **整合现有DinkToPdf**如使用DinkToPdf转换复用已有的`PdfConverterSingleton`
- **集成Ghostscript**如采用Ghostscript方案将PDF字节流直接传入
#### 原则3非阻塞设计
- **PDF缓存同步**:验证+缓存为关键路径,必须快速完成
- **条码识别异步**:条码识别为后续异步操作,失败不影响主流程
## 实施方案详细设计
### 方案A基于现有DinkToPdf最小化改动 ✅ **推荐短期**
**优点**
- 项目已集成DinkToPdf
- 与现有代码体系一致
- 改动最小
**流程**
```
PDF字节流已有
验证PDF + 缓存PDF字节流
使用DinkToPdf或项目已有能力进行渲染
条码识别(非必须)
```
### 方案B集成Ghostscript生产级方案 ✅ **推荐长期**
**优点**
- 渲染效果最佳
- 专业PDF处理
- 性能和质量兼优
**流程**
```
PDF字节流已有
验证PDF + 缓存PDF字节流
使用Ghostscript渲染第一页→Bitmap
条码识别(非必须)
```
## 推荐实施流程
### 第一阶段:保障业务连续性(高优先级)
1. **改造缓存逻辑**确保PDF验证通过→立即缓存
-`ProcessSingleCacheTask`中调整顺序
- 先保存PDF字节流再进行条码识别
- 条码识别失败不回滚缓存
2. **缓存表结构确认**确保能存储完整PDF数据
- PdfBytes字段存储PDF二进制数据 ✅ (已有)
- Status字段标记缓存状态 ✅ (已有)
- 条码字段:可选,识别成功时更新 ✅ (已有)
### 第二阶段改造ConvertPdfFirstPageToBitmap方法中优先级
#### 选项A1使用DinkToPdf现有能力
```
输入byte[] pdfBytes已有字节流
处理流程:
1. 使用PdfConverterSingleton进行转换
2. 或复用项目中TagGenerationService的PDF处理逻辑
3. 生成Bitmap用于条码识别
输出Bitmap对象
```
#### 选项B1集成Ghostscript.NET
```bash
dotnet add package Ghostscript.NET
```
```
输入byte[] pdfBytes已有字节流
处理流程:
1. 保存PDF字节流到临时文件
2. 使用GhostscriptRasterizer初始化
3. 设置DPI为200
4. 渲染第一页→Image
5. 转换为Bitmap
6. 清理临时文件
输出Bitmap对象
```
### 第三阶段:异常处理和性能优化(低优先级)
- 渲染超时处理3-5秒
- 大文件内存管理
- 缓存渲染结果
## 实现要点详解
### 关键修改1缓存优先原则
**在ProcessSingleCacheTask中**
```
原始下载PDF → 条码识别 → 成功则保存 → 失败则标记失败
改进下载PDF → 验证PDF → 立即保存PDF → 异步进行条码识别
```
**新增逻辑**
```csharp
// 1. 获取PDF字节流现有能力
byte[] labelBytes = // ... 现有转换逻辑
// 2. 验证PDF有效性
int pageCount = GetPdfPageCount(labelBytes); // 验证通过
// 3. 立即保存PDF到缓存同步
await SaveCacheAsync(
waybillNumber,
labelBytes,
pageCount,
labelBytes.Length,
finalMileTrackingNumber,
customerId
// 暂不传入条码信息
);
// 4. 异步进行条码识别(不阻塞,失败不影响缓存)
_ = Task.Run(async () =>
{
try
{
var (barcodeNumber, barcodeType, confidence) =
await ExtractBarcodeFromPdfAsync(labelBytes);
if (!string.IsNullOrEmpty(barcodeNumber))
{
// 条码识别成功,更新缓存中的条码字段
await UpdateCacheWithBarcodeAsync(waybillNumber, barcodeNumber, barcodeType, confidence);
}
}
catch { /* 静默失败不影响已缓存的PDF */ }
});
```
### 关键修改2PDF字节流复用
**充分利用现有能力**
```
现有代码中的PDF URL → 字节流转换
直接传给ConvertPdfFirstPageToBitmap
直接传给SaveCacheAsync
```
**好处**
- 无需重复转换
- 一次转换多次使用
- 性能最优
## 风险评估与对策
### 风险1缓存失败导致无备份
**风险**如果缓存失败可能没有PDF数据用于打印
**对策**
- 重试机制缓存失败重试3次
- 业务降级缓存失败时保留URL现场可实时下载
- 监控告警记录所有缓存失败的case
### 风险2条码识别阻塞缓存
**风险**:条码识别耗时影响业务
**对策**
- 使用异步Task已设计
- 设置超时控制
- 失败自动降级
### 风险3Ghostscript部署依赖
**风险**Ghostscript需要系统配置
**对策**
- 选择包含预编译二进制的NuGet版本
- 统一部署文档和脚本
- 开发环境提前测试
## 验证方案
### 验收标准
-**业务保障**无论条码识别成否PDF都被成功缓存
-**调试可见**SaveDebugImage输出显示真实PDF内容非空白
-**条码增强**:条码识别成功率>80%(失败不影响业务)
-**性能指标**
- PDF验证+缓存:<1秒
- PDF渲染<3秒
- 条码识别<2秒
- **异常处理**所有异常都被捕获不影响主流程
### 测试场景
1. 正常PDF成功缓存+条码识别成功
2. 正常PDF成功缓存+条码识别失败验收PDF仍被缓存
3. 包含二维码的PDF成功缓存+二维码识别
4. 包含一维码的PDF成功缓存+一维码识别
5. 损坏的PDF缓存失败异常处理业务降级
6. 超大PDF性能和内存测试
## 实施优先级
1. **高优先级**修改缓存逻辑确保验证通过立即缓存
2. **高优先级**改造ConvertPdfFirstPageToBitmap进行真实渲染
3. **中优先级**条码识别异步化失败自动降级
4. **低优先级**性能优化和缓存结果
## 预期效果
完成此方案后
- 业务连续性保障缓存的PDF数据可用于现场打印
- 渲染效果提升调试图像显示真实PDF内容
- 条码识别增强成功识别条码但不强制依赖
- 系统鲁棒性异常不影响核心缓存功能
- 现有资源复用充分利用已有的字节流转换能力