Files
XplorePlane/XP.ReportEngine/Documents/XP.ReportEngineDesign.md

14 KiB
Raw Permalink Blame History

XP.ReportEngine 项目规划

一、项目结构优化

1. 完整目录结构

XP.ReportEngine/
├── Interfaces/
│   ├── IReportGenerator.cs            // 报告生成器核心接口
│   ├── ITemplateEngine.cs               // 模板引擎接口
│   └── IDataBinder.cs                   // 数据绑定接口
├── Models/
│   ├── ReportContext.cs               // 报告上下文(包含测量数据、图片列表)
│   ├── ReportTemplate.cs              // 报告模板定义
│   ├── TemplateElement.cs             // 模板元素定义
│   └── LayoutSettings.cs              // 布局配置参数
├── Services/
│   ├── MeasurementReportBuilder.cs    // 测量报告构建器
│   ├── ImageLayoutService.cs          // 图片排版服务(计算坐标、缩放)
│   ├── TemplateEngine.cs              // 模板引擎实现
│   ├── DataBinder.cs                   // 数据绑定实现
│   └── PdfGenerationService.cs        // PDF生成核心服务
├── Templates/
│   └── StandardReportTemplate.json    // 标准报告模板配置
└── Extensions/
    └── ImageExtensions.cs             // 图像处理扩展方法

二、核心模块设计

1. 报告模板引擎

1.1 模板定义规范

  • JSON模板结构:

    {
      "document": {
        "pageSize": "A4",
        "margins": { "top": 20, "bottom": 20, "left": 20, "right": 20 }
      },
      "pages": [
        {
          "type": "title",
          "elements": [
            { "type": "text", "content": "工业CT检测报告", "style": "title", "position": [10, 10] },
            { "type": "text", "content": "报告日期: ${reportDate}", "style": "subtitle", "position": [10, 30] }
          ]
        },
        {
          "type": "measurement",
          "elements": [
            { "type": "table", "dataKey": "measurements", "position": [10, 10], "size": [190, 100] },
            { "type": "image", "dataKey": "overviewImage", "position": [10, 120], "size": [190, 100] }
          ]
        },
        {
          "type": "defectDetail",
          "elements": [
            { "type": "image", "dataKey": "defectImage", "position": [10, 10], "size": [90, 90] },
            { "type": "text", "content": "缺陷类型: ${defectType}", "style": "normal", "position": [10, 100] }
          ]
        }
      ],
      "styles": {
        "title": { "font": "Arial", "size": 24, "bold": true, "color": "#000000" },
        "subtitle": { "font": "Arial", "size": 16, "italic": true, "color": "#666666" },
        "normal": { "font": "Arial", "size": 12, "color": "#000000" }
      }
    }
    

1.2 模板引擎实现

  • 模板加载与解析:

    public class TemplateEngine : ITemplateEngine
    {
        public ReportTemplate LoadTemplate(string templatePath)
        {
            var json = File.ReadAllText(templatePath);
            return JsonConvert.DeserializeObject<ReportTemplate>(json);
        }
    
        public List<PageElement> ParseTemplate(ReportTemplate template, ReportContext context)
        {
            var elements = new List<PageElement>();
    
            foreach (var page in template.Pages)
            {
                foreach (var element in page.Elements)
                {
                    // 处理数据绑定
                    var boundElement = BindData(element, context);
                    elements.Add(boundElement);
                }
            }
    
            return elements;
        }
    
        private PageElement BindData(PageElement element, ReportContext context)
        {
            // 实现数据绑定逻辑
            if (element.Type == "text" && element.Content.Contains("${"))
            {
                element.Content = DataBinder.Bind(element.Content, context);
            }
            return element;
        }
    }
    

2. 数据绑定系统

2.1 数据绑定机制

  • 支持的绑定语法:
    • ${propertyName} - 基本属性绑定
    • ${object.property} - 对象属性绑定
    • ${list[index]} - 列表索引访问
    • ${function(param)} - 函数调用(如日期格式化)

2.2 数据绑定实现

public class DataBinder : IDataBinder
{
    public string Bind(string template, ReportContext context)
    {
        // 使用正则表达式匹配绑定表达式
        var pattern = @"\$\{([^\}]+)\}";
        return Regex.Replace(template, pattern, match => 
        {
            var expression = match.Groups[1].Value;
            return EvaluateExpression(expression, context);
        });
    }

    private string EvaluateExpression(string expression, ReportContext context)
    {
        // 解析表达式并获取值
        if (expression.Contains("."))
        {
            // 处理对象属性
            var parts = expression.Split('.');
            var obj = context.GetType().GetProperty(parts[0])?.GetValue(context);
            return obj?.GetType().GetProperty(parts[1])?.GetValue(obj)?.ToString() ?? string.Empty;
        }
        else if (expression.Contains("["))
        {
            // 处理列表索引
            var index = int.Parse(expression.Split('[')[1].TrimEnd(']'));
            return context.Images.Count > index ? "Image" : string.Empty;
        }
        else
        {
            // 处理基本属性
            return context.GetType().GetProperty(expression)?.GetValue(context)?.ToString() ?? string.Empty;
        }
    }
}

3. 自动排版功能

3.1 布局引擎设计

  • 核心功能:
    • 页面分隔: 当内容超出一页时自动创建新页
    • 元素定位: 根据模板定义计算元素在页面上的精确位置
    • 尺寸计算: 自动调整元素大小以适应内容
    • 响应式布局: 根据页面尺寸动态调整元素位置

3.2 排版服务实现

public class ImageLayoutService
{
    public LayoutResult CalculateLayout(ReportTemplate template, ReportContext context)
    {
        var result = new LayoutResult();
        var currentPage = 0;
        var currentY = template.Document.Margins.Top;

        foreach (var page in template.Pages)
        {
            foreach (var element in page.Elements)
            {
                // 计算元素位置
                var position = new Point(
                    template.Document.Margins.Left + element.Position[0],
                    currentY + element.Position[1]
                );

                // 计算元素尺寸
                var size = new Size(element.Size[0], element.Size[1]);

                // 检查是否需要换页
                if (position.Y + size.Height > PageSize.A4.Height - template.Document.Margins.Bottom)
                {
                    currentPage++;
                    currentY = template.Document.Margins.Top;
                    position = new Point(
                        template.Document.Margins.Left + element.Position[0],
                        currentY + element.Position[1]
                    );
                }

                // 添加到布局结果
                result.Elements.Add(new LayoutElement
                {
                    Page = currentPage,
                    Element = element,
                    Position = position,
                    Size = size
                });

                // 更新当前Y位置
                currentY = position.Y + size.Height;
            }
        }

        return result;
    }
}

4. 图表嵌入实现

4.1 WPF图表转PDF图像

  • 实现方案:
    • 使用RenderTargetBitmap将WPF控件渲染为位图
    • 支持高质量图像输出(300 DPI
    • 提供图像压缩选项,平衡质量与文件大小

4.2 图像转换服务

public static class ImageExtensions
{
    public static byte[] ToPdfImage(this ImageSource image, double width, double height)
    {
        var renderTarget = new RenderTargetBitmap(
            (int)width, (int)height,
            96, 96, PixelFormats.Pbgra32);

        renderTarget.Render(image);

        using (var stream = new MemoryStream())
        {
            var encoder = new PngBitmapEncoder();
            encoder.Frames.Add(BitmapFrame.Create(renderTarget));
            encoder.Save(stream);
            return stream.ToArray();
        }
    }

    public static byte[] ToPdfImage(this FrameworkElement element, double width, double height)
    {
        var renderTarget = new RenderTargetBitmap(
            (int)width, (int)height,
            96, 96, PixelFormats.Pbgra32);

        renderTarget.Render(element);

        using (var stream = new MemoryStream())
        {
            var encoder = new PngBitmapEncoder();
            encoder.Frames.Add(BitmapFrame.Create(renderTarget));
            encoder.Save(stream);
            return stream.ToArray();
        }
    }
}

三、PDF生成核心流程

1. 生成步骤

  1. 加载模板: 从Templates目录加载JSON模板
  2. 解析上下文: 将MeasurementData和图片列表转换为ReportContext
  3. 数据绑定: 将上下文数据绑定到模板中的占位符
  4. 计算布局: 确定每个元素在PDF页面上的精确位置
  5. 生成PDF: 使用iTextSharp绘制内容到PDF文档
  6. 输出结果: 返回MemoryStream或保存为文件

2. 核心生成服务

public class PdfGenerationService
{
    public MemoryStream GeneratePdf(ReportContext context, string templatePath)
    {
        // 1. 加载模板
        var templateEngine = new TemplateEngine();
        var template = templateEngine.LoadTemplate(templatePath);

        // 2. 解析模板元素
        var elements = templateEngine.ParseTemplate(template, context);

        // 3. 计算布局
        var layoutService = new ImageLayoutService();
        var layout = layoutService.CalculateLayout(template, context);

        // 4. 创建PDF文档
        var document = new Document(PageSize.A4, 
            template.Document.Margins.Left,
            template.Document.Margins.Right,
            template.Document.Margins.Top,
            template.Document.Margins.Bottom);

        var stream = new MemoryStream();
        var writer = PdfWriter.GetInstance(document, stream);
        document.Open();

        // 5. 绘制内容
        DrawContent(document, layout, context);

        // 6. 关闭文档
        document.Close();

        return stream;
    }

    private void DrawContent(Document document, LayoutResult layout, ReportContext context)
    {
        // 实现内容绘制逻辑
        foreach (var element in layout.Elements)
        {
            switch (element.Element.Type)
            {
                case "text":
                    DrawText(document, element);
                    break;
                case "image":
                    DrawImage(document, element, context);
                    break;
                case "table":
                    DrawTable(document, element, context);
                    break;
            }
        }
    }

    private void DrawText(Document document, LayoutElement element)
    {
        var paragraph = new Paragraph(element.Element.Content);
        paragraph.SetLocation(element.Position.X, document.PageSize.Height - element.Position.Y);
        document.Add(paragraph);
    }

    private void DrawImage(Document document, LayoutElement element, ReportContext context)
    {
        // 获取图像数据
        var imageData = context.Images.FirstOrDefault();
        if (imageData == null) return;

        // 创建iTextSharp图像对象
        var image = Image.GetInstance(imageData);
        image.SetAbsolutePosition(element.Position.X, document.PageSize.Height - element.Position.Y - element.Size.Height);
        image.ScaleToFit(element.Size.Width, element.Size.Height);

        document.Add(image);
    }

    private void DrawTable(Document document, LayoutElement element, ReportContext context)
    {
        // 创建表格
        var table = new PdfPTable(3); // 假设3列
        table.WidthPercentage = 100;

        // 添加表头
        table.AddCell(new PdfPCell(new Phrase("参数", new Font(Font.FontFamily.HELVETICA, 12, Font.BOLD))));
        table.AddCell(new PdfPCell(new Phrase("测量值", new Font(Font.FontFamily.HELVETICA, 12, Font.BOLD))));
        table.AddCell(new PdfPCell(new Phrase("标准值", new Font(Font.FontFamily.HELVETICA, 12, Font.BOLD))));

        // 添加数据行
        foreach (var measurement in context.Measurements)
        {
            table.AddCell(new PdfPCell(new Phrase(measurement.Parameter)));
            table.AddCell(new PdfPCell(new Phrase(measurement.Value.ToString())));
            table.AddCell(new PdfPCell(new Phrase(measurement.StandardValue.ToString())));
        }

        document.Add(table);
    }
}

四、最佳实践与建议

1. 性能优化

  • 图像处理: 对大尺寸图像进行压缩和缩放,避免PDF文件过大
  • 内存管理: 使用using语句确保资源及时释放
  • 批量处理: 对大量数据采用分批处理策略,避免UI冻结

2. 错误处理

  • 实现完善的异常捕获机制,特别是图像转换和PDF生成环节
  • 提供友好的错误提示,便于问题排查
  • 添加日志记录功能,跟踪报告生成过程

3. 样式管理

  • 创建样式库,统一字体、颜色、间距等
  • 支持主题切换,适应不同客户的品牌要求
  • 确保打印友好,考虑黑白打印时的可读性

4. 扩展性考虑

  • 插件架构: 设计可扩展的插件系统,便于添加新功能
  • 多格式输出: 基于相同架构,扩展支持Word、Excel等格式输出
  • 云服务集成: 考虑与云存储集成,自动上传生成的报告

通过以上设计,XP.ReportEngine将成为一个灵活、高效、可维护的PDF报告生成系统,满足工业CT检测报告的专业需求,同时保持系统的扩展性和易用性。