C#利用Spire.Pdf包實現(xiàn)為PDF添加數(shù)字簽名
背景
- 對PDF文檔進行數(shù)字簽名的需求
- 對PDF文檔添加水印的需求
- 網(wǎng)上資料版本不一或不全
本文章提到的Spire.Pdf均是使用的Spire.Pdf for .NET,除此之前還有其他語言的版本,如Spire.Pdf for JAVA;
Spire.Pdf主要用于操作PDF,另外還有Spire.Excel、Spire.Doc等
主要介紹了在C#中使用Spire.Pdf組件包對PDF文檔進行數(shù)字簽名、添加水印功能,旨在引導(dǎo)大家快速、輕松的對PDF文檔進行數(shù)字簽名和添加水印功能;
簡介
Spire.PDF for .NET 是一款專業(yè)的基于.NET平臺的PDF文檔控制組件。它能夠讓開發(fā)人員在不使用Adobe Acrobat和其他外部控件的情況下,運用.NET 應(yīng)用程序創(chuàng)建,閱讀,編寫和操縱PDF 文檔。Spire.PDF for .NET 功能豐富,除了基本的功能比如:繪制多種圖形,圖片,創(chuàng)建窗體字段,插入頁眉頁腳,輸入數(shù)據(jù)表,自動對大型表格進行分頁外,Spire.PDF for .NET還支持PDF數(shù)字簽名,將HTML轉(zhuǎn)換成PDF格式,提取PDF文檔中的文本信息和圖片等,目前Spire.PDF for .NET共有兩個版本,一個是免費版本一個是付費版本,免費版本如果只是處理簡單的pdf是沒問題的,但是如果涉及到輸出為pdf則會只顯示前10頁,第十一頁則是預(yù)定的購買頁介紹,我這里主要是對PDF文檔的數(shù)字簽名和水印,所以不涉及輸出pdf;
依賴
本文示例代碼依賴于Spire.Pdf,可以在項目中使用NuGet程序包引入。
源碼
核心代碼
public class DigitalSignature { /// <summary> /// 頁頂部紅色警告字樣覆蓋白色圖片Base64. /// </summary> private const string WatermarkCoverBase64 = "/9j/4AAQSkZJRgABAQEAYABgAAD/2wBDAAMCAgMCAgMDAwMEAwMEBQgFBQQEBQoHBwYIDAoMDAsKCwsNDhIQDQ4RDgsLEBYQERMUFRUVDA8XGBYUGBIUFRT/2wBDAQMEBAUEBQkFBQkUDQsNFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBT/wAARCABHAycDASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD9U6KKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooA//Z"; /// <summary> /// 構(gòu)造函數(shù). /// </summary> /// <param name="waitSignFile">待簽名文件.</param> /// <param name="imageSign">簽名圖片.</param> /// <param name="pfx">簽名證書.</param> /// <param name="pfxPwd">簽名證書密碼.</param> public DigitalSignature(byte[] waitSignFile, byte[] imageSign, byte[] pfx, string pfxPwd) { this.WaitSignFile = waitSignFile; this.ImageSign = imageSign; this.Pfx = pfx; this.PfxPwd = pfxPwd; } /// <summary> /// 構(gòu)造函數(shù). /// </summary> /// <param name="waitSignFile">待簽名文件.</param> /// <param name="charactersSign">簽名文字.</param> /// <param name="signRightLeftWidth">簽名右向左寬度.</param> /// <param name="signBottomUpHeight">簽名低向上高度.</param> /// <param name="pfx">簽名證書.</param> /// <param name="pfxPwd">簽名證書密碼.</param> public DigitalSignature(byte[] waitSignFile, string charactersSign, float signRightLeftWidth, float signBottomUpHeight, byte[] pfx, string pfxPwd) { this.WaitSignFile = waitSignFile; this.CharactersSign = charactersSign; this.SignRightLeftWidth = signRightLeftWidth; this.SignBottomUpHeight = signBottomUpHeight; this.Pfx = pfx; this.PfxPwd = pfxPwd; } /// <summary> /// 構(gòu)造函數(shù). /// </summary> /// <param name="waitSignFile">待簽名文件.</param> /// <param name="imageSign">簽名圖片.</param> /// <param name="charactersSign">簽名文字.</param> /// <param name="pfx">簽名證書.</param> /// <param name="pfxPwd">簽名證書密碼.</param> public DigitalSignature(byte[] waitSignFile, byte[] imageSign, string charactersSign, byte[] pfx, string pfxPwd) { this.WaitSignFile = waitSignFile; this.ImageSign = imageSign; this.CharactersSign = charactersSign; this.Pfx = pfx; this.PfxPwd = pfxPwd; } /// <summary> /// Gets or sets 待簽名文件. /// </summary> public byte[] WaitSignFile { get; set; } /// <summary> /// Gets or sets 圖簽名. /// </summary> public byte[] ImageSign { get; set; } /// <summary> /// Gets or sets 文字簽名. /// </summary> public string CharactersSign { get; set; } /// <summary> /// Gets or sets 簽名右向左的寬度. /// </summary> public float? SignRightLeftWidth { get; set; } /// <summary> /// Gets or sets 簽名頂向上高度. /// </summary> public float? SignBottomUpHeight { get; set; } /// <summary> /// Gets or sets 簽名索引頁面(不指定默認所有頁進行簽名). /// </summary> public int? SignIndexPages { get; set; } /// <summary> /// Gets or sets Pfx證書. /// </summary> public byte[] Pfx { get; set; } /// <summary> /// Gets or sets Pfx證書密碼. /// </summary> public string PfxPwd { get; set; } public Stream Signature() { ///加載PDF文檔 PdfDocument pdf = new PdfDocument(); pdf.LoadFromBytes(this.WaitSignFile); if (pdf?.Pages?.Count <= 0) { throw new Exception("文件有誤"); } X509Certificate2 x509 = new X509Certificate2(this.Pfx, this.PfxPwd); PdfOrdinarySignatureMaker signatureMaker = new PdfOrdinarySignatureMaker(pdf, x509); var appearance = new PdfCustomSignatureAppearance(this.CharactersSign, this.ImageSign, this.SignRightLeftWidth, this.SignBottomUpHeight); IPdfSignatureAppearance signatureAppearance = appearance; // 繪畫白底圖片 PdfRubberStampAnnotation logoStamp = new PdfRubberStampAnnotation(new RectangleF(new PointF(0, 0), new SizeF(350, 22))); PdfAppearance logoApprearance = new PdfAppearance(logoStamp); //var logoPath = AppDomain.CurrentDomain.BaseDirectory + "\\white.jpg"; byte[] byt = Convert.FromBase64String(WatermarkCoverBase64); Stream streamByLogo = new MemoryStream(byt); PdfImage image = PdfImage.FromStream(streamByLogo); PdfTemplate template = new PdfTemplate(350, 22); template.Graphics.DrawImage(image, 0, 0); logoApprearance.Normal = template; logoStamp.Appearance = logoApprearance; if (this.SignIndexPages.HasValue) { if (this.SignIndexPages.Value < 0 || this.SignIndexPages.Value > pdf?.Pages?.Count) { throw new Exception("簽名索引頁有誤"); } var page = pdf.Pages[this.SignIndexPages.Value]; // 添加白底圖片覆蓋頁面頂部印記 page.AnnotationsWidget.Add(logoStamp); // 在頁面中的指定位置添加可視化簽名 signatureMaker.MakeSignature("signName_", page, page.ActualSize.Width - appearance.SignRightLeftWidth, page.ActualSize.Height - appearance.SignBottomUpHeight, appearance.SignRightLeftWidth, appearance.SignBottomUpHeight, signatureAppearance); } else { foreach (PdfPageBase page in pdf.Pages) { // 添加白底圖片覆蓋頁面頂部印記 page.AnnotationsWidget.Add(logoStamp); // 在頁面中的指定位置添加可視化簽名 signatureMaker.MakeSignature("signName_", page, page.ActualSize.Width - appearance.SignRightLeftWidth, page.ActualSize.Height - appearance.SignBottomUpHeight, appearance.SignRightLeftWidth, appearance.SignBottomUpHeight, signatureAppearance); } } MemoryStream stream = new MemoryStream(); pdf.SaveToStream(stream, FileFormat.PDF); pdf.Close(); return stream; } /// <summary> /// 使用第三方插件 =》 去除 Evaluation Warning : The document was created with Spire.PDF for .NET. /// </summary> /// <param name="sourcePdfs">原文件地址</param> //private static MemoryStream ClearPdfFilesFirstPage(MemoryStream sourcePdf) //{ // iTextSharp.text.pdf.PdfReader reader = null; // iTextSharp.text.Document document = new iTextSharp.text.Document(); // iTextSharp.text.pdf.PdfImportedPage page = null; // iTextSharp.text.pdf.PdfCopy pdfCpy = null; // int n = 0; // reader = new iTextSharp.text.pdf.PdfReader(sourcePdf); // reader.ConsolidateNamedDestinations(); // n = reader.NumberOfPages; // document = new iTextSharp.text.Document(reader.GetPageSizeWithRotation(1)); // MemoryStream memoryStream = new MemoryStream(); // pdfCpy = new iTextSharp.text.pdf.PdfCopy(document, memoryStream); // document.Open(); // for (int j = 2; j <= n; j++) // { // page = pdfCpy.GetImportedPage(reader, j); // pdfCpy.AddPage(page); // } // reader.Close(); // document.Close(); // return memoryStream; //} } public class PdfCustomSignatureAppearance : IPdfSignatureAppearance { public PdfCustomSignatureAppearance(string charactersSign, byte[] sign, float? signRightLeftWidth, float? signBottomUpHeight) { this.CharactersSign = charactersSign; if (sign != null && sign.Length > 0) { this.Sign = sign; MemoryStream ms = new MemoryStream(sign); var image = System.Drawing.Image.FromStream(ms); if (!signRightLeftWidth.HasValue) { signRightLeftWidth = image.Width; } if (!signBottomUpHeight.HasValue) { signBottomUpHeight = image.Height; } } this.SignRightLeftWidth = signRightLeftWidth.Value; this.SignBottomUpHeight = signBottomUpHeight.Value; } /// <summary> /// Gets or sets 簽名. /// </summary> public byte[] Sign { get; set; } /// <summary> /// Gets or sets 簽名右向左的寬度. /// </summary> public float SignRightLeftWidth { get; set; } /// <summary> /// Gets or sets 簽名頂向上高度. /// </summary> public float SignBottomUpHeight { get; set; } /// <summary> /// Gets or sets 文字簽名. /// </summary> public string CharactersSign { get; set; } public void Generate(PdfCanvas g) { if (!string.IsNullOrWhiteSpace(CharactersSign)) { float fontSize = 15; var font = new System.Drawing.Font("Arial", fontSize); PdfTrueTypeFont fontByPdf = new PdfTrueTypeFont(font, true); g.DrawString(CharactersSign, fontByPdf, PdfBrushes.Black, new PointF(0, 0)); } if (this.Sign != null && this.Sign.Length > 0) { Stream stream = new MemoryStream(this.Sign); g.DrawImage(Spire.Pdf.Graphics.PdfImage.FromStream(stream), new PointF(20, 20)); } } }
調(diào)用實現(xiàn)
static void Main(string[] args) { /* 前言:最近有個需求是需要對文檔進行數(shù)字簽名; 描述:本示例基于Spire.Pdf組件對PDF進行數(shù)字簽名,演示了 簽名證書使用項目 CreateSelfSignedCertificateByBouncyCastle(https://github.com/daileass/CreateSelfSignedCertificateByBouncyCastle.git) 生成的自簽名證書pfx,解決了數(shù)字簽名后文檔頭部有警告 */ var fileCert = System.Environment.CurrentDirectory + "\\Cert\\"; var file = System.Environment.CurrentDirectory + "\\File\\"; var filePath = file + "dome.pdf"; var newFilePath = file + $"dome_{DateTime.Now.ToString("yyyyMMddHHmmss")}.pdf"; var pfxFilePath = fileCert + "edd9386229324d969692dcabf97ac095dpps.fun.pfx"; var pfxFilePwd = "ABCD123456"; var signFilePath = file + "sign.png"; // 數(shù)字簽名 var digitalSignature = new DigitalSignature( File2Bytes(filePath), File2Bytes(signFilePath), "Sign Here:", File2Bytes(pfxFilePath), pfxFilePwd ); var stream = digitalSignature.Signature(); // 保存簽名后的文件 using (var fileStream = File.Create(newFilePath)) { stream.Seek(0, SeekOrigin.Begin); stream.CopyTo(fileStream); } Console.WriteLine("OK"); Console.ReadLine(); } /// <summary> /// 將文件轉(zhuǎn)換為byte數(shù)組 /// </summary> /// <param name="path">文件地址</param> /// <returns>轉(zhuǎn)換后的byte數(shù)組</returns> public static byte[] File2Bytes(string path) { if (!System.IO.File.Exists(path)) { return new byte[0]; } FileInfo fi = new FileInfo(path); byte[] buff = new byte[fi.Length]; FileStream fs = fi.OpenRead(); fs.Read(buff, 0, Convert.ToInt32(fs.Length)); fs.Close(); return buff; }
源碼下載:https://github.com/daileass/PDFDigitalSignatureBySelfSignedCertificate
到此這篇關(guān)于C#利用Spire.Pdf包實現(xiàn)為PDF添加數(shù)字簽名的文章就介紹到這了,更多相關(guān)C# PDF添加數(shù)字簽名內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
c#打印預(yù)覽控件中實現(xiàn)用鼠標(biāo)移動頁面功能代碼分享
項目中需要實現(xiàn)以下功能:打印預(yù)覽控件中,可以用鼠標(biāo)拖動頁面,以查看超出顯示范圍之外的部分內(nèi)容,下面就是實現(xiàn)代碼2013-12-12C#抓取網(wǎng)頁數(shù)據(jù) 解析標(biāo)題描述圖片等信息 去除HTML標(biāo)簽
本文主要一步一步介紹利用C#抓取頁面數(shù)據(jù)的過程,抓取HTML,獲取標(biāo)題、描述、圖片等信息,并去除HTML,希望對大家有所幫助。2016-04-04C#實現(xiàn)遠程連接ORACLE數(shù)據(jù)庫的方法
這篇文章主要介紹了C#實現(xiàn)遠程連接ORACLE數(shù)據(jù)庫的方法,通過自定義函數(shù)db_connection_test實現(xiàn)遠程連接Oracle數(shù)據(jù)庫的功能,是非常實用的技巧,需要的朋友可以參考下2014-12-12c# Bitmap轉(zhuǎn)bitmapImage高效方法
本文主要介紹了c# Bitmap轉(zhuǎn)bitmapImage高效方法,文中通過示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下2021-11-11