切換語言為:簡體

透過 .NET 實現 pdf 檔案自動蓋章(電子簽章)

  • 爱糖宝
  • 2024-06-08
  • 2084
  • 0
  • 0

序言

在數字化時代,電子文件的安全性和真實性越來越受到重視。電子印章作為一種數字化的身份驗證工具,已經成為確保文件合法性和不可篡改性的重要手段。然而,傳統的電子印章往往需要人工操作,不僅效率低下,而且在處理大量檔案時容易出錯。爲了解決這一問題,自動化地給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"//文字素材的表示式,也可以直接寫固定文字
  }
]


說明:

  1. 這裏之所以設計為一個數組,是因為可能有些場景下,不僅需要蓋電子章,還需要自動簽上日期,比如本案例。

  2. 簽署位置可以自定義,座標(0,0)代表的是左下角,x 變大即表示橫向右移,y 變大表示縱向上移。

  3. 配置檔案儲存,我這裏是把配置檔案放在了本地,當然你可以儲存在任何地方,比如 MongoDB等。

程式碼展示

本案例採用的是 .net7.0,當然 .net6及以後都是可以的。

  1. 配置檔案類,與上一步的 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);
}


  1. 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);
    }
}


  1. 測試呼叫

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);
}


  1. 效果展示
    原 pdf 檔案如下圖: 透過 .NET 實現 pdf 檔案自動蓋章(電子簽章) 最終效果如下圖: 透過 .NET 實現 pdf 檔案自動蓋章(電子簽章)

結束語

隨著本文的深入探討,我們共同經歷了一個完整的旅程,從理解電子印章的重要性到實現一個自動化的.NET程式,用於在PDF檔案上高效、準確地加蓋電子章。我們不僅學習了.NET環境下處理PDF檔案的技術細節,還掌握瞭如何將電子印章整合到我們的應用程式中,以實現自動化的文件認證過程。

0則評論

您的電子郵件等資訊不會被公開,以下所有項目均必填

OK! You can skip this field.