# Html To PDF with Templater

## 引言

用參數化的 Blazor 元件產生 html 再轉換成 PDF。

整合 `BlazorTemplater` 與 `Haukcode.WkHtmlToPdfDotNet` 兩個套件實作出可參數化送印報表的能力。

## 安裝套件

用 `BlazorTemplater` 產生 html, 可支援 Blazor 語法。當然也支援 Parameter 送入參數。 透過此套件就不用辛苦的手刻 html，尤其有明細清單時可以少一些工作。

{% embed url="<https://github.com/conficient/BlazorTemplater>" %}

用 `WkHtmlToPdfDotNet` 把 html 轉成 PDF。

{% embed url="<https://github.com/HakanL/WkHtmlToPdf-DotNet>" %}

## 開發平台

平台: NET8\
IDE: Visual Studio 2022\
框架: Blazor Web App - Server interactive

## 關鍵程式碼紀錄

報表元件.razor，可用 `[Parameter]` 帶入參數動態生成 html。

<pre class="language-cshtml" data-title="MyHtmlReport.razor" data-line-numbers><code class="lang-cshtml"><strong>@using YourProject.Models
</strong>
&#x3C;!DOCTYPE html>
&#x3C;html lang="zh-Hant">
&#x3C;head>
  &#x3C;meta http-equiv="content-type" content="text/html;charset=utf-8">
  &#x3C;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%;
    }
    ...略...
    
  &#x3C;/style>
&#x3C;/head>
&#x3C;body class="dev-preview watermark">

  &#x3C;h1>HTML轉PDF測試：銀行簡介&#x3C;/h1>
  &#x3C;div class="big-font" style="font-family:標楷體">@Title&#x3C;/div> @* &#x3C;--- 參數化 *@

  &#x3C;h1 class="break-page">顯示清單 &#x3C;small style="color:darkorange;">(強制分頁控制)&#x3C;/small>&#x3C;/h1>
  &#x3C;ol>
    @foreach (var item in ItemList) @* &#x3C;--- 明細清單參數化 *@
    {
      &#x3C;li>@($"{item.ImageFileName} {item.ImageType}")&#x3C;/li>
    }
  &#x3C;/ol>
  ...略...
&#x3C;/body>
&#x3C;/html>

@code {
  [Parameter] public string Title { get; set; } = "這是報表標題";
  [Parameter] public List&#x3C;ImageCropInfo> ItemList { get; set; } = new();
  [Parameter] public List&#x3C;(string, string)> BarcodeList { get; set; } = new();
  [Parameter] public string WatermarkImageUrl { get; set; } = default!;
}
</code></pre>

Html to PDF 轉換程序

{% code title="SampleBiz.cs" lineNumbers="true" %}

```csharp
/// <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;
}
```

{% endcode %}

產生報表主程式

{% code title="YourPage.razor" lineNumbers="true" %}

```cshtml
@* ...略... *@
<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;
    }
  }
}
```

{% endcode %}

(EOF)
