在 pdf 文件最後一頁才顯示 footer

前言

在 將 datatable 的資料轉出成有浮水印的 PDF 檔 (2) 中,我們已可以將 datatable 的資料轉出有浮水印的 pdf 檔。 但客戶有個需求是, footer 可以在最後一頁才顯示嗎?

因為我們是透過 Excel 去轉成 PDF ,於是就研究看看 Excel 是否可在最後一頁才顯示,參考 Excel 有多頁列時,只希望列印最後一頁的頁尾,其他分頁都不會印出 似乎不容易 (啓動巨集呢!)

研究

Excel 無法操作,那就看看 PDF 是否可以加工,研究了一下,可以在不同的 Page 中加入 Header 及 Footer 。
所以在產生 PDF 後,在最後一頁加入我們要的 Footer 就可以了。
程式如下,

public static MemoryStream AddFooterAndWatermark(MemoryStream pdfStream, WatermarkArg arg)
{
	var pdfDocument = new Aspose.Pdf.Document(pdfStream);
	var pdfLastPage = pdfDocument.Pages[pdfDocument.Pages.Count];
	var footer = new Aspose.Pdf.HeaderFooter();
	//Instantiate a table object
	Aspose.Pdf.Table tab1 = new Aspose.Pdf.Table();
	tab1.HorizontalAlignment = HorizontalAlignment.Center;
	//設定預設的文字格式
	var defaultTextState = new TextState("MingLiU", 8);
	footer.Paragraphs.Add(tab1);
	tab1.DefaultColumnWidth = "180";
	tab1.DefaultCellTextState = defaultTextState;
	//Create rows in the table and then cells in the rows
	var row1 = tab1.Rows.Add();
	var cellL = row1.Cells.Add("信用資訊查詢主管");
	//cellL.DefaultCellTextState = defaultTextState;
	cellL.Alignment = HorizontalAlignment.Left;
	var cellR = row1.Cells.Add("經辦");
	cellR.Alignment = HorizontalAlignment.Right;
	pdfLastPage.Footer = footer;

	if (!string.IsNullOrWhiteSpace(arg.Watermark))
	{
		var text = new FormattedText(arg.Watermark);
		foreach (var page in pdfDocument.Pages)
		{
			switch (arg.WMStyle)
			{
				case WatermarkStyle.FitPage:
					AddWatermarkFitPage(page, arg);
					break;
				case WatermarkStyle.RepeatHorizontal:
					AddWatermarkRepeatHorizontal(page, arg);
					break;

				default:
					break;
			}
		}
	}
	var newPdfStream = new MemoryStream();
	pdfDocument.Save(newPdfStream);
	return newPdfStream;
}

所以使用時,如果有要 Footer 的話,就改 Call AddFooterAndWatermark 這個 Method。

protected void btnFooter_Click(object sender, EventArgs e)
{
	var excelArg = new ExportDataTable2ExcelArg
	{
		dataSource = GetDataSource(),
		HeaderCenter = "&24 This is Report Header ...",
		HeaderRight = $"&12 使用者:Rainmaker\r日期:{DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss")}",
		FooterRight = "&10 &P/&N",
		ColumnInfos = new Dictionary<string, Tuple<string, double, Aspose.Cells.Style>>
		{
			{"ProductID", new Tuple<string, double, Aspose.Cells.Style>($"產品代號", -1, null) },
			{"ProductName", new Tuple<string, double, Aspose.Cells.Style>("產品名稱" , -1, null) },
			{"ProductDesc", new Tuple<string, double, Aspose.Cells.Style>("產品描述" , -1, null) },
			{"Units", new Tuple<string, double, Aspose.Cells.Style>("產品 庫存" , -1, null) },
			{"CreDte", new Tuple<string, double, Aspose.Cells.Style>("日期" , 10, new Aspose.Cells.Style{ Number = 14 }) }
		},
		PageOrientation = PageOrientationType.Landscape,
		IsTextWrapped = false,
		PageScale = 80,
		FontName = "標楷體",
		HeaderHorizontalAlignment = TextAlignmentType.Center
	};
	var pdfStream = GenPDFFromDataTable(excelArg);
	var fileNameWithoutExt = $"{Guid.NewGuid().ToString("N")}";

	var watermarkArg = new WatermarkArg
	{
		Watermark = $"* 使用者:亂馬客  *{Environment.NewLine}{DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss")}",
		WMStyle = WatermarkStyle.RepeatHorizontal,
		WatermarkHeight = 100,
		WatermarkWidth = 130,
		WatermarkHorizontalSpace = 50,
		WatermarkVerticalSpace = 30,
		RotateAngle = 30,
		Opacity = .1

	};
	var waterStream = AddFooterAndWatermark(pdfStream, watermarkArg);
	Response.ContentType = "application/pdf";
	Response.AddHeader("content-disposition", "attachment; filename=" + $"{fileNameWithoutExt}.pdf");
	var fileSize = waterStream.Length;
	byte[] pdfBuffer = new byte[(int)fileSize];
	waterStream.Read(pdfBuffer, 0, (int)fileSize);
	waterStream.Close();
	Response.BinaryWrite(pdfBuffer);
	Response.End();
}

產出的結果如下,

  • 註:使用 TextState 時 (var defaultTextState = new TextState(“MingLiU”, 8);),不能直接輸入中文的字型名稱,要到機碼「HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\fonts」去找出對應的名稱哦!
    例如: MingLiU。不然會出現 FontNotFoundException,如下,
    ‘Aspose.Pdf.Text.FontRepository.FindFont(“新細明體”)’ 擲回 ‘Aspose.Pdf.FontNotFoundException’ 類型的例外狀況

而且機碼的名稱,目前是區分大小寫的哦!


// 中文字型名稱 ,或是機碼中的名稱大小寫不對,都會錯誤
var textStateFromFontCName = new TextState("標楷體", 8);
var textStateFromFontEName= new TextState("DFKai-sb", 8);

// 機碼中是 DFKai-SB
var textStateFromFontEName= new TextState("DFKai-SB", 8);

 

作者: 亂馬客

亂馬客 @叡揚資訊 rainmaker_ho@gss.com.tw https://rainmakerho.github.io/ https://www.slideshare.net/rainmakerho

發表迴響