使用C#、Nustache、Mustache和Pechkin从HTML创建PDF
本文介绍了如何使用 C# 对象创建 PDF 文件。
背景
最近,我需要完成一项任务,需要创建一个Silverlight页面的PDF版本。标记(XAML)的数据来自C#对象(没错,你猜对了!我们使用了MVVM模式),我们想将该对象用于PDF文件。以下是我们用来创建PDF文件的组件。
- Nustache [^],一个.NET库,用于将对象数据转换为字符串(在本例中为HTML)
- Mustache模板[^] 用于视觉外观
- Pechkin[^],一个.NET PDF库,用于将
string
转换为PDF
依赖项
如上所述,您需要
- Nustache库
- Pechkin
我在示例代码中排除了这些DLL,因为Pechkin包中的一个DLL,wkhtmltox0
,大约有29 MB,导致附件变大。因此,如果您只是打开并按下F5,您将收到构建错误(源代码可以在VS 2010或VS 2012中打开)。
安装依赖项
使用Nuget包管理器
手动安装
您也可以下载这些文件的.zip版本,并手动将其添加到您的项目中。在这种情况下,您应该进行以下设置才能使代码正常工作。
添加引用
将这些文件添加到项目的根目录,并设置“如果较新则复制”
更新web.config(如果您在控制台中使用它,则为App.config)
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="Common.Logging"
publicKeyToken="af08829b84f0328e" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-2.1.2.0" newVersion="2.1.2.0" />
</dependentAssembly>
</assemblyBinding>
</runtime>
Using the Code
示例解决方案包含三个项目
- WCF 服务
- Silverlight应用程序
- Web应用程序
PDFService
PdfService
类提供两种方法
PdfBytes
- 接受任何string
内容并将其转换为客户端的PDF字节。EmployeePdf
- 特定于Employee
对象,它将employee
数据转换为htmlstring
,然后可以将其传递给PdfBytes
方法以获取PDF字节。
public class PdfService : IPdfService
{
public PdfResult PdfBytes(string content)
{
var result = new PdfResult();
try
{
var oc = new ObjectConfig();
oc.SetPrintBackground(true); //to apply the background colors in the pdf
var footer = oc.Footer;
footer.SetFontSize(8);
footer.SetTexts("For internal use only", string.Empty, string.Empty);
result.Bytes = new SynchronizedPechkin(new GlobalConfig()).Convert(oc, content);
}
catch (Exception ex)
{
result.Error = ex.Message;
}
return result;
}
public PdfResult EmployeePdf(Employee employee)
{
string nustachTemplate = Path.Combine
(HostingEnvironment.ApplicationPhysicalPath, "App_Data", "EmployeeTemplate.html");
var employeeHtml = Render.FileToString(nustachTemplate, employee);
return PdfBytes(employeeHtml);
}
}
Employee
对象的数据被注入到Mustache html模板中。您可以应用样式(只有内联样式,样式表无法链接)来设计页面输出。
<html>
<head>
<title>Employee Print</title>
<style>
body {
margin: 5px;
}
h3 {
text-align: center;
border-radius: 10px;
}
h4 {
background: silver;
border-radius: 5px;
padding-left: 10px;
}
</style>
</head>
<body>
<h3>Employee {{Name}}</h3>
<h4>Basic Details</h4>
<div>
<p>Name:</p>
<p>{{Name}}</p>
</div>
<div>
<p>Email:</p>
<p>{{Email}}</p>
</div>
<div>
<p>Address:</p>
<p>{{Address}}</p>
</div>
<h4>Skills</h4>
{{#Skills}}
<p>{{Name}}</p>
{{/Skills}}
{{^Skills}}
<p>No skills</p>
{{/Skills}}
<h4>Hobbies</h4>
{{#Hobbies}}
<p>{{Name}}</p>
{{/Hobbies}}
{{^Hobbies}}
<p>No hobbies</p>
{{/Hobbies}}
<h4>Jobs</h4>
{{#Jobs}}
<p>{{Company}}: as a {{Role}} for {{NoOfYears}} years.</p>
{{/Jobs}}
{{^Jobs}}
<p>No jobs</p>
{{/Jobs}}
</body>
</html>
以及Employee
类
[DataContract]
public class Employee
{
public Employee()
{
Hobbies = new List<Hobby>();
Skills = new List<Skill>();
Jobs = new List<Job>();
}
[DataMember]
public string Name { get; set; }
[DataMember]
public string Address { get; set; }
[DataMember]
public string Email { get; set; }
[DataMember]
public List<Hobby> Hobbies { get; set; }
[DataMember]
public List<Skill> Skills { get; set; }
[DataMember]
public List<Job> Jobs { get; set; }
}
这是最终的PDF
SilverlightApplication1
一个使用PDFService
生成Pdf的客户端应用程序。调用服务并保存文件的代码。
private void ButtonBase_OnClick(object sender, RoutedEventArgs e)
{
var dialog = new SaveFileDialog()
{
DefaultExt = "Adobe PDF Files(*.pdf)",
Filter = "PDF (*.PDF)|*.PDF",
FilterIndex = 2
};
if (dialog.ShowDialog() == true)
{
var client = new PdfServiceClient();
var emp = GetEmployee();
client.EmployeePdfCompleted += (s, ea) =>
{
if (ea.Error != null)
{
MessageBox.Show(string.Format("Error:{0}", ea.Error.Message));
return;
}
if (!string.IsNullOrWhiteSpace(ea.Result.Error))
{
MessageBox.Show(string.Format("Error:{0}", ea.Result.Error));
return;
}
using (System.IO.Stream stream = dialog.OpenFile())
{
stream.Write(ea.Result.Bytes, 0, ea.Result.Bytes.Length);
}
MessageBox.Show("Pdf saved");
};
client.EmployeePdfAsync(emp);
}
}
优点和缺点
优点
- 易于构建页面内容
- 我们可以使用CSS来设置输出样式
- 无需手动计算PDF中的页数。页面根据内容自动生成。
- 免费库
缺点
- DLL大小很大
- 来自Quake2Player:(我还没有遇到这种情况,但感谢您的信息)
一个重要的缺点是,一些主机阻止通过内核执行DLL。例如,Azure网站。因此,例如,不可能执行wkhtmltopdf.exe。
- 您可能还会想到其他什么?
关注点
Nustache和Mustache模板并不是创建PDF文件的必要条件。您可以无需它,只需传递一个string
或构建您自己的html,只要它满足要求即可。我个人更喜欢Mustache,因为它易于构建html,更重要的是,您可以在具有完整HTML布局的情况下根据条件显示或隐藏元素。
在下载示例代码之前
再次说明,除非您按照上面依赖项部分中提到的说明操作,否则示例代码将无法工作。
历史
- 第一版
最后...
我想分享我关于创建PDF的工作,我现在分享了。如果有人觉得这很有趣并且它可以提供帮助,那么我会觉得这是值得的努力。一如既往,欢迎提出意见/建议。