邻女詈人网

使用PdfSharp从模板生成Pdf文件

使用PdfSharp从模板生成Pdf文件

最近在做一个生成文档的使用需求。通过先制作一个包含各字段占位符的从模成文档模板,导入这个模板并填写内容替换掉占位符,板生再输出成最终文件。文件

由于版式固定,使用安全性更好,从模成业务上常用Pdf作为最终标准化的板生格式, 在.Net平台下,文件可以使用PdfSharp导入,使用编辑,从模成导出Pdf文档。板生这次做一个生成电子处方Pdf的文件小示例:

制作模板

使用一个Pdf编辑器(如福昕PDF编辑器)创建模板RecipeTemplate

用[形状编辑]绘制表格框体,用[编辑文本]工具,使用先插入好固定的从模成内容,比如标题、板生和各栏目冒号之前的内容。

绘制完成如下图

 再用[表单 - 文本域] 工具,在各个需要生成内容的地方插入表单项。

文本域名称中,填入占位符

假定占位符规则为:

  1. 图片占位符: #{ 字段名称}#
  2. 文字占位符: ${ 字段名称}$

那么“医院名称”展位符则设置如下: 

 完成所有字段的占位符,如下图:

 

编写代码

用visual studio新建一个PdfGenerator的项目,保存RecipeTemplate.pdf至Assets目录并设置复制输出目录方式为“始终复制”

项目引用PdfSharp库

dotnet add package PdfSharp --version 1.50.5147

创建模型类RecipeDocInfo,此类用于承载业务数据

public class RecipeDocInfo    {         public int Id {  get; set; }        public string HospitalName {  get; set; }        public string DepartmentName {  get; set; }        public string ClientName {  get; set; }        public string ClientAge {  get; set; }        public string ClientSex {  get; set; }        public string Rps {  get; set; }        public string DraftEmployeeName {  get; set; }        public string Name {  get; set; }        public decimal Price {  get; set; }        public string Status {  get; set; }        public string AuditEmployeeName {  get; set; }        public string DraftEmployeeSignature {  get; set; }        public string AuditEmployeeSignature {  get; set; }        public string StartTimeString {  get; set; }    }

 Exporter.cs中,创建ExportDocxByObject方法,使用PdfReader.Open()可以获取PdfDocument对象

public static PdfDocument ExportDocxByObject(string templatePath, object data){       var doc = PdfReader.Open(templatePath, PdfDocumentOpenMode.Modify);      return doc;}

PdfDocument.AcroForm()方法可以拿到Pdf文档中的表单对象,该对象中的Fields存储表单项目集合,遍历Key值获取每个表单项

PdfAcroForm form = doc.AcroForm;foreach (var fieldName in form.Fields.Names){      var run = form.Fields[fieldName] as PdfTextField;     text = run.Name;  //获取每一个占位符名称}          

 表单项的Name属性为我们设置的表单名称,即占位符。

接下来处理数据对象,通过反射方式获取对象成员名称,并与占位符作匹配,若占位符包含(string.Contains())该成员名称,则将值写入这个表单项的Value中,这里注意一个多行处理的情况。

foreach (PropertyInfo p in pi){ 	string key = $"${ p.Name}$";	if (text.Contains(key))	{ 		var value = "";		try		{ 			value =  p.GetValue(model, null).ToString();		}		catch (Exception ex)		{ 		}		if (value.Contains('\n'))		{ 			run.MultiLine = true;		}		run.Value = new PdfString(value);		run.ReadOnly = true;	}}

 readOnly设置为true,以防止Pdf表单中的值被随意修改。

同理我们处理图片:

首先数据对象中的内容,应为图片的本地路径或者网络Url

var filePath = p.GetValue(model, null) as string;

 然后读取,绘制图片,注意图片的大小以及位置坐标显示,与表单所对应的框架(/Rect)一致

详细的绘图方式,请参考官方文档:PDFsharp Sample: Graphics - PDFsharp and MigraDoc Wiki

var rectangle = run.Elements.GetRectangle("/Rect");var xForm = new XForm(doc, rectangle.Size);using (var xGraphics = XGraphics.FromPdfPage(doc.Pages[0])){ 	var image = XImage.FromStream(fileStream);	xGraphics.DrawImage(image, rectangle.ToXRect() +new XPoint(0, 400));	var state = xGraphics.Save();	xGraphics.Restore(state);}

完成Exporter.cs之后,在Main函数中使用

public class Program{ 	public static async Task Main(string[] args)	{ 		Console.WriteLine("Generator begin");		var docinfo = GetRecipeDocInfo() {   ...  };		var result = Exporter.ExportDocxByObject(/*template path*/, docinfo);		result.Save(/*output path*/);	}}

 测试

至此完成了所有工作,运行程序,待程序执行完毕后,打开output目录下生成的文档,看看最后效果:

 

项目地址:

jevonsflash/PdfGenerator (github.com)

结束语

根据这一思想,我们可以直观地编辑我们想要的最终文件,无论这个文档多么复杂,我们只用关心占位符和最终的值。

同样,这一思想也可以应用到NPOI库来生成Word文档。

未经允许不得转载:邻女詈人网 » 使用PdfSharp从模板生成Pdf文件