使用iTextsharp實作PDF檔

iTextsharp 今天要介紹一個製作表格的原件iTextsharp,iTextsharp是一個可用來建立、編輯PDF的元件,可以輕鬆將資料自訂在文件的任何位置,且製作表格時可設定分割或合併每一格縱橫行分配比例,並且自訂表格內的文字大小,可說是非常方便。

簡單介紹iTextsharp

iTextsharp是由iText而來,原先僅支援Java語言,之後也針對C Sharp推出另一個版本,目前免費版本僅推行到5.5.13.2版,之後為付費版的iText 7,而我們本次示範免費版的功能。

 

安裝iTextsharp

我們只需要到管理NuGet套件的地方搜尋iTextsharp即可找到5.5.13.2的版本。

iTextsharp

 

實作於電子發票表單

我們以財政部提供的電子發票證明聯格式二當作範例:

iTextsharp

一開始先加入以下程式碼

Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);

行程式碼用意為,將套件中的其他編碼註冊到 Encoding 中,CodePagesEncodingProvider 以 Singleton 方式提供 Provider 減少註冊複雜性。

 

接著設定紙張的大小,A4以72dpi大約是593*842,根據不同dpi也可以設定其他數值

Rectangle pageSize = new Rectangle(593, 842);
Document PdfDoc = new Document();
PdfDoc = new Document(pageSize, 0, 0, 0, 0);

 

接著設定要產生pdf的位置,file為包含檔案名稱的完整路徑

PdfWriter PdfDocWriter = PdfWriter.GetInstance(PdfDoc, new FileStream(file, FileMode.Create));

 

接著設定字型,會用到兩種字體大小,所以就直接宣告兩個,這邊的mingliu.ttc,1為新細明體,如要使用標楷體則改為kaiu.ttf即可。

string fontPath = @"C:\Windows\Fonts\mingliu.ttc,1";
BaseFont bfont = BaseFont.CreateFont(fontPath, BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);
Font text1 = new Font(bfont, 10f);
Font text2 = new Font(bfont, 18f);
PdfDoc.Open();
PdfContentByte PdfCB = PdfDocWriter.DirectContent;

到這邊大致上已完成基本設定的部分,接著便可開始編輯pdf的內容。

PdfDoc.Open();
PdfContentByte PdfCB = PdfDocWriter.DirectContent;

iTextsharp

 

首先來做上半區非表格的部分

Phrase phrase1 = new Phrase("詮力科技股份有限公司", text2);
ColumnText.ShowTextAligned(PdfCB, Element.ALIGN_CENTER, phrase1, 296f, 821f, 0f);

Element.ALIGN_CENTER表示置中,另外有靠左Element.ALIGN_LEFT跟靠右Element.ALIGN_RIGHT,要注意的是置中的話文字是由中間往左右延伸,靠左則是由左向右,靠右反之;後面三個數字分別為x座標、y座標以及文字旋轉角度rotation,這樣便完成了第一行字。

iTextsharp

接這繼續完成其他部分,資料來源可自行從外部傳入(此處先以固定資料當做範例)

 

Phrase phrase2 = new Phrase($"電子發票證明聯", text2);
ColumnText.ShowTextAligned(PdfCB, Element.ALIGN_CENTER, phrase2, 296f, 801f, 0f);

string date = DateTime.Now.ToString("yyyy-MM-dd");
string dateInfo = $"{date}";
Phrase phrase3 = new Phrase(dateInfo, text1);
ColumnText.ShowTextAligned(PdfCB, Element.ALIGN_CENTER, phrase3, 296f, 781f, 0f);

string strInvoiceNumber = $"發票號碼:DU77988106 ";
Phrase phrase4 = new Phrase(strInvoiceNumber, text1);
ColumnText.ShowTextAligned(PdfCB, Element.ALIGN_LEFT, phrase4, 30f, 771f, 0f);

Phrase phrase5 = new Phrase("格 式:25", text1);
ColumnText.ShowTextAligned(PdfCB, Element.ALIGN_LEFT, phrase5, 405f, 771f, 0f);

Phrase phrase6 = new Phrase($"買  方:買方公司名稱", text1);
<ColumnText.ShowTextAligned(PdfCB, Element.ALIGN_LEFT, phrase6, 30f, 761f, 0f);/code>

Phrase phrase7 = new Phrase($"隨機碼:1234", text1);
ColumnText.ShowTextAligned(PdfCB, Element.ALIGN_LEFT, phrase7, 405f, 761f, 0f);

Phrase phrase8 = new Phrase($"統一編號:12345678", text1);
ColumnText.ShowTextAligned(PdfCB, Element.ALIGN_LEFT, phrase8, 30f, 751f, 0f);

Phrase phrase9 = new Phrase($"地  址: 台北市南港區忠孝東路六段1號", text1);
ColumnText.ShowTextAligned(PdfCB, Element.ALIGN_LEFT, phrase9, 30f, 741f, 0f);

iTextsharp

這樣便完成上半部的文字部分。

 

接著說明表格的部分,首先宣告表格,下圖中先找到最多格的一行,一共有9格,因此在宣告時的陣列就是9個數,並依照格子大小比例調整數字,如圖所示比例約為2:1:1:1:1:1:2:4:6

PdfPTable table = new PdfPTable(new float[] { 2, 1, 1, 1, 1, 1, 2, 4, 6 });

iTextsharp

 

宣告PdfPCell,第一橫行有五格,所以直接宣告5個PdfPCell之後再依序AddCell,由於我們一開始宣告PdfPTable時宣告了9格,而這邊第一橫行只有5格,所以要設定Colspan決定每一格要占用幾個column,如果是要垂直跨列的話則使用Rowspan,Colspan與Rowspan若沒有特別設定的話則會默認為1,另外要注意的是在AddCell的時候必須照順序,由左至右到同一橫行的Colspan總計為初始宣告的數量(這邊範例是9)後才會換到下一row。

PdfPCell header1 = new PdfPCell(new Phrase("品名", text1));
header1.Colspan = 3;
header1.HorizontalAlignment = Element.ALIGN_CENTER;
PdfPCell header2 = new PdfPCell(new Phrase("數量", text1));
header2.Colspan = 2;
header2.HorizontalAlignment = Element.ALIGN_CENTER;
PdfPCell header3 = new PdfPCell(new Phrase("單價", text1));
header3.Colspan = 2;
header3.HorizontalAlignment = Element.ALIGN_CENTER;
PdfPCell header4 = new PdfPCell(new Phrase("金額", text1));
header4.HorizontalAlignment = Element.ALIGN_CENTER;
PdfPCell header5 = new PdfPCell(new Phrase("備註", text1));
header5.HorizontalAlignment = Element.ALIGN_CENTER;

table.AddCell(header1);
table.AddCell(header2);
table.AddCell(header3);
table.AddCell(header4);
table.AddCell(header5);

 

接下來為項目內容的部分,這邊我們宣告一個變數來使欄位高度固定,ProductItem.Count為產品項目總數,產品都填完後再補\r\n來補足row

int A4varRow = 40;
int secondRowlenth = A4varRow - ProductItem.Count;

string PdsDescription = "";
foreach (var item in ProductItem)
{
PdsDescription += $"{item.Description}\r\n";
}
for (int i = 0; i < secondRowlenth; i++)
{
PdsDescription += $"\r\n";
}
PdfPCell ProductsDescription = new PdfPCell(new Phrase(PdsDescription, text1));
ProductsDescription.Colspan = 3;
ProductsDescription.HorizontalAlignment = Element.ALIGN_LEFT;
table.AddCell(ProductsDescription);

string PdsQuantity = "";
foreach (var item in ProductItem)
{
PdsQuantity += $"{item.Quantity.ToString("f0")}\r\n";
}
for (int i = 0; i < secondRowlenth; i++)
{
PdsQuantity += $"\r\n";
}

PdfPCell ProductsQuantity = new PdfPCell(new Phrase(PdsQuantity, text1));
ProductsQuantity.Colspan = 2;
ProductsQuantity.HorizontalAlignment = Element.ALIGN_RIGHT;
table.AddCell(ProductsQuantity);

string PdsUnitPrice = "";
foreach (var item in ProductItem)
{
PdsUnitPrice += $"{item.UnitPrice.ToString("f4")}\r\n";
}
for (int i = 0; i < secondRowlenth; i++)
{
PdsUnitPrice += $"\r\n";
}

PdfPCell ProductsUnitPrice = new PdfPCell(new Phrase(PdsUnitPrice, text1));
ProductsUnitPrice.Colspan = 2;
ProductsUnitPrice.HorizontalAlignment = Element.ALIGN_RIGHT;
table.AddCell(ProductsUnitPrice);

string PdsAmount = "";
foreach (var item in ProductItem)
{
PdsAmount += $"{item.Amount.ToString("N0")}\r\n";
}
for (int i = 0; i < secondRowlenth; i++)
{
PdsAmount += $"\r\n";
}

PdfPCell ProductsAmount = new PdfPCell(new Phrase(PdsAmount, text1));
ProductsAmount.HorizontalAlignment = Element.ALIGN_RIGHT;
table.AddCell(ProductsAmount);

string PdsRemark = "";
foreach (var item in ProductItem)
{
PdsRemark += $"{item.Remark}\r\n";
}
for (int i = 0; i < secondRowlenth; i++)
{
PdsRemark += $"\r\n";
}

PdfPCell ProductsRemark = new PdfPCell(new Phrase(PdsRemark, text1));
ProductsRemark.HorizontalAlignment = Element.ALIGN_LEFT;
table.AddCell(ProductsRemark);
.
.
.
(下略)

其餘的資料都填寫完之後,設定table的總寬度,再決定table起始位置
WriteSelectedRows(int rowStart, int rowEnd, float xPos, float yPos, PdfContentByte canvas);
即可完成table製作。

.
.
.
table.TotalWidth = 530f;
table.LockedWidth = true;
table.WriteSelectedRows(0, -1, 30f, 721f, PdfCB);

 

完成後如下圖

iTextsharp

另外,如果需要在一個pdf中開新頁,則使用PdfDoc.NewPage();即可。

 

Reference

1. https://einvoice.nat.gov.tw/
2. https://itextpdf.com/en/products/itextsharp
3. https://blog.csdn.net/hj7jay/article/details/82023361
4. https://www.cc.ntu.edu.tw/chinese/epaper/0015/20101220_1509.htm
5. http://limitedcode.blogspot.com/2017/06/net-core-big5.html

Comments

No comments yet. Why don’t you start the discussion?

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *

這個網站採用 Akismet 服務減少垃圾留言。進一步了解 Akismet 如何處理網站訪客的留言資料