// =========================================================================== //  ©2013-2026 WebSupergoo. All rights reserved. // //  This source code is for use exclusively with the ABCpdf product with //  which it is distributed, under the terms of the license for that //  product. Details can be found at // //    http://www.websupergoo.com/ // //  This copyright notice must not be deleted and must be reproduced alongside //  any sections of code extracted from this module. // =========================================================================== using System; using System.Collections.Generic; using System.Diagnostics; using System.Text; using System.IO; using System.Security.Cryptography.X509Certificates; using System.Windows.Forms; using WebSupergoo.ABCpdf14; using WebSupergoo.ABCpdf14.Objects; using WebSupergoo.ABCpdf14.Atoms; using WebSupergoo.ABCpdf14.Elements; using WebSupergoo.ABCpdf14.Operations; namespace WebSupergoo.Annotations {   public class Test {     class Server {       public static string MapPath(string fileName) {         string theBase = Directory.GetCurrentDirectory();         return Directory.GetParent(theBase).Parent.FullName + "\\" + fileName;       }     }     public static void Main() {       const bool warning = false;       const string msg = "This project will prompt you for a signature. In order to provide the correct signature you will need to first install the JohnSmith.pfx certificate.\r\n\r\n" +         "You can do this by right clicking on the PFX file and selecting \'Install PFX\'. The password for the certificate is \'1234\'.\r\n\r\n" +         "Please note that this is a console application and that as such, any notifications or errors will be written to the console window.";       DialogResult result = (warning) ? MessageBox.Show(msg, "Important Note", MessageBoxButtons.OKCancel) : DialogResult.OK;       if (result == DialogResult.OK) {         CreateAnnotationsDemo(Server.MapPath("Annotations.pdf"));         ModifyFieldsDemo(Server.MapPath("DocToModify.pdf"), Server.MapPath("ModifiedFields.pdf"));         VerifyFileAndMakeReport(Server.MapPath("Annotations.pdf"), Server.MapPath("VerificationReport.txt"));         SimpleTextSignature(Server.MapPath("SignedDocument.pdf"));         if (File.Exists(Server.MapPath("image.png")))           SimpleImageSignature(Server.MapPath("image.png"), Server.MapPath("SignedDocumentImage.pdf"));         if ((File.Exists(Server.MapPath("image.png"))) && (File.Exists(Server.MapPath("DocToModify.pdf"))))           SimpleImageSignatureWithBorder(Server.MapPath("DocToModify.pdf"), Server.MapPath("image.png"), Server.MapPath("SignedDocumentImageBorder.pdf"));       }     }     // <summary>Ask the current user to select a certificate from the his/her     // personal store.</summary>     private static X509Certificate2 PromptUserForCert() {       X509Store store = new X509Store(StoreName.My, StoreLocation.CurrentUser);       store.Open(OpenFlags.ReadOnly);       try {         X509Certificate2Collection certs =           X509Certificate2UI.SelectFromCollection(           store.Certificates, "Digital Identity",           "Select a private key to sign",           X509SelectionFlag.SingleSelection);         // Return the first cert in the selection         foreach (X509Certificate2 cert in certs)           return cert;         return null;       }       finally {         store.Close();       }     }     // <returns>Friendly name of the cert, using canonical name as fallback.</returns>     private static string DisplayNameFromCert(X509Certificate2 cert) {       if (!string.IsNullOrEmpty(cert.FriendlyName))         return cert.FriendlyName;       return cert.Subject.Split(',')[0].Split('=')[1];     }     public static void CreateAnnotationsDemo(string outputFile) {       try {         using (Doc theDoc = new Doc()) {           theDoc.Font = theDoc.AddFont("Helvetica");           theDoc.FontSize = 36;           Catalog cat = theDoc.ObjectSoup.Catalog;           EmbeddedFileTree fileTree = new EmbeddedFileTree(theDoc);           fileTree.EmbedFile("MyFile1", Server.MapPath("ABCpdf.swf"), "attachment without annotation");           theDoc.SetInfo(theDoc.Root, "/PageMode:Name", "UseAttachments");           theDoc.Pos.X = 40;           theDoc.Pos.Y = theDoc.MediaBox.Top - 40;           theDoc.AddText("Interactive Form annotations");           // Create interactive form           XForm form = theDoc.Form;           int fontID = theDoc.AddFont("Times-Roman", LanguageType.Latin);           string fontName = form.AddResource(theDoc.ObjectSoup[fontID], "Font", "TimesRoman");           // Radio buttons           Field radio = form.AddRadioButtonGroup(new XRect[] { new XRect("40 610 80 650"), new XRect("40 660 80 700") }, "RadioGroupField", 0);           theDoc.Pos.String = "100 696";           theDoc.AddText("RadioButton 1");           theDoc.Pos.String = "100 646";           theDoc.AddText("RadioButton 2");           // Text fields           Field text = form.AddTextField(new XRect("40 530 300 580"), "TextField1", "Hello World!");           FieldElement textE = new FieldElement(text);           WidgetAnnotationElement textW = new WidgetAnnotationElement(text);           textE.EntryDA = $"/{fontName} 36 Tf 0 0 1 rg";           textW.EntryMK = new AppearanceCharacteristicsElement(textE);           textW.EntryMK.EntryBC = new double[] { 0, 0, 0 };           textW.EntryMK.EntryBG = new double[] { 220.0 / 255.0, 220.0 / 255.0, 220.0 / 255.0 };           textE.EntryQ = 0; // Left alignment           text = form.AddTextField(new XRect("40 460 300 510"), "TextField2", "Text Field");           textE = new FieldElement(text);           textW = new WidgetAnnotationElement(text);           textW.EntryMK = new AppearanceCharacteristicsElement(textE);           textW.EntryMK.EntryBC = new double[] { 0, 0, 0 };           textE.EntryDA = $"/{fontName} 36 Tf 0 0 1 rg";           textE.EntryQ = 0; // Left alignment           textE.EntryFf |= (int)Field.FieldFlags.Password;           text = form.AddTextField(new XRect("320 460 370 580"), "TextField3", "Vertical");           textE = new FieldElement(text);           textW = new WidgetAnnotationElement(text);           textW.EntryMK = new AppearanceCharacteristicsElement(textE);           textW.EntryMK.EntryBC = new double[] { 0, 0, 0 };           textE.EntryDA = $"/{fontName} 36 Tf 0 0 0 rg";           textW.EntryMK.EntryR = 90; // Rotation           // Combobox field           Field combo = form.AddComboBoxField(new XRect("40 390 300 440"), "ComboBoxField");           FieldElement comboE = new FieldElement(combo);           comboE.EntryDA = $"/{fontName} 24 Tf 0 0 0 rg";           combo.Options = new string[] { "ComboBox Item 1", "ComboBox Item 2", "ComboBox Item 3" };           // Listbox field           Field listbox = form.AddListBoxField(new XRect("40 280 300 370"), "ListBoxField");           FieldElement listboxE = new FieldElement(listbox);           listboxE.EntryDA = $"/{fontName} 24 Tf 0 0 0 rg";           listbox.Options = new string[] { "ListBox Item 1", "ListBox Item 2", "ListBox Item 3" };           // Checkbox field           form.AddCheckbox(new XRect("40 220 80 260"), "CheckBoxField", true);           theDoc.Pos.String = "100 256";           theDoc.AddText("Check Box");           // Pushbutton field           Field button = form.AddButton(new XRect("40 160 200 200"), "ButtonField", "Button");           WidgetAnnotationElement buttonW = new WidgetAnnotationElement(button);           buttonW.EntryMK = new AppearanceCharacteristicsElement(buttonW);           buttonW.EntryMK.EntryBC = new double[] { 0, 0, 0 };           buttonW.EntryBS = new BorderStyleElement(buttonW);           buttonW.EntryBS.EntryS = "B"; // beveled           // Markup annotations           theDoc.Page = theDoc.AddPage();           theDoc.Pos.X = 40;           theDoc.Pos.Y = theDoc.MediaBox.Top - 40;           theDoc.AddText("Markup annotations");           SquareAnnotation square = new SquareAnnotation(theDoc, new XRect("40 560 300 670"), XColor.FromRgb(255, 0, 0), XColor.FromRgb(0, 0, 255));           square.SquareElement.EntryBS = new BorderStyleElement(square.SquareElement);           square.SquareElement.EntryBS.EntryW = 8;           LineAnnotation line = new LineAnnotation(theDoc, new XPoint("100 565"), new XPoint("220 665"), XColor.FromRgb(255, 0, 0));           line.LineElement.EntryBS = new BorderStyleElement(line.LineElement);           line.LineElement.EntryBS.EntryW = 12;           line.RichTextCaption = "<span style= \"font-size:36pt; color:#FF0000\">Line</span>";           theDoc.FontSize = 24;           theDoc.Pos.String = "400 670";           int id1 = theDoc.AddText("Underline");           TextMarkupAnnotation markup = new TextMarkupAnnotation(theDoc, id1, TextMarkupType.Underline, XColor.FromRgb(0, 255, 0));           theDoc.Pos.String = "400 640";           int id2 = theDoc.AddText("Highlight");           markup = new TextMarkupAnnotation(theDoc, id2, TextMarkupType.Highlight, XColor.FromRgb(255, 255, 0));           theDoc.Pos.String = "400 610";           int id3 = theDoc.AddText("StrikeOut");           markup = new TextMarkupAnnotation(theDoc, id3, TextMarkupType.StrikeOut, XColor.FromRgb(255, 0, 0));           theDoc.Pos.String = "400 580";           int id4 = theDoc.AddText("Squiggly");           markup = new TextMarkupAnnotation(theDoc, id4, TextMarkupType.Squiggly, XColor.FromRgb(0, 0, 255));           CircleAnnotation circle = new CircleAnnotation(theDoc, new XRect("80 320 285 525"), XColor.FromRgb(255, 255, 0), XColor.FromRgb(255, 128, 0));           circle.CircleElement.EntryBS = new BorderStyleElement(circle.CircleElement);           circle.CircleElement.EntryBS.EntryW = 20;           circle.CircleElement.EntryBS.EntryS = "D"; // dashed           circle.CircleElement.EntryBS.EntryD = new ArrayElement<Element>(Atom.FromString("[3 2]"), cat);           LineAnnotation arrowLine = new LineAnnotation(theDoc, new XPoint("385 330"), new XPoint("540 520"), XColor.FromRgb(255, 0, 0));           arrowLine.LineEndingsStyle = "ClosedArrow ClosedArrow";           arrowLine.LineElement.EntryBS = new BorderStyleElement(arrowLine.LineElement);           arrowLine.LineElement.EntryBS.EntryW = 6;           arrowLine.FillColor = XColor.FromRgb(255, 0, 0);           double[] v1 = new double[] { 100, 70, 50, 120, 50, 220, 100, 270, 200, 270, 250, 220, 250, 120, 200, 70 };           PolygonAnnotation polygon = new PolygonAnnotation(theDoc, v1, XColor.FromRgb(255, 0, 0), XColor.FromRgb(0, 255, 0));           double[] v2 = new double[] { 400, 70, 350, 120, 350, 220, 400, 270, 500, 270, 550, 220, 550, 120, 500, 70 };           PolygonAnnotation cloudyPolygon = new PolygonAnnotation(theDoc, v2, XColor.FromRgb(255, 0, 0), XColor.FromRgb(64, 85, 255));           cloudyPolygon.CloudyEffect = 1;           // Movie annotations           // WMV is courtesy of NASA - http://www.nasa.gov/wmv/30873main_cardiovascular_300.wmv           theDoc.Page = theDoc.AddPage();           theDoc.Pos.X = 40;           theDoc.Pos.Y = theDoc.MediaBox.Top - 40;           theDoc.AddText("Multimedia features");           theDoc.FontSize = 24;           // Adobe says that Flash Player is not supported after December 2020 so this content addition is disabled.           // Of course "not supported" does not mean "does not work" which is why the code has been left here.           //theDoc.Pos.String = "40 690";           //theDoc.AddText("Flash movie:");           //ScreenAnnotation movie1 = new ScreenAnnotation(theDoc, new XRect("40 420 300 650"), Server.MapPath("ABCpdf.swf"));           //theDoc.Pos.String = "312 690";           //theDoc.AddText("Flash rich media:");           //RichMediaAnnotation media1 = new RichMediaAnnotation(theDoc, new XRect("312 420 572 650"), Server.MapPath("ABCpdf.swf"), "Flash");           theDoc.Pos.String = "40 400";           theDoc.AddText("Video File:");           ScreenAnnotation movie2 = new ScreenAnnotation(theDoc, new XRect("80 40 520 360"), Server.MapPath("video.wmv"));           theDoc.Page = theDoc.AddPage();           theDoc.FontSize = 36;           theDoc.Pos.X = 40;           theDoc.Pos.Y = theDoc.MediaBox.Top - 40;           theDoc.AddText("Other types of annotations");           // Sticky note annotation           theDoc.FontSize = 24;           theDoc.Pos.String = "40 680";           theDoc.AddText("Text annotation");           TextAnnotation textAnnotation = new TextAnnotation(theDoc, new XRect("340 660 360 680"), new XRect("550 650 600 750"), "6 sets of 13 pages. Trim to 5X7.");           // File attachment annotation           theDoc.Pos.String = "40 640";           theDoc.AddText("File Attachment annotation");           FileAttachmentAnnotation fileAttachment = new FileAttachmentAnnotation(theDoc, new XRect("340 620 360 640"), Server.MapPath("video.WMV"));           // StampAnnotations           theDoc.Pos.String = "40 600";           theDoc.AddText("Stamp annotations");           StampAnnotation stamp1 = new StampAnnotation(theDoc, new XRect("340 560 540 600"), "DRAFT", XColor.FromRgb(0, 0, 128));           StampAnnotation stamp2 = new StampAnnotation(theDoc, new XRect("340 505 540 545"), "FINAL", XColor.FromRgb(0, 128, 0));           StampAnnotation stamp3 = new StampAnnotation(theDoc, new XRect("340 450 540 490"), "NOT APPROVED", XColor.FromRgb(128, 0, 0));           string obj = Path.Combine(Path.GetTempPath(), "sphere.obj");           string mtl = Path.Combine(Path.GetTempPath(), "sphere.mtl");           try {             File.Copy(Server.MapPath("sphere.obj.txt"), obj, true);             File.Copy(Server.MapPath("sphere.mtl.txt"), mtl, true);             D3DAnnotation d3d = new D3DAnnotation(theDoc, new XRect("40 40 440 440"));             d3d.SetOBJ(obj);           }           finally {             File.Delete(obj);             File.Delete(mtl);           }           theDoc.PageNumber = 1;           // Link annotations           theDoc.Rect.SetSides(450, 530, 550, 580);           theDoc.Color.String = "128 128 255";           theDoc.FillRect();           var link = new LinkAnnotation(theDoc, theDoc.Rect);           var dest = new DestinationElement(link.LinkElement);           var page2 = theDoc.ObjectSoup.Catalog.Pages.GetPageArrayAll()[1];           dest.SetTarget(new PageObjectElement(page2), DestinationType.Fit);           link.LinkElement.EntryDest = dest;           theDoc.Color.String = "0 0 0";           // Some releases of Acrobat are problematic. eg 2022.003.20322           // They have things they want to add to Annotations, for example           // an NM property. These properties are optional and indeed           // somewhat niche, so they are not generally added by other           // software.           //           // However if, after signing, you click on the 'Validate' button           // on the 'Signature Panel' Acrobat will complain that the changes           // it has made have resulted in a change to the document. So it           // becomes a problem.           //           // Presumably at some point Adobe will see this as a bug in Acrobat           // and fix it, but in the short run it is probably best to cater to           // these ideosyncracies by adding in the bits Acrobat wants.           Page[] pages = theDoc.ObjectSoup.Catalog.Pages.GetPageArrayAll();           foreach (Page page in pages) {             foreach (var annot in page.GetAnnotations()) {               var ae = new AnnotationElement(annot);               if (ae.EntryAP == null || ae.EntryAP.EntryN == null)                 annot.UpdateAppearance();               if (ae.EntryNM == null)                 ae.EntryNM = Guid.NewGuid().ToString();               if (ae.EntrySubtype == "Text") {                 var e = new TextAnnotationElement(annot);                 e.EntryF |= (int)(Annotation.AnnotationFlags.NoZoom | Annotation.AnnotationFlags.NoRotate);               }             }           }           // Signature fields           // Add signature fields last so that entire document is signed           // Note: For maximum portability, it is recommended           // that you create all the signature fields before           // signing any one of them (as is demonstrated below).           //           // The reason is that adding a signature field           // changes the document. Although this is legal, not all           // versions of Acrobat are happy with all types of updates.           // As such, they may report existing valid signatures to be           // invalid.           //           // In the past, the "SigFlags" entry allowed contents to be           // appended to signed documents using incremental updates.           // However, the entry's treatment seems to have changed in           // Adobe Reader X. For example, Adobe Reader X will           // report the signatures in `SignedThenAppended.pdf` to           // be invalid whereas Acrobat 8 will report           // "signatures are valid, but document has been changed           // since it was signed."           // This `SignedThenAppended.pdf` file is a document created           // using Acrobat Professional 8. So given that Adobe products           // are not internally consistent here, it is difficult to see           // how any other products can be.           // We add the first signature field unsigned           Signature sig1 = form.AddSignature(new XRect("40 100 240 150"), "Signature1");           if (true) {             // And the second signature field unsigned.             // We will then add and sign a third signature.             // Then we will go back and sign the second signature.             Signature sig2 = form.AddSignature(new XRect("340 100 540 150"), "Signature2");             X509Certificate2 userCert = PromptUserForCert();             if (userCert != null) {               sig2.Signer = DisplayNameFromCert(userCert);               // We need not call sig2.Commit() as sig2 is not signed yet.             }             // We can add the last signature field signed and with appearance.             Signature sig3 = form.AddSignature(new XRect("340 160 540 220"), "Signature3");             sig3.Sign(Server.MapPath("JohnSmith.pfx"), "1234");             sig3.Reason = "I am the author";             sig3.Location = "New York";             VirtualPageOperation op = new VirtualPageOperation(theDoc, sig3.Rect.Width, sig3.Rect.Height);             theDoc.FitText($"Digitally signed by {sig3.Signer}\nReason: {sig3.Reason}\nLocation: {sig3.Location}\nDate: {sig3.SigningUtcTime:yyyy.MM.dd}");             sig3.GetAnnotations()[0].NormalAppearance = op.GetFormXObject();             theDoc.Page = sig3.PageID;             sig3.Commit();             // Go back and sign the second signature placeholder             // if interactive user has supplied the signing key             if (userCert != null) {               sig2 = (Signature)theDoc.Form.Fields["Signature2"];               sig2.Sign(userCert, true);             }           }           theDoc.SaveOptions.Linearize = false;           theDoc.SaveOptions.Remap = false;           theDoc.Save(outputFile);         }       }       catch (Exception e) {         Console.WriteLine("An exception occurred during document signing:");         Console.WriteLine("Message: " + e.Message);         Console.WriteLine("Source: " + e.Source);       }     }     public static void ModifyFieldsDemo(string inputFile, string outputFile) {       if (!File.Exists(inputFile))         return;       try {         using (Doc theDoc = new Doc()) {           theDoc.Read(inputFile);           theDoc.Font = theDoc.AddFont("Helvetica");           theDoc.FontSize = 36;           // Create interactive form           XForm form = theDoc.Form;           int fontID = theDoc.AddFont("Times-Roman", LanguageType.Latin);           string fontName = form.AddResource(theDoc.ObjectSoup[fontID], "Font", "TimesRoman");           // Add Radio buttons           form.AddRadioButtonGroup(new XRect[] { new XRect("40 610 80 650"), new XRect("40 660 80 700") }, "RadioGroupField", 0);           theDoc.Pos.String = "100 696";           theDoc.AddText("RadioButton 1");           theDoc.Pos.String = "100 646";           theDoc.AddText("RadioButton 2");           // Fields cannot have the same name. If we are going to add duplicate field name then later           // we will need to rationalize the document structure so that the two fields will synchronize.           string textFieldName = "TextField1";           bool fieldAlreadyExists = theDoc.Form[textFieldName] != null;           // Add Text field           Field text = form.AddTextField(new XRect("40 530 300 580"), textFieldName, "Hello World!");           FieldElement textE = new FieldElement(text);           WidgetAnnotationElement textW = new WidgetAnnotationElement(text);           textE.EntryDA = $"/{fontName} 36 Tf 0 0 1 rg";           textW.EntryMK = new AppearanceCharacteristicsElement(textE);           textW.EntryMK.EntryBC = new double[] { 0, 0, 0 };           textW.EntryMK.EntryBG = new double[] { 220.0 / 255.0, 220.0 / 255.0, 220.0 / 255.0 };           textE.EntryQ = 0; // Left alignment           // Here we need rationalize if necessary           if (fieldAlreadyExists)             form.MakeFieldIntoGroup(text);           // Add Synchronized Text Fields           List<IndirectObject> kids = new List<IndirectObject>();           kids.Add(form.AddTextField(new XRect("40 230 300 280"), null, null));           kids.Add(form.AddTextField(new XRect("40 170 300 220"), null, null));           form.AddGroupField(kids, "Group Field", "Synchronized");           // Delete Pre-Existing Fields (ones that appear to relate to text)           string[] names = theDoc.Form.GetFieldNames();           foreach (string name in names) {             if (name.Contains("Text")) {               Field field = theDoc.Form[name];               form.Remove(field);             }           }           // Move Pre-Existing Fields (ones that appear to relate to names)           foreach (string name in names) {             if (name.Contains("Name")) {               Field field = theDoc.Form[name];               Annotation[] annots = field.GetAnnotations();               foreach (Annotation annot in annots) {                 XRect rect = annot.Rect;                 rect.Move(0, -200); // move down                 rect.Magnify(2, 2); // amd make bigger                 annot.Rect = rect;               }             }           } #if DEBUG           // these options make PDF files more diff-able           theDoc.SaveOptions.Linearize = false;           theDoc.SaveOptions.Remap = false; #endif           theDoc.Save(outputFile);         }       }       catch (Exception e) {         Console.WriteLine("An exception occurred:");         Console.WriteLine("Message: " + e.Message);         Console.WriteLine("Source: " + e.Source);       }     }     public static void VerifyFileAndMakeReport(string fileName, string reportFileName) {       try {         StringBuilder sb = new StringBuilder();         sb.AppendLine("Signature verification report");         sb.AppendLine("File name: " + fileName);         using (Doc subjectDoc = new Doc()) {           subjectDoc.Read(fileName);           // certificates are used for validating the X.509 signature           // you may wish to obtain root certificates from a trusted authority           string[] certs = Server.MapPath("JohnSmith.cer").Split(new char[] { ';' });           int sigCount = 0;           foreach (Field theField in subjectDoc.Form.Fields) {             if (theField is Signature) {               sigCount++;               sb.AppendLine("");               Signature theSig = (Signature)theField;               string reportHtml = null;               if (theSig.Signer != null && theSig.Signer.Length > 0) {                 bool certificateValid = theSig.Validate(certs);                 IndirectObject v = theSig.ResolveObj(Atom.GetItem(theSig.Atom, "V"));                 int revision = v != null ? v.Revision : theSig.Revision;                 reportHtml = "Signature name: " + theSig.Name + "\r\n" +                   "Signed by: " + theSig.Signer + "\r\n" +                   "Reason: " + theSig.Reason + "\r\n" +                   "Date (UTC Time): " + theSig.SigningUtcTime + "\r\n" +                   "Location: " + theSig.Location + "\r\n" +                   "Is document modified: " + theSig.IsModified.ToString() + "\r\n" + // document has been modified or tampered with in some way - implies signature not valid                   "Is certificate valid: " + certificateValid.ToString() + "\r\n" +                   "Is document valid: " + (certificateValid && !theSig.IsModified).ToString() + "\r\n" +                   "Has document been updated: " + (revision < subjectDoc.ObjectSoup.Revisions).ToString() + "\r\n"; // signature applies to a previous revision of the document - valid but changes have been made               }               else {                 reportHtml = "Signature name: " + theSig.Name + "\r\n" +                   "This signature has not been signed.\r\n";               }               sb.Append(reportHtml);               foreach (byte[] certData in theSig.GetCertificates()) {                 X509Certificate2 theCert = new X509Certificate2(certData);                 sb.Append(AddCertificateDetails(theCert).ToString());               }             }           }           if (sigCount == 0)             sb.AppendLine("The document is not signed.");         }         File.WriteAllText(reportFileName, sb.ToString());       }       catch (Exception e) {         Console.WriteLine("An exception occured during document validation:");         Console.WriteLine("Message: " + e.Message);         Console.WriteLine("Source: " + e.Source);       }     }     private static StringBuilder AddCertificateDetails(X509Certificate2 inCert) {       StringBuilder sb = new StringBuilder();       sb.Append("Certificate details:" + "\r\n");       sb.Append("Subject: " + inCert.Subject + "\r\n");       sb.Append("Issued by: " + inCert.IssuerName.Name + "\r\n");       sb.Append("From: " + inCert.NotBefore.ToString() + " To: " + inCert.NotAfter.ToString() + "\r\n");       sb.Append("Serial Number:" + inCert.GetSerialNumberString() + "\r\n");       sb.Append("Version: " + inCert.Version.ToString() + "\r\n");       sb.Append("Algorithm: " + inCert.SignatureAlgorithm.FriendlyName + "\r\n");       foreach (X509Extension e in inCert.Extensions)         sb.Append(e.Oid.FriendlyName + ": " + e.Format(false) + "\r\n");       sb.Append("Public Key: " + inCert.PublicKey.Key.KeyExchangeAlgorithm + "\r\n");       sb.Append("Public Key Data " + inCert.GetPublicKeyString() + "\r\n");       return sb;     }     public static void SimpleTextSignature(string outputFile) {       try {         using (Doc theDoc = new Doc()) {           theDoc.Font = theDoc.AddFont("Helvetica");           theDoc.FontSize = 36;           // Create interactive form           XForm form = theDoc.Form;           theDoc.Pos.X = 40;           theDoc.Pos.Y = theDoc.MediaBox.Top - 40;           theDoc.AddText("Simple signed document");           // add signature           Signature sig = form.AddSignature(new XRect("340 160 540 220"), "Signature");           sig.LockFields();           sig.Sign(Server.MapPath("JohnSmith.pfx"), "1234");           sig.Reason = "I am the author";           sig.Location = "New York";           // Certifying the document makes all but the last signed signature invalid.           // See the CertifyDocument function for details.           sig.Certify();           // make signature appearance           VirtualPageOperation op = new VirtualPageOperation(theDoc, sig.Rect.Width, sig.Rect.Height);           theDoc.FitText($"Digitally signed by {sig.Signer}\nReason: {sig.Reason}\nLocation: {sig.Location}\nDate: {sig.SigningUtcTime:yyyy.MM.dd}");           sig.GetAnnotations()[0].NormalAppearance = op.GetFormXObject(); #if DEBUG           // these options make PDF files more diff-able           theDoc.SaveOptions.Linearize = false;           theDoc.SaveOptions.Remap = false; #endif           theDoc.Save(outputFile);         }       }       catch (Exception e) {         Console.WriteLine("An exception occurred during document signing:");         Console.WriteLine("Message: " + e.Message);         Console.WriteLine("Source: " + e.Source);       }     }     public static void SimpleImageSignature(string imageFile, string outputFile) {       try {         using (Doc theDoc = new Doc()) {           theDoc.Font = theDoc.AddFont("Helvetica");           theDoc.FontSize = 36;           // Create interactive form           XForm form = theDoc.Form;           theDoc.Pos.X = 40;           theDoc.Pos.Y = theDoc.MediaBox.Top - 40;           theDoc.AddText("Simple signed document");           // add signature           // Certifying the document makes all but the last signed signature invalid.           // See the CertifyDocument function for details.           Signature sig = form.AddSignature(new XRect("340 160 540 220"), "Signature");           sig.LockFields();           sig.Sign(Server.MapPath("JohnSmith.pfx"), "1234");           sig.Certify();           // make signature appearance           VirtualPageOperation op = new VirtualPageOperation(theDoc, sig.Rect.Width, sig.Rect.Height);           using (XImage theImage = XImage.FromFile(imageFile, null))             theDoc.AddImage(theImage);           sig.GetAnnotations()[0].NormalAppearance = op.GetFormXObject(); #if DEBUG           // these options make PDF files more diff-able           theDoc.SaveOptions.Linearize = false;           theDoc.SaveOptions.Remap = false; #endif           theDoc.Save(outputFile);         }       }       catch (Exception e) {         Console.WriteLine("An exception occurred during document signing:");         Console.WriteLine("Message: " + e.Message);         Console.WriteLine("Source: " + e.Source);       }     }     public static void SimpleImageSignatureWithBorder(string originalPdf, string imageFile, string outputFile) {       try {         using (Doc theDoc = new Doc()) {           theDoc.Read(originalPdf);           theDoc.Font = theDoc.AddFont("Helvetica");           theDoc.FontSize = 36;           // Create interactive form           XForm form = theDoc.Form;           theDoc.Rect.Inset(40, 40);           theDoc.AddText("Document Read\r\nAdd Unsigned Signature\r\nShow Image & Border");           // add signature           Signature sig = form.AddSignature(new XRect("340 160 540 220"), "Signature");           // make signature appearance           VirtualPageOperation op = new VirtualPageOperation(theDoc, sig.Rect.Width, sig.Rect.Height);           using (XImage theImage = XImage.FromFile(imageFile, null))             theDoc.AddImage(theImage);           theDoc.Color.SetRgb(255, 0, 0);           theDoc.FrameRect(true);           sig.GetAnnotations()[0].NormalAppearance = op.GetFormXObject(); #if DEBUG           // these options make PDF files more diff-able           theDoc.SaveOptions.Linearize = false;           theDoc.SaveOptions.Remap = false; #endif           theDoc.Save(outputFile);         }       }       catch (Exception e) {         Console.WriteLine("An exception occurred during document signing:");         Console.WriteLine("Message: " + e.Message);         Console.WriteLine("Source: " + e.Source);       }     }   } }