序言
在數字化時代,電子文件的安全性和真實性越來越受到重視。電子印章作為一種數字化的身份驗證工具,已經成為確保文件合法性和不可篡改性的重要手段。然而,傳統的電子印章往往需要人工操作,不僅效率低下,而且在處理大量檔案時容易出錯。爲了解決這一問題,自動化地給PDF檔案蓋電子章成爲了一個迫切的需求。本文將詳細介紹,如何透過 .net 程式實現這一功能,廢話不多說,步入正題
Nuget 包
本文的核心包為:
iTextSharp,用它來操作 pdf 檔案非常方便,具體的用法這裏不多贅述,請參考官網
DynamicExpresso,一個非常好用的動態表示式解析工具包
<ItemGroup> <PackageReference Include="DynamicExpresso.Core" Version="2.16.1" /> <PackageReference Include="iTextSharp" Version="5.5.13.3" /> <PackageReference Include="Newtonsoft.Json" Version="13.0.3" /> </ItemGroup>
素材準備
本案例用到的素材包括:用於測試的 pdf 檔案一個,類比電子章圖片一張,以及蓋章配置檔案,檔案內容如下:
[ { "SignType" : "image",//素材型別,image表示圖片素材,text 表示文字素材 "LastPage" : true,//是否僅最後一頁蓋章 "ImageUrl" : "https://xxxxxxxx",//圖片素材的下載連結 "FileName" : "sign.png",//圖片素材檔名稱 "ScalePercent" : 20,//圖片縮放百分比,100 表示不縮放 "Opacity" : 0.6,//圖片透明度,1 表示不透明 "LocationX" : "(input.Width/10)*6",//圖片素材的絕對位置表示式,(0,0) 表示左下角 "LocationY" : "input.Height/23 +20",//input.With 和 input.Height 代表 pdf 檔案的寬度及高度 "Rotation" : 0//素材的旋轉角度 }, { "SignType" : "text", "LastPage" : true, "LocationX" : "(input.Width/10)*6+85", "LocationY" : "input.Height/23 ", "Rotation" : 0, "FontSize" : 20, "Opacity" : 0.6, "FontColor" : {//文字素材的字型顏色值 "R" : 255, "G" : 0, "B" : 0 }, "Text" : "input.Date"//文字素材的表示式,也可以直接寫固定文字 } ]
說明:
這裏之所以設計為一個數組,是因為可能有些場景下,不僅需要蓋電子章,還需要自動簽上日期,比如本案例。
簽署位置可以自定義,座標(0,0)代表的是左下角,x 變大即表示橫向右移,y 變大表示縱向上移。
配置檔案儲存,我這裏是把配置檔案放在了本地,當然你可以儲存在任何地方,比如 MongoDB等。
程式碼展示
本案例採用的是 .net7.0,當然 .net6及以後都是可以的。
配置檔案類,與上一步的 json 配置檔案對應
namespace PdfSign; public class SignOpt { public string SignType { get; set; } public bool LastPage { get; set; } public string ImageUrl { get; set; } public string FileName { get; set; } public int ScalePercent { get; set; } = 50; public string LocationX { get; set; } public string LocationY { get; set; } public float LocationYf { get; set; } public float Rotation { get; set; } = 0; public int FontSize { get; set; } public float Opacity { get; set; } public RBGColor FontColor { get; set; } public string? Text { get; set; } public record RBGColor(int R, int G, int B); }
pdf 簽署方法
using System.Dynamic; using DynamicExpresso; using iTextSharp.text; using iTextSharp.text.pdf; using Newtonsoft.Json.Linq; namespace PdfSign; public class SignService { public static string PdfSign(List<SignOpt> signOpts, string pdfName) { var beforeFileName = pdfName; //簽名之前檔名 var afterFileName = pdfName + "_sign"; //簽名之後檔名 var idx = 0; foreach (var opt in signOpts) { //建立蓋章後生成pdf var outputPdfStream = new FileStream(afterFileName + ".pdf", FileMode.Create, FileAccess.Write, FileShare.None); //讀取原有pdf var pdfReader = new PdfReader(beforeFileName + ".pdf"); var pdfStamper = new PdfStamper(pdfReader, outputPdfStream); //讀取頁數 var pdfPageSize = pdfReader.NumberOfPages; //讀取pdf檔案第一頁尺寸,得到 With 和 Height var size = pdfReader.GetPageSize(1); //透過表示式計算出簽署的絕對座標 var locationX = Eval<float>(opt.LocationX, new { size.Width, size.Height }); var locationY = Eval<float>(opt.LocationY, new { size.Width, size.Height }); if (opt.LastPage) { //蓋章在最後一頁 var pdfContentByte = pdfStamper.GetOverContent(pdfPageSize); var gs = new PdfGState { FillOpacity = opt.Opacity }; pdfContentByte.SetGState(gs); switch (opt.SignType.ToLower()) { case "image": //獲取圖片 var image = Image.GetInstance(opt.FileName); //設定圖片比例 image.ScalePercent(opt.ScalePercent); //設定圖片的絕對位置,位置偏移方向為:左到右,下到上 image.SetAbsolutePosition(locationX, locationY); //圖片新增到文件 pdfContentByte.AddImage(image); break; case "text": if (string.IsNullOrWhiteSpace(opt.Text)) continue; var font = BaseFont.CreateFont(); var text = Eval<string>(opt.Text, new { Date = DateTime.Now.ToString("yyyy-MM-dd") }); //開始寫入文字 pdfContentByte.BeginText(); pdfContentByte.SetColorFill( new BaseColor(opt.FontColor.R, opt.FontColor.G, opt.FontColor.B)); pdfContentByte.SetFontAndSize(font, opt.FontSize); pdfContentByte.SetTextMatrix(0, 0); pdfContentByte.ShowTextAligned(Element.ALIGN_CENTER, text, locationX, locationY, opt.Rotation); pdfContentByte.EndText(); break; } } pdfStamper.Close(); pdfReader.Close(); idx++; if (idx >= signOpts.Count) continue; //檔名重新賦值 beforeFileName = afterFileName; afterFileName += "_sign"; } return afterFileName + ".pdf"; } //計算動態表示式的值 public static T? Eval<T>(string expr, object context) { if (string.IsNullOrWhiteSpace(expr)) return default; var target = new Interpreter(); var input = JObject.FromObject(context); target.SetVariable("input", input.ToObject<ExpandoObject>()); return target.Eval<T>(expr); } }
測試呼叫
using Newtonsoft.Json; using PdfSign; //讀取簽名所需配置檔案 var signOpts = await GetSignOpt(); if (signOpts != null && signOpts.Any()) { //執行 pdf 檔案蓋章 var signFileName= SignService.PdfSign(signOpts, "test"); } //讀取配置檔案 static async Task<List<SignOpt>?> GetSignOpt() { var strSign = await File.ReadAllTextAsync("cfg.json"); return JsonConvert.DeserializeObject<List<SignOpt>>(strSign); }
效果展示
原 pdf 檔案如下圖: 最終效果如下圖:
結束語
隨著本文的深入探討,我們共同經歷了一個完整的旅程,從理解電子印章的重要性到實現一個自動化的.NET程式,用於在PDF檔案上高效、準確地加蓋電子章。我們不僅學習了.NET環境下處理PDF檔案的技術細節,還掌握瞭如何將電子印章整合到我們的應用程式中,以實現自動化的文件認證過程。