PDFsharp 6.2 中文操作練習
試著用 PDFsharp 開啟現有 PDF 檔用憑證簽署。
引言
主要問題 - 版本
主要問題 - 中文字型
開發環境
關鍵程式碼紀錄 - 支援中文字型
關鍵程式碼紀錄 - 用憑證簽署
完整原始碼
參考文件
Last updated
試著用 PDFsharp 開啟現有 PDF 檔用憑證簽署。
Last updated
using PdfSharp.Fonts;
using System.Drawing.Text;
using System.Runtime.CompilerServices;
namespace PDFSharpLab_HelloWorld2;
public class CustomFontResolver : IFontResolver
{
//DirectoryInfo fontsFolder = new DirectoryInfo(Environment.GetFolderPath(Environment.SpecialFolder.Fonts)); // 取得字型資料夾路徑
readonly DirectoryInfo _fontsFolder = new DirectoryInfo(@"assets\pdfsharp-6.x\fonts"); // 取得字型資源路徑
public byte[]? GetFont(string faceName)
{
// Note: PDFsharp never calls GetFont twice with the same face name.
// Note: If a typeface is resolved by the PlatformFontResolver.ResolveTypeface
// you never come here.
string fontFileName = faceName;
//※ PDFsharp 只支援 TrueType 字型(.ttf)。
foreach (var fontFolder in _fontsFolder.GetDirectories())
{
foreach (FileInfo file in fontFolder.GetFiles("*.ttf"))
{
if(file.Name == fontFileName)
{
return File.ReadAllBytes(file.FullName);
}
}
}
throw new FileNotFoundException($"字型檔案 {fontFileName} 未找到!");
}
public FontResolverInfo? ResolveTypeface(string familyName, bool bold, bool italic)
{
//※ PDFsharp 只支援 TrueType 字型(.ttf)。
foreach (var fontFolder in _fontsFolder.GetDirectories())
{
foreach (FileInfo file in fontFolder.GetFiles("*.ttf"))
{
var pfc = new PrivateFontCollection();
pfc.AddFontFile(file.FullName);
if (pfc.Families.Length > 0)
{
foreach (var family in pfc.Families)
{
if (family.Name == familyName)
{
return new FontResolverInfo(file.Name, bold, italic); // 此處 faceName 等於字型檔案名稱。
}
}
}
}
}
// Alternatively forward call to PlatformFontResolver.
return PlatformFontResolver.ResolveTypeface(familyName, bold, italic);
//// 回傳 null 表示不支援該字型。
//return null;
}
}// 註冊自訂字型解析器
GlobalFontSettings.FontResolver = new CustomFontResolver();
GlobalFontSettings.UseWindowsFontsUnderWindows = true;
// 使用註冊過的微軟正黑體字型
XFont font = new XFont("微軟正黑體", 20);
// 建立 PDF 文件
using PdfDocument document = new PdfDocument();
document.Info.Title = "PDFsharp 中文練習";
document.Info.Subject = "PDFsharp 中文練習主旨";
PdfPage page = document.AddPage();
XGraphics gfx = XGraphics.FromPdfPage(page);
XFont fontJhengHei = new XFont("微軟正黑體", 36);
gfx.DrawString($"這是微軟正黑體 36", fontJhengHei, XBrushes.Black, 10, 60);
XFont fontKaiu = new XFont("標楷體", 36);
gfx.DrawString($"這是標楷體 36", fontKaiu, XBrushes.Black, 10, 100);
XFont fontArial = new XFont("Arial", 36);
gfx.DrawString($"This is Arial font 36", fontArial, XBrushes.Black, 10, 140);using PdfSharp.Drawing;
using PdfSharp.Drawing.Layout;
using PdfSharp.Pdf.Annotations;
namespace PDFSharpLab_HelloWorld2;
class SignatureAppearanceHandler : IAnnotationAppearanceHandler
{
private string _signatureText = "簽名";
public SignatureAppearanceHandler(string signatureText)
{
_signatureText = signatureText;
}
public void DrawAppearance(XGraphics gfx, XRect rect)
{
DirectoryInfo imageFolder = new DirectoryInfo(@"assets/pdfsharp-6.x/signatures"); // 取得字型資源路徑
var image = XImage.FromFile(Path.Combine(imageFolder.FullName, "JohnDoe.png"));
//string text = "John Doe\nSeattle, " + DateTime.Now.ToString(CultureInfo.GetCultureInfo("EN-US"));
string text = $"{_signatureText}, {DateTime.Now:F}";
//var font = new XFont("Verdana", 7.0, XFontStyleEx.Regular);
var font = new XFont("標楷體", 8.0, XFontStyleEx.Regular);
var textFormatter = new XTextFormatter(gfx);
double num = (double)image.PixelWidth / image.PixelHeight;
double signatureHeight = rect.Height * .4;
var point = new XPoint(rect.Width / 10, rect.Height / 10);
// Draw image.
gfx.DrawImage(image, point.X, point.Y, signatureHeight * num, signatureHeight);
// Adjust position for text. We draw it below image.
point = new XPoint(point.X, rect.Height / 2d);
//textFormatter.DrawString(text, font, new XSolidBrush(XColor.FromKnownColor(XKnownColor.Black)), new XRect(point.X, point.Y, rect.Width, rect.Height - point.Y), XStringFormats.TopLeft);
textFormatter.DrawString(text, font, XBrushes.Black, new XRect(point.X, point.Y, rect.Width, rect.Height - point.Y), XStringFormats.TopLeft);
}
}
//§ 開啟現有的 PDF 文件並嘗試簽章
using PdfDocument document2 = PdfReader.Open(filename, PdfDocumentOpenMode.Modify);
int lastPageIndex = document2.Pages.Count - 1;
PdfPage lastPage = document2.Pages[lastPageIndex];
XGraphics lastGfx = XGraphics.FromPdfPage(lastPage);
//## 試著簽章
var signPosition = lastGfx.Transformer.WorldToDefaultPage(new XPoint(144, 600));
var pdfSignatureHandler = DigitalSignatureHandler.ForDocument(document2,
new PdfSharpDefaultSigner(GetCertificate(), PdfMessageDigestType.SHA256),
new DigitalSignatureOptions
{
ContactInfo = "Sky-Walker Kao",
Location = "新北市",
Reason = "測試 PDF 簽章",
Rectangle = new XRect(signPosition.X, signPosition.Y, 200, 50), // 簽章位置
AppearanceHandler = new SignatureAppearanceHandler("高天賜2\n新北市"),
PageIndex = lastPageIndex
});
string filename2 = "output2.pdf";
document2.Save(filename2);
document2.Close();
Console.WriteLine($"簽章 PDF 已儲存為 {filename2}");
/// 取簽署憑證
static X509Certificate2 GetCertificate()
{
DirectoryInfo certFolder = new DirectoryInfo(@"assets/pdfsharp-6.x/signatures"); // 取得字型資源路徑
var pfxFile = Path.Combine(certFolder.FullName , "test-cert_rsa_1024.pfx");
var rawData = File.ReadAllBytes(pfxFile);
// This code is for demonstration only. Do not use password literals for real certificates in source code.
var certificatePassword = "Seecrit1243";
var certificate = new X509Certificate2(rawData,
certificatePassword,
X509KeyStorageFlags.MachineKeySet | X509KeyStorageFlags.PersistKeySet | X509KeyStorageFlags.Exportable);
return certificate;
}