本文章提到的Spire.Pdf均是使用的Spire.Pdf for .NET,除此之前还有其他语言的版本,如Spire.Pdf for JAVA;
Spire.Pdf主要用于操作PDF,另外还有Spire.Excel、Spire.Doc等
主要介绍了在C#中使用Spire.Pdf组件包对PDF文档进行数字签名、添加水印功能,旨在引导大家快速、轻松的对PDF文档进行数字签名和添加水印功能;
Spire.PDF for .NET 是一款专业的基于.NET平台的PDF文档控制组件。它能够让开发人员在不使用Adobe Acrobat和其他外部控件的情况下,运用.NET 应用程序创建,阅读,编写和操纵PDF 文档。Spire.PDF for .NET 功能丰富,除了基本的功能比如:绘制多种图形,图片,创建窗体字段,插入页眉页脚,输入数据表,自动对大型表格进行分页外,Spire.PDF for .NET还支持PDF数字签名,将HTML转换成PDF格式,提取PDF文档中的文本信息和图片等,目前Spire.PDF for .NET共有两个版本,一个是免费版本一个是付费版本,免费版本如果只是处理简单的pdf是没问题的,但是如果涉及到输出为pdf则会只显示前10页,第十一页则是预定的购买页介绍,我这里主要是对PDF文档的数字签名和水印,所以不涉及输出pdf;
本文示例代码依赖于Spire.Pdf,可以在项目中使用NuGet程序包引入。
核心代码
1 public class DigitalSignature
2 {
3 ///
6 private const string WatermarkCoverBase64 = "/9j/4AAQSkZJRgABAQEAYABgAAD/2wBDAAMCAgMCAgMDAwMEAwMEBQgFBQQEBQoHBwYIDAoMDAsKCwsNDhIQDQ4RDgsLEBYQERMUFRUVDA8XGBYUGBIUFRT/2wBDAQMEBAUEBQkFBQkUDQsNFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBT/wAARCABHAycDASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD9U6KKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooA//Z";
7
8 ///
11 /// 待签名文件.
12 /// 签名图片.
13 /// 签名证书.
14 /// 签名证书密码.
15 public DigitalSignature(byte[] waitSignFile, byte[] imageSign, byte[] pfx, string pfxPwd)
16 {
17 this.WaitSignFile = waitSignFile;
18 this.ImageSign = imageSign;
19 this.Pfx = pfx;
20 this.PfxPwd = pfxPwd;
21 }
22
23 ///
26 /// 待签名文件.
27 /// 签名文字.
28 /// 签名右向左宽度.
29 /// 签名低向上高度.
30 /// 签名证书.
31 /// 签名证书密码.
32 public DigitalSignature(byte[] waitSignFile, string charactersSign, float signRightLeftWidth, float signBottomUpHeight, byte[] pfx, string pfxPwd)
33 {
34 this.WaitSignFile = waitSignFile;
35 this.CharactersSign = charactersSign;
36 this.SignRightLeftWidth = signRightLeftWidth;
37 this.SignBottomUpHeight = signBottomUpHeight;
38 this.Pfx = pfx;
39 this.PfxPwd = pfxPwd;
40 }
41
42 ///
45 /// 待签名文件.
46 /// 签名图片.
47 /// 签名文字.
48 /// 签名证书.
49 /// 签名证书密码.
50 public DigitalSignature(byte[] waitSignFile, byte[] imageSign, string charactersSign, byte[] pfx, string pfxPwd)
51 {
52 this.WaitSignFile = waitSignFile;
53 this.ImageSign = imageSign;
54 this.CharactersSign = charactersSign;
55 this.Pfx = pfx;
56 this.PfxPwd = pfxPwd;
57 }
58
59 ///
62 public byte[] WaitSignFile { get; set; }
63
64 ///
67 public byte[] ImageSign { get; set; }
68
69 ///
72 public string CharactersSign { get; set; }
73
74 ///
77 public float? SignRightLeftWidth { get; set; }
78
79 ///
82 public float? SignBottomUpHeight { get; set; }
83
84 ///
87 public int? SignIndexPages { get; set; }
88
89 ///
92 public byte[] Pfx { get; set; }
93
94 ///
97 public string PfxPwd { get; set; }
98
99 public Stream Signature()
100 {
101 ///加载PDF文档
102 PdfDocument pdf = new PdfDocument();
103 pdf.LoadFromBytes(this.WaitSignFile);
104
105 if (pdf?.Pages?.Count <= 0)
106 {
107 throw new Exception("文件有误");
108 }
109
110 X509Certificate2 x509 = new X509Certificate2(this.Pfx, this.PfxPwd);
111 PdfOrdinarySignatureMaker signatureMaker = new PdfOrdinarySignatureMaker(pdf, x509);
112
113 var appearance = new PdfCustomSignatureAppearance(this.CharactersSign, this.ImageSign, this.SignRightLeftWidth, this.SignBottomUpHeight);
114 IPdfSignatureAppearance signatureAppearance = appearance;
115
116 // 绘画白底图片
117 PdfRubberStampAnnotation logoStamp = new PdfRubberStampAnnotation(new RectangleF(new PointF(0, 0), new SizeF(350, 22)));
118 PdfAppearance logoApprearance = new PdfAppearance(logoStamp);
119 //var logoPath = AppDomain.CurrentDomain.BaseDirectory + "\\white.jpg";
120 byte[] byt = Convert.FromBase64String(WatermarkCoverBase64);
121 Stream streamByLogo = new MemoryStream(byt);
122 PdfImage image = PdfImage.FromStream(streamByLogo);
123 PdfTemplate template = new PdfTemplate(350, 22);
124 template.Graphics.DrawImage(image, 0, 0);
125 logoApprearance.Normal = template;
126 logoStamp.Appearance = logoApprearance;
127
128 if (this.SignIndexPages.HasValue)
129 {
130 if (this.SignIndexPages.Value < 0 || this.SignIndexPages.Value > pdf?.Pages?.Count)
131 {
132 throw new Exception("签名索引页有误");
133 }
134
135 var page = pdf.Pages[this.SignIndexPages.Value];
136
137 // 添加白底图片覆盖页面顶部印记
138 page.AnnotationsWidget.Add(logoStamp);
139
140 // 在页面中的指定位置添加可视化签名
141 signatureMaker.MakeSignature("signName_", page, page.ActualSize.Width - appearance.SignRightLeftWidth, page.ActualSize.Height - appearance.SignBottomUpHeight, appearance.SignRightLeftWidth, appearance.SignBottomUpHeight, signatureAppearance);
142 }
143 else
144 {
145 foreach (PdfPageBase page in pdf.Pages)
146 {
147 // 添加白底图片覆盖页面顶部印记
148 page.AnnotationsWidget.Add(logoStamp);
149
150 // 在页面中的指定位置添加可视化签名
151 signatureMaker.MakeSignature("signName_", page, page.ActualSize.Width - appearance.SignRightLeftWidth, page.ActualSize.Height - appearance.SignBottomUpHeight, appearance.SignRightLeftWidth, appearance.SignBottomUpHeight, signatureAppearance);
152 }
153 }
154
155 MemoryStream stream = new MemoryStream();
156 pdf.SaveToStream(stream, FileFormat.PDF);
157 pdf.Close();
158 return stream;
159 }
160
161 ///
164 /// 原文件地址
165 //private static MemoryStream ClearPdfFilesFirstPage(MemoryStream sourcePdf)
166 //{
167 // iTextSharp.text.pdf.PdfReader reader = null;
168 // iTextSharp.text.Document document = new iTextSharp.text.Document();
169 // iTextSharp.text.pdf.PdfImportedPage page = null;
170 // iTextSharp.text.pdf.PdfCopy pdfCpy = null;
171 // int n = 0;
172 // reader = new iTextSharp.text.pdf.PdfReader(sourcePdf);
173 // reader.ConsolidateNamedDestinations();
174 // n = reader.NumberOfPages;
175 // document = new iTextSharp.text.Document(reader.GetPageSizeWithRotation(1));
176 // MemoryStream memoryStream = new MemoryStream();
177 // pdfCpy = new iTextSharp.text.pdf.PdfCopy(document, memoryStream);
178 // document.Open();
179 // for (int j = 2; j <= n; j++)
180 // {
181 // page = pdfCpy.GetImportedPage(reader, j);
182 // pdfCpy.AddPage(page);
183
184 // }
185 // reader.Close();
186 // document.Close();
187 // return memoryStream;
188 //}
189 }
190
191
192 public class PdfCustomSignatureAppearance : IPdfSignatureAppearance
193 {
194 public PdfCustomSignatureAppearance(string charactersSign, byte[] sign, float? signRightLeftWidth, float? signBottomUpHeight)
195 {
196 this.CharactersSign = charactersSign;
197
198 if (sign != null && sign.Length > 0)
199 {
200 this.Sign = sign;
201 MemoryStream ms = new MemoryStream(sign);
202 var image = System.Drawing.Image.FromStream(ms);
203 if (!signRightLeftWidth.HasValue)
204 {
205 signRightLeftWidth = image.Width;
206 }
207
208 if (!signBottomUpHeight.HasValue)
209 {
210 signBottomUpHeight = image.Height;
211 }
212 }
213
214 this.SignRightLeftWidth = signRightLeftWidth.Value;
215 this.SignBottomUpHeight = signBottomUpHeight.Value;
216 }
217
218 ///
221 public byte[] Sign { get; set; }
222
223 ///
226 public float SignRightLeftWidth { get; set; }
227
228 ///
231 public float SignBottomUpHeight { get; set; }
232
233 ///
236 public string CharactersSign { get; set; }
237
238 public void Generate(PdfCanvas g)
239 {
240 if (!string.IsNullOrWhiteSpace(CharactersSign))
241 {
242 float fontSize = 15;
243 var font = new System.Drawing.Font("Arial", fontSize);
244 PdfTrueTypeFont fontByPdf = new PdfTrueTypeFont(font, true);
245 g.DrawString(CharactersSign, fontByPdf, PdfBrushes.Black, new PointF(0, 0));
246 }
247
248 if (this.Sign != null && this.Sign.Length > 0)
249 {
250 Stream stream = new MemoryStream(this.Sign);
251 g.DrawImage(Spire.Pdf.Graphics.PdfImage.FromStream(stream), new PointF(20, 20));
252 }
253 }
254 }
调用实现
1 static void Main(string[] args)
2 {
3
4 /*
5 前言:最近有个需求是需要对文档进行数字签名;
6 描述:本示例基于Spire.Pdf组件对PDF进行数字签名,演示了
7 签名证书使用项目
8 CreateSelfSignedCertificateByBouncyCastle(https://github.com/daileass/CreateSelfSignedCertificateByBouncyCastle.git)
9 生成的自签名证书pfx,解决了数字签名后文档头部有警告
10
11 */
12
13 var fileCert = System.Environment.CurrentDirectory + "\\Cert\\";
14 var file = System.Environment.CurrentDirectory + "\\File\\";
15 var filePath = file + "dome.pdf";
16 var newFilePath = file + $"dome_{DateTime.Now.ToString("yyyyMMddHHmmss")}.pdf";
17 var pfxFilePath = fileCert + "edd9386229324d969692dcabf97ac095dpps.fun.pfx";
18 var pfxFilePwd = "ABCD123456";
19 var signFilePath = file + "sign.png";
20
21 // 数字签名
22 var digitalSignature = new DigitalSignature(
23 File2Bytes(filePath),
24 File2Bytes(signFilePath),
25 "Sign Here:",
26 File2Bytes(pfxFilePath),
27 pfxFilePwd
28 );
29 var stream = digitalSignature.Signature();
30
31 // 保存签名后的文件
32 using (var fileStream = File.Create(newFilePath))
33 {
34 stream.Seek(0, SeekOrigin.Begin);
35 stream.CopyTo(fileStream);
36 }
37
38 Console.WriteLine("OK");
39 Console.ReadLine();
40 }
41
42 ///
45 /// 文件地址
46 ///
47 public static byte[] File2Bytes(string path)
48 {
49 if (!System.IO.File.Exists(path))
50 {
51 return new byte[0];
52 }
53
54 FileInfo fi = new FileInfo(path);
55 byte[] buff = new byte[fi.Length];
56
57 FileStream fs = fi.OpenRead();
58 fs.Read(buff, 0, Convert.ToInt32(fs.Length));
59 fs.Close();
60
61 return buff;
62 }
源码下载:https://github.com/daileass/PDFDigitalSignatureBySelfSignedCertificate.git
手机扫一扫
移动阅读更方便
你可能感兴趣的文章