Html To PDF with Templater
BlazorTemplater, WkHtmlToPdfDotNet, HtmlToPDF, 工作紀錄
引言
用參數化的 Blazor 元件產生 html 再轉換成 PDF。
整合 BlazorTemplater
與 Haukcode.WkHtmlToPdfDotNet
兩個套件實作出可參數化送印報表的能力。
安裝套件
用 BlazorTemplater
產生 html, 可支援 Blazor 語法。當然也支援 Parameter 送入參數。 透過此套件就不用辛苦的手刻 html,尤其有明細清單時可以少一些工作。
用 WkHtmlToPdfDotNet
把 html 轉成 PDF。
開發平台
平台: NET8 IDE: Visual Studio 2022 框架: Blazor Web App - Server interactive
關鍵程式碼紀錄
報表元件.razor,可用 [Parameter]
帶入參數動態生成 html。
@using YourProject.Models
<!DOCTYPE html>
<html lang="zh-Hant">
<head>
<meta http-equiv="content-type" content="text/html;charset=utf-8">
<style>
@@page {
size: A4 portrait; /* 直印 */
margin-top: 20mm;
margin-left: 10mm;
margin-right: 10mm;
margin-bottom: 10mm;
}
/* 浮水印 */
.watermark {
background-image: url("@(WatermarkImageUrl)");
}
table {
border-collapse: collapse;
width: 100%;
}
...略...
</style>
</head>
<body class="dev-preview watermark">
<h1>HTML轉PDF測試:銀行簡介</h1>
<div class="big-font" style="font-family:標楷體">@Title</div> @* <--- 參數化 *@
<h1 class="break-page">顯示清單 <small style="color:darkorange;">(強制分頁控制)</small></h1>
<ol>
@foreach (var item in ItemList) @* <--- 明細清單參數化 *@
{
<li>@($"{item.ImageFileName} {item.ImageType}")</li>
}
</ol>
...略...
</body>
</html>
@code {
[Parameter] public string Title { get; set; } = "這是報表標題";
[Parameter] public List<ImageCropInfo> ItemList { get; set; } = new();
[Parameter] public List<(string, string)> BarcodeList { get; set; } = new();
[Parameter] public string WatermarkImageUrl { get; set; } = default!;
}
Html to PDF 轉換程序
/// <summary>
/// A4彩色直印
/// </summary>
public byte[] HtmlToPdf(string html)
{
//# Define document to convert
var doc = new HtmlToPdfDocument()
{
GlobalSettings = {
ColorMode = ColorMode.Color,
Orientation = Orientation.Portrait,
PaperSize = PaperKind.A4,
Margins = new MarginSettings() { Top = 26, Left = 10 },
},
Objects = {
// 也有支援封面
new CoverSettings()
{
HtmlContent = @"
<!DOCTYPE html>
<html>
...略...
</html>
"
},
// 報表內容
new ObjectSettings() {
PagesCount = true,
HtmlContent = html,
WebSettings = { DefaultEncoding = "utf-8", PrintMediaType = true },
LoadSettings = new LoadSettings { ZoomFactor = 1.26 }, //1.26
HeaderSettings = {
FontSize = 9,
Right = "Date: [date]",
Line = false,
Spacing = 0, // 2.812,
HtmlUrl = $"{_navSvc.BaseUri}reportResource/cpaheader.html" // 必需是完整的URL
},
FooterSettings = {
FontSize = 9,
Right = "Page [page] of [toPage]",
Line = true,
Spacing = 2.812,
HtmlUrl = ""
},
}
}
};
//# Convert
byte[] fileBlob = _pdfSvc.Convert(doc);
return fileBlob;
}
產生報表主程式
@* ...略... *@
<MudButton OnClick=HandleComponentRendererReport>
測試 Render Component to Report
</MudButton>
@code {
async Task HandleComponentRendererReport()
{
try
{
f_loading = true;
// 模擬資料
List<ImageCropInfo> itemList = new()
{
new ImageCropInfo { ImageFileName = "image1.jpg", ... },
new ImageCropInfo { ImageFileName = "image2.png", ... },
new ImageCropInfo { ImageFileName = "image3.gif", ... },
};
List<(string, string)> barcodeList = new()
{
("A10011", "data:image/png;base64,iVBORw0KGgoAAAANSUhE..."),
("B10011", "data:image/png;base64,iVBORw0KGgoAAAANSUhE..."),
("C10011", "data:image/png;base64,iVBORw0KGgoAAAANSUhE..."),
};
//# 產生 HTML 報表檔;可帶入參數
string html = new ComponentRenderer<MyHtmlReport>()
.Set(m => m.Title, "唷~ 太神了傑克")
.Set(m => m.ItemList, itemList)
.Set(m => m.BarcodeList, barcodeList)
.Set(m => m.WatermarkImageUrl, $"{navSvc.BaseUri}image/watermark_draft.png")
.Render();
// Convert to blob
byte[] fileBlob = await Task.Run(() => bizSvc.HtmlToPdf(html)); // pdf file blob.
//# 下載檔案
string filename = $"ReportSample_{DateTime.Now.ToString("yyyyMMdd")}.pdf";
await jsTool.DownloadFileAsync(filename, fileBlob);
}
catch (Exception ex)
{
dlgSvc.ShowAlert("出現例外!" + ex.Message);
}
finally
{
f_loading = false;
}
}
}
(EOF)
Last updated