在App Service 透过Html 产生PDF
使用 TuesPechkin套件在App Service透过Html产生PDF的使用心得。
前言
最近自己和朋友都刚好有在App Service产生PDF的需求,在过去有很多套件都是基于 wkhtmltopdf来实做的,现在要在App Service上使用,是否会因为App Service架构和限制而产生问题:
执行绪问题。
是否会没有中文字形导致中文处理问题。
静态(图片、CSS、JavaScript)档案路径问题。
共用资源App Service Plan 无法有足够资源执行。
实做说明
安装 TuesPechkin 套件
经过一些测试,发现 TuesPechkin 这一个套件可以正常在App Service 使用,语法也算简单,因此最后决定使用这一套来产生PDF。
TuesPechkin 也是以wkhtmltopdf 为基础来开发的套件,我们可以直接透过NuGet 来安装套件,搜寻之后会有四个套件,其中TuesPechkin 为主要套件,其余三个则为对应CPU 核心的的wkhtmltopdf 套件,而为了之后方便,我选择AnyCPU 的套件。
新增 PdfHelper
新增一个静态类别 PdfHelper 来撰写转换Html 成PDF 的程式码。
/// <summary>
/// Pdf 轉換工具
/// </summary>
public static class PdfHelper
{
/* 多執行續類型的程式需使用 ThreadSafeConverter 並且將 Converter 放置在 Static */
private static IConverter converter =
new ThreadSafeConverter(
new RemotingToolset<PdfToolset>(
new WinAnyCPUEmbeddedDeployment(
new TempFolderDeployment())));
/// <summary>
/// 將Html文字 輸出到PDF檔裡
/// </summary>
/// <param name="htmlText"></param>
/// <returns></returns>
public static byte[] ConvertHtmlTextToPDF(string htmlText)
{
if (string.IsNullOrEmpty(htmlText))
{
return null;
}
var document = new HtmlToPdfDocument
{
GlobalSettings = { },
Objects = {
new ObjectSettings {
HtmlText = htmlText
}
}
};
var result = converter.Convert(document);
return result;
}
}
多执行续类型的程式需使用ThreadSafeConverter 并且将Converter 放置在Static
准备要转换的Html
预先准备好要测试来转换的Html,这边需要注意的是:
CSS 中文字形需使用英文名称
图片路径可支援完整路径、Base64、实体档案路径
JavaScript 路径可支援完整路径、实体档案路径
<!DOCTYPE html>
<html lang="zh-tw" xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta charset="utf-8" />
<title>PDF 轉換測試</title>
<style>
body {
margin: 0 auto;
width: 21cm;
}
.text {
font-size: x-large;
}
.text-pmingliu {
font-family: "Microsoft PMingLiU";
}
.text-dfkai {
font-family: DFKai-SB;
}
.text-jhenghei {
font-family: "Microsoft JhengHei";
}
</style>
</head>
<body>
<div>
<!-- 中文測試 -->
<h1>中文測試</h1>
<p class="text text-pmingliu">新細明體</p>
<p class="text text-dfkai">標楷體</p>
<p class="text text-jhenghei">微軟正黑體</p>
<!-- 圖片測試 -->
<h1>圖片測試</h1>
<img src="http://fakeimg.pl/250x100" />完整網址<br>
<img src="data:image/png;base64,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" />Base64<br>
<img src="{BasePath}/Images/250x100.png" />實體路徑<br>
<!-- SVG 不支援 -->
<svg id="svg-app-service" viewBox="0 0 50 50" width="100%" height="100%"> <path fill="#A0A1A2" d="M20.1,46.5H3.5V30h3.4c-0.4-1-0.6-2.1-0.6-3.3c0,0,0-0.1,0-0.2H0V50h23.6V36h-3.5V46.5z"></path> <path fill="#A0A1A2" d="M43.5,30h3v16.6H29.9V36.1h-3.5V50H50V26.5h-7.4c0.5,1,0.9,2,0.9,3.3C43.5,29.8,43.5,29.9,43.5,30z"></path> <path fill="#A0A1A2" d="M3.5,20V3.5h16.6v9.6c1-0.8,2.3-1.3,3.5-1.6V0H0v23.5h6.8C7.3,22.3,8,21,9,20.1L3.5,20L3.5,20z"></path> <path fill="#A0A1A2" d="M29.9,11.1V3.5h16.6v16.6h-7.3c0.3,1,0.5,2.2,0.5,3.4c0,0,0,0.1,0,0.1H50V0H26.4v10.9c0.3,0,0.5-0.1,0.8-0.1 C28.1,10.9,29,10.9,29.9,11.1z"></path> <path fill="#59B4D9" d="M40.8,29.7c0-2.1-1.7-3.7-3.7-3.7c-0.2,0-0.3,0-0.5,0c0.2-0.8,0.4-1.7,0.4-2.6c0-5.5-4.4-9.9-9.9-9.9 c-4.3,0-8,2.8-9.3,6.8c-0.7-0.2-1.4-0.4-2.2-0.4c-3.7,0-6.7,3-6.7,6.8c0,3.8,3,6.8,6.7,6.8c0,0,0,0,0,0v0h21.8l0,0 C39.3,33.3,40.8,31.7,40.8,29.7"></path> <path opacity="0.2" fill="#FFFFFF" d="M19.2,33.5c-0.9-0.9-1.5-2-1.8-3.3c-0.8-3.7,1.4-7.3,5.1-8.1c0.8-0.2,1.5-0.2,2.2-0.1 c0.3-3.4,2.4-6.5,5.5-8c-0.9-0.3-1.9-0.5-3-0.5c-4.3,0-8,2.8-9.3,6.8c-0.7-0.2-1.4-0.4-2.2-0.4c-3.7,0-6.7,3-6.7,6.8 c0,3.8,3,6.8,6.7,6.8c0,0,0,0,0,0v0H19.2z"></path> </svg>SVG
<!-- JavaScript 測試 -->
<p id="js-test"></p>
</div>
<script src="{BasePath}/Scripts/jquery-2.2.4.min.js"></script>
<script>
$(function () {
$("#js-test").html("<b>JavaScript 測試</b>");
});
</script>
</body>
</html>
Action 中转换PDF
[HttpPost]
[ValidateInput(false)] // 這邊是為了範例方便,正式環境不建議這樣使用,導致所有欄位都可以讀 Html
public ActionResult PDF(string Html)
{
if (string.IsNullOrWhiteSpace(Html))
{
Html = System.IO.File.ReadAllText(Server.MapPath("~/App_Data/PDF.html"));
// 取代 {BasePath} 成實體路徑
Html = Html.Replace("{BasePath}", AppDomain.CurrentDomain.BaseDirectory);
}
var pdf = PdfHelper.ConvertHtmlTextToPDF(Html);
return File(pdf, "application/pdf");
}
呈现结果
将程式都完成之后上传到App Service 测试,结果的画面呈现如下图:
其它
在测试的时候还有一点需要注意的, App Service Plan如果选择共用计算类型的定价层(免费、共用)会因为资源权限的关系无法正常转换,至少需要选择基础的定价层才有办法正常执行转换,这一点需要也是需要注意的地方。
结论
在App Service 是可以成功使用套件来转换Html 成PDF,但是仍有些需要注意的项目:
中文字形需使用英文名称,不然无法显示
静态档案需注意路径问题
App Service Plan 需要标准方案以上
此外,本文所写的范例为ASP.NET MVC ,套件也可能无法支援ASP.NET Core,因此未来还需要针对ASP.NET Core 的站台做测试才能知道是否可行或是需要用哪一个套件才可以。
上一篇: phpMyadmin 用户权限中英对照_php技巧
下一篇: GD2绘制图形在浏览器中不能展示