// You may also change texts, positions and more by editing directly the method // generatePrinterFriendlyVersion() below. // #################################################################################################### // GET: PrinterFriendlyPadesRestPki?userfile={id} public ActionResult Index(string userfile) { // Locate document and read content from storage. Our action only works if the a valid fileId is // given. byte[] fileContent; try { fileContent = StorageMock.Read(userfile); } catch (FileNotFoundException) { return(HttpNotFound()); } // Check if doc already has a verification code registered on storage. var verificationCode = StorageMock.GetVerificationCode(userfile); if (verificationCode == null) { // If not, generate a code an register it. verificationCode = AlphaCode.Generate(); StorageMock.SetVerificationCode(userfile, verificationCode); } // Generate the printer-friendly version. var pfvContent = generatePrinterFriendlyVersion(fileContent, verificationCode); // Return printer-friendly version as a downloadable file. return(File(pfvContent, "application/pdf", "printer-friendly.pdf")); }
// You may also change texts, positions and more by editing directly the method generatePrinterFriendlyVersion below // ################################################################################################################## protected void Page_Load(object sender, EventArgs e) { // Get document ID from query string var fileId = Request.QueryString["file"]; // Locate document and read content from storage var fileContent = StorageMock.Read(fileId); // Check if doc already has a verification code registered on storage var verificationCode = StorageMock.GetVerificationCode(fileId); if (verificationCode == null) { // If not, generate a code and register it verificationCode = AlphaCode.Generate(); StorageMock.SetVerificationCode(fileId, verificationCode); } // Generate the printer-friendly version var pfvContent = generatePrinterFriendlyVersion(fileContent, verificationCode); // Return printer-friendly version as a downloadable file Response.ContentType = "application/pdf"; Response.AddHeader("Content-Disposition", "attachment; filename=printer-friendly.pdf"); Response.BinaryWrite(pfvContent); Response.End(); }
// GET: CheckPadesRest?c={id} public ActionResult Index(string c) { // On PrinterFriendlyVersionController, we stored the unformatted version of the verification // code (without hyphens) but used the formatted version (with hiphens) on the printer-friendly // PDF. Now, we remove the hyphens before looking it up. var verificationCode = AlphaCode.Parse(c); // Get document associated with verification code. var fileId = StorageMock.LookupVerificationCode(verificationCode); if (fileId == null) { // Invalid code give! // Small delay to slow down brute-force attacks (if you want to be extra careful you might // want to add a CAPTCHA to the process). Thread.Sleep(TimeSpan.FromSeconds(2)); // Return Not Found return(HttpNotFound()); } // Read document from storage. var fileContent = StorageMock.Read(fileId); // Get an instance of the PadesSignatureExplorer class, used to open/validate PDF signatures. var sigExplorer = new PadesSignatureExplorer(Util.GetRestPkiClient()) { // Specify that we want to validate the signatures in the file, not only inspect them. Validate = true, // Specify the parameters for the signature validation: // Accept any PAdES signature as long as the signer has an ICP-Brasil certificate. DefaultSignaturePolicyId = StandardPadesSignaturePolicies.Basic, // Specify the security context to be used to determine trust in the certificate chain. We // have encapsulated the security context choice on Util.cs. SecurityContextId = Util.GetSecurityContextId() }; // Set the PDF file. sigExplorer.SetSignatureFile(fileContent); // Call the Open() method, which returns the signature file's information. var signature = sigExplorer.Open(); // Render the information (see file Check/Index.html for more information on // the information returned). return(View(new OpenPadesSignatureModel() { Signature = signature, File = fileId })); }
protected void Page_Load(object sender, EventArgs e) { // Get verification code from query string var formattedVerificationCode = Request.QueryString["code"]; // On PrinterFriendlyVersion.aspx, we stored the unformatted version of the verification code (without hyphens) but // used the formatted version (with hyphens) on the printer-friendly PDF. Now, we remove the hyphens before looking it up. var verificationCode = AlphaCode.Parse(formattedVerificationCode); // Get document associated with verification code var fileId = StorageMock.LookupVerificationCode(verificationCode); if (fileId == null) { // Invalid code given! // Small delay to slow down brute-force attacks (if you want to be extra careful you might want to add a CAPTCHA to the process) Thread.Sleep(TimeSpan.FromSeconds(2)); // Return Not Found Response.StatusCode = 404; Response.End(); return; } // Read document from storage var fileContent = StorageMock.Read(fileId); // Open and validate signatures with Rest PKI var client = Util.GetRestPkiClient(); var sigExplorer = new PadesSignatureExplorer(client) { Validate = true, DefaultSignaturePolicyId = StandardPadesSignaturePolicies.Basic, SecurityContextId = Util.GetSecurityContextId(), }; sigExplorer.SetSignatureFile(fileContent); var signature = sigExplorer.Open(); // Set properties for rendering on page (see aspx file) this.FileId = fileId; this.Model = signature; }
protected void Page_Load(object sender, EventArgs e) { // Get verification code from query string. var formattedVerificationCode = Request.QueryString["c"]; // On PrinterFriendlyVersion.aspx, we stored the unformatted version of the verification code // (without hyphens) but used the formatted version (with hyphens) on the printer-friendly PDF. Now, // we remove the hyphens before looking it up. var verificationCode = AlphaCode.Parse(formattedVerificationCode); // Get document associated with verification code. var fileId = Storage.LookupVerificationCode(verificationCode); if (fileId == null) { // Invalid code given! // Small delay to slow down brute-force attacks (if you want to be extra careful you might want // to add a CAPTCHA to the process). Thread.Sleep(TimeSpan.FromSeconds(2)); // Return "Not Found" HTTP response. Response.StatusCode = 404; Response.End(); return; } // Read document from storage. var fileContent = Storage.GetFile(fileId); // Open and validate signatures with PKI SDK based on the PAdES Basic policy. var signature = Lacuna.Pki.Pades.PadesSignature.Open(fileContent); var policyMapper = PadesPoliciesForGeneration.GetPadesBasic(Util.GetTrustArbitrator()); // Generate a model to be shown on the page from the PadesSignature instance computed from Open() // method above. This class can be inspected on SignatureModels.cs file. In this class, we validate // each signature based on the policy mapper defined above. var model = new PadesSignatureModel(signature, policyMapper); // Set properties for rendering on page (see aspx file). this.FileId = fileId; this.Model = model; }
// GET: CheckCadesSdk?c={id} public ActionResult Index(string c) { // On PrinterFriendlyVersionController, we stored the unformatted version of the verification // code (without hyphens) but used the formatted version (with hiphens) on the printer-friendly // PDF. Now, we remove the hyphens before looking it up. var verificationCode = AlphaCode.Parse(c); // Get document associated with verification code. var fileId = StorageMock.LookupVerificationCode(verificationCode); if (fileId == null) { // Invalid code give! // Small delay to slow down brute-force attacks (if you want to be extra careful you might // want to add a CAPTCHA to the process). Thread.Sleep(TimeSpan.FromSeconds(2)); // Return Not Found return(HttpNotFound()); } // Read document from storage. var fileContent = StorageMock.Read(fileId); var signature = CadesSignature.Open(fileContent); // Specify the parameters for the signature validation: // Define the trust arbitrator used to validate the certificate. var trustArbitrator = Util.GetTrustArbitrator(); var policyMapper = CadesPoliciesForValidation.GetCadesBasic(trustArbitrator); // Render the information (see file Check/Index.html for more information on // the information returned). return(View(new OpenCadesSignatureModel() { Signature = new CadesSignatureModel(signature, policyMapper), File = fileId })); }
// You may also change texts, positions and more by editing directly the method // generatePrinterFriendlyVersion() below. // #################################################################################################### protected void Page_Load(object sender, EventArgs e) { // Get document ID from query string. var fileId = Request.QueryString["file"]; // Our action only works if a fileId is given to work with. if (string.IsNullOrEmpty(fileId)) { // Return "Not Found" HTTP response. Response.StatusCode = 404; Response.End(); return; } // Locate document and read content from storage. var fileContent = Storage.GetFile(fileId); // Check if doc already has a verification code registered on storage. var verificationCode = Storage.GetVerificationCode(fileId); if (verificationCode == null) { // If not, generate a code and register it. verificationCode = AlphaCode.Generate(); Storage.SetVerificationCode(fileId, verificationCode); } // Generate the printer-friendly version. var pfvContent = generatePrinterFriendlyVersion(fileContent, verificationCode); // Return printer-friendly version as a downloadable file. Response.ContentType = "application/pdf"; Response.AddHeader("Content-Disposition", "attachment; filename=printer-friendly.pdf"); Response.BinaryWrite(pfvContent); Response.End(); }
private byte[] generatePrinterFriendlyVersion(byte[] pdfContent, string verificationCode) { var client = Util.GetRestPkiClient(); // The verification code is generated without hyphens to save storage space and avoid // copy-and-paste problems. On the PDF generation, we use the "formatted" version, with hyphens // (which will later be discarded on the verification page). var formattedVerificationCode = AlphaCode.Format(verificationCode); // Build the verification link from the constant "VerificationLinkFormat" (see above) and the // formatted verification code. var verificationLink = string.Format(VerificationLinkFormat, formattedVerificationCode); // 1. Upload the PDF var blob = client.UploadFile(pdfContent); // 2. Inspect signatures on the uploaded PDF var sigExplorer = new PadesSignatureExplorer(client) { Validate = true, DefaultSignaturePolicyId = StandardPadesSignaturePolicies.Basic, SecurityContextId = Util.GetSecurityContextId(), }; sigExplorer.SetSignatureFile(blob); var signature = sigExplorer.Open(); // 3. Create PDF with verification information from uploaded PDF var pdfMarker = new PdfMarker(client); pdfMarker.SetFile(blob); // Build string with joined names of signers (see method getDisplayName below) var signerNames = Util.JoinStringsPt(signature.Signers.Select(s => getDisplayName(s.Certificate))); var allPagesMessage = string.Format("This document was digitally signed by {0}.\nTo verify the signatures go to {1} on {2} and inform the code {3}", signerNames, VerificationSiteNameWithArticle, VerificationSite, formattedVerificationCode); // PdfHelper is a class from the Rest PKI Client "fluent API" that helps to create elements and // parameters for the PdfMarker. var pdf = new PdfHelper(); // ICP-Brasil logo on bottom-right corner of every page (except on the page which will be created // at the end of the document). pdfMarker.Marks.Add( pdf.Mark() .OnAllPages() .OnContainer(pdf.Container().Width(1).AnchorRight(1).Height(1).AnchorBottom(1)) .AddElement( pdf.ImageElement() .WithOpacity(75) .WithImage(StorageMock.GetIcpBrasilLogoContent(), "image/png") ) ); // Summary on bottom margin of every page (except on the page which will be created at the end of // the document). pdfMarker.Marks.Add( pdf.Mark() .OnAllPages() .OnContainer(pdf.Container().Height(2).AnchorBottom().VarWidth().Margins(1.5, 3.5)) .AddElement( pdf.TextElement() .WithOpacity(75) .AddSection(allPagesMessage) ) ); // Summary on right margin of every page (except on the page which will be created at the end of // the document), rotated 90 degrees counterclockwise (text goes up). pdfMarker.Marks.Add( pdf.Mark() .OnAllPages() .OnContainer(pdf.Container().Width(2).AnchorRight().VarHeight().Margins(1.5, 3.5)) .AddElement( pdf.TextElement() .Rotate90Counterclockwise() .WithOpacity(75) .AddSection(allPagesMessage) ) ); // Create a "manifest" mark on a new page added on the end of the document. We'll add several // elements to this mark. var manifestMark = pdf.Mark() .OnNewPage() // This mark's container is the whole page with 1-inch margins. .OnContainer(pdf.Container().VarWidthAndHeight().Margins(2.54, 2.54)); // We'll keep track of our "vertical offset" as we add elements to the mark. double verticalOffset = 0; double elementHeight; elementHeight = 3; manifestMark // ICP-Brasil logo on the upper-left corner. .AddElement( pdf.ImageElement() .OnContainer(pdf.Container().Height(elementHeight).AnchorTop(verticalOffset).Width(elementHeight /* using elementHeight as width because the image is square */).AnchorLeft()) .WithImage(StorageMock.GetIcpBrasilLogoContent(), "image/png") ) // QR Code with the verification link on the upper-right corner. .AddElement( pdf.QRCodeElement() .OnContainer(pdf.Container().Height(elementHeight).AnchorTop(verticalOffset).Width(elementHeight /* using elementHeight as width because QR Codes are square */).AnchorRight()) .WithQRCodeData(verificationLink) ) // Header "VERIFICAÇÃO DAS ASSINATURAS" centered between ICP-Brasil logo and QR Code. .AddElement( pdf.TextElement() .OnContainer(pdf.Container().Height(elementHeight).AnchorTop(verticalOffset + 0.2).FullWidth()) .AlignTextCenter() .AddSection(pdf.TextSection().WithFontSize(NormalFontSize * 1.6).WithText("SIGNATURE\nCHECK")) ); verticalOffset += elementHeight; // Vertical padding. verticalOffset += 1.7; // Header with verification code. elementHeight = 2; manifestMark.AddElement( pdf.TextElement() .OnContainer(pdf.Container().Height(elementHeight).AnchorTop(verticalOffset).FullWidth()) .AlignTextCenter() .AddSection(pdf.TextSection().WithFontSize(NormalFontSize * 1.2).WithText(string.Format("Verification Code: {0}", formattedVerificationCode))) ); verticalOffset += elementHeight; // Paragraph saying "this document was signed by the following signers etc" and mentioning the // time zone of the date/times below. elementHeight = 2.5; manifestMark.AddElement( pdf.TextElement() .OnContainer(pdf.Container().Height(elementHeight).AnchorTop(verticalOffset).FullWidth()) .AddSection(pdf.TextSection().WithFontSize(NormalFontSize).WithText(string.Format("This document was digitally signed by the following signers on the indicated dates ({0}):", TimeZoneDisplayName))) ); verticalOffset += elementHeight; // Iterate signers. foreach (var signer in signature.Signers) { elementHeight = 1.5; manifestMark // Green "check" or red "X" icon depending on result of validation for this signer. .AddElement( pdf.ImageElement() .OnContainer(pdf.Container().Height(0.5).AnchorTop(verticalOffset + 0.2).Width(0.5).AnchorLeft()) .WithImage(StorageMock.GetValidationResultIcon(signer.ValidationResults.IsValid), "image/png") ) // Description of signer (see method getSignerDescription() below). .AddElement( pdf.TextElement() .OnContainer(pdf.Container().Height(elementHeight).AnchorTop(verticalOffset).VarWidth().Margins(0.8, 0)) .AddSection(pdf.TextSection().WithFontSize(NormalFontSize).WithText(getSignerDescription(signer))) ); verticalOffset += elementHeight; } // Some vertical padding from last signer. verticalOffset += 1; // Paragraph with link to verification site and citing both the verification code above and the // verification link below. elementHeight = 2.5; manifestMark.AddElement( pdf.TextElement() .OnContainer(pdf.Container().Height(elementHeight).AnchorTop(verticalOffset).FullWidth()) .AddSection(pdf.TextSection().WithFontSize(NormalFontSize).WithText(string.Format("To verify the signatures, go to {0} on ", VerificationSiteNameWithArticle))) .AddSection(pdf.TextSection().WithFontSize(NormalFontSize).WithColor(Color.Blue).WithText(VerificationSite)) .AddSection(pdf.TextSection().WithFontSize(NormalFontSize).WithText(" and inform the code above or follow the link below:")) ); verticalOffset += elementHeight; // Verification link. elementHeight = 1.5; manifestMark.AddElement( pdf.TextElement() .OnContainer(pdf.Container().Height(elementHeight).AnchorTop(verticalOffset).FullWidth()) .AddSection(pdf.TextSection().WithFontSize(NormalFontSize).WithColor(Color.Blue).WithText(verificationLink)) .AlignTextCenter() ); // Apply marks. pdfMarker.Marks.Add(manifestMark); var result = pdfMarker.Apply(); // Return result. return(result.GetContent()); }
private byte[] generatePrinterFriendlyVersion(byte[] pdfContent, string verificationCode) { // The verification code is generated without hyphens to save storage space and avoid copy-and-paste // problems. On the PDF generation, we use the "formatted" version, with hyphens (which will later // be discarded on the verification page). var formattedVerificationCode = AlphaCode.Format(verificationCode); // Build the verification link from the constant "VerificationLinkFormat" (see above) and the // formatted verification code. var verificationLink = string.Format(VerificationLinkFormat, formattedVerificationCode); // 1. Inspect signatures on the PDF. var signature = Lacuna.Pki.Pades.PadesSignature.Open(pdfContent); // 2. Create PDF with verification information from the signed PDF. var pdfMarker = new PdfMarker(); // Build string with joined names of signers (see method getDisplayName() below). var signerNames = Util.JoinStringsPt(signature.Signers.Select(s => getDisplayName(s.Signer.SigningCertificate))); var allPagesMessage = string.Format("This document was digitally signed by {0}.\nTo verify the signatures go to {1} on {2} and inform the code {3}", signerNames, VerificationSiteNameWithArticle, VerificationSite, formattedVerificationCode); // ICP-Brasil logo on bottom-right corner of every page (except on the page which will be created at // the end of the document). pdfMarker.AddMark(new PdfMark() { PageOption = PdfMarkPageOptions.AllPages, Container = new PadesVisualRectangle() { Width = 1, Right = 1, Height = 1, Bottom = 1 }, Elements = new List <PdfMarkElement>() { new PdfMarkImage() { ImageContent = Storage.GetIcpBrasilLogoContent(), Opacity = 75 } } }); // Summary on bottom margin of every page (except on the page which will be created at the end of // the document). pdfMarker.AddMark(new PdfMark() { PageOption = PdfMarkPageOptions.AllPages, Container = new PadesVisualRectangle() { Height = 2, Bottom = 0, Left = 1.5, Right = 3.5 }, Elements = new List <PdfMarkElement>() { new PdfMarkText() { Texts = new List <PdfTextSection>() { new PdfTextSection() { Style = PdfTextStyle.Normal, Text = allPagesMessage } } } } }); // Summary on right margin of every page (except on the page which will be created at the end of the // document), rotated 90 degrees counterclockwise (text goes up). pdfMarker.AddMark(new PdfMark() { PageOption = PdfMarkPageOptions.AllPages, Container = new PadesVisualRectangle() { Width = 2, Right = 0, Top = 1.5, Bottom = 3.5 }, Elements = new List <PdfMarkElement>() { new PdfMarkText() { Rotation = PdfMarkRotation.D90, Texts = new List <PdfTextSection>() { new PdfTextSection() { Style = PdfTextStyle.Normal, Text = allPagesMessage } } } } }); // Create a "manifest" mark on a new page added on the end of the document. We'll add several // elements to this marks. var manifestMark = new PdfMark() { PageOption = PdfMarkPageOptions.NewPage, // This mark's container is the whole page with 1-inch margins. Container = new PadesVisualRectangle() { Top = 2.54, Bottom = 2.54, Right = 2.54, Left = 2.54 } }; // We'll keep track of our "vertical offset" as we add elements to the mark. double verticalOffset = 0; double elementHeight; elementHeight = 3; // ICP-Brasil logo on the upper-left corner. manifestMark.Elements.Add(new PdfMarkImage() { RelativeContainer = new PadesVisualRectangle() { Height = elementHeight, Top = verticalOffset, Width = elementHeight, /* Using elemengHeight as width because the image is square. */ Left = 0 }, ImageContent = Storage.GetIcpBrasilLogoContent() }); // QR Code with the verification link on the upper-right corner. We will generate a PdfMarkImage from // a QR Code generated using the QRCoder library. byte[] qrCodeImageContent; using (var qrGenerator = new QRCodeGenerator()) { using (var qrCodeData = qrGenerator.CreateQrCode(verificationLink, QRCodeGenerator.ECCLevel.M)) { using (var qrCode = new QRCode(qrCodeData)) { var qrCodeBitmap = qrCode.GetGraphic(10, Color.Black, Color.White, false); using (var buffer = new MemoryStream()) { qrCodeBitmap.Save(buffer, ImageFormat.Png); qrCodeImageContent = buffer.ToArray(); }; } } } manifestMark.Elements.Add(new PdfMarkImage() { RelativeContainer = new PadesVisualRectangle() { Height = elementHeight, Top = verticalOffset, Width = elementHeight, /* Using elemengHeight as width because the image is square. */ Right = 0 }, ImageContent = qrCodeImageContent }); // Header "SIGNATURES VERIFICATION" centered between ICP-Brasil logo and QR Code. manifestMark.Elements.Add(new PdfMarkText() { RelativeContainer = new PadesVisualRectangle() { Height = elementHeight, Top = verticalOffset + 0.2, Right = 0, Left = 0 }, Align = PadesHorizontalAlign.Center, Texts = new List <PdfTextSection>() { new PdfTextSection() { Style = PdfTextStyle.Normal, FontSize = NormalFontSize * 1.6, Text = "SIGNATURES\nVERIFICATION" } } }); verticalOffset += elementHeight; // Verifical padding. verticalOffset += 1.7; // Header with verification code. elementHeight = 2; manifestMark.Elements.Add(new PdfMarkText() { RelativeContainer = new PadesVisualRectangle() { Height = elementHeight, Top = verticalOffset, Right = 0, Left = 0 }, Align = PadesHorizontalAlign.Center, Texts = new List <PdfTextSection>() { new PdfTextSection() { Style = PdfTextStyle.Normal, FontSize = NormalFontSize * 1.2, Text = string.Format("Verification Code: {0}", formattedVerificationCode) } } }); verticalOffset += elementHeight; // Paragraph saying "this document was signed by the following signer etc" and mentioning the time zone of the // date/times below. elementHeight = 2.5; manifestMark.Elements.Add(new PdfMarkText() { RelativeContainer = new PadesVisualRectangle() { Height = elementHeight, Top = verticalOffset, Left = 0, Right = 0 }, Texts = new List <PdfTextSection>() { new PdfTextSection() { Style = PdfTextStyle.Normal, FontSize = NormalFontSize, Text = string.Format("This document was digitally signed by the following signers on the indicated dates ({0}):", TimeZoneDisplayName) } } }); verticalOffset += elementHeight; // Iterate signers. foreach (var signer in signature.Signers) { elementHeight = 1.5; // Validate signature based on the PAdES Basic policy. var policyMapper = PadesPoliciesForGeneration.GetPadesBasic(Util.GetTrustArbitrator()); var validationResults = signature.ValidateSignature(signer, policyMapper); // Green "check" or red "X" icon depending on result of validation for this signer. manifestMark.Elements.Add(new PdfMarkImage() { RelativeContainer = new PadesVisualRectangle() { Height = 0.5, Top = verticalOffset + 0.2, Width = 0.5, Left = 0 }, ImageContent = Storage.GetValidationResultIcon(validationResults.IsValid) }); // Description of signer (see method getSignerDescription() below). manifestMark.Elements.Add(new PdfMarkText() { RelativeContainer = new PadesVisualRectangle() { Height = elementHeight, Top = verticalOffset, Left = 0.8, Right = 0 }, Texts = new List <PdfTextSection>() { new PdfTextSection() { Style = PdfTextStyle.Normal, FontSize = NormalFontSize, Text = getSignerDescription(signer) } } }); verticalOffset += elementHeight; } // Some vertical padding from last signer. verticalOffset += 1; // Paragraph with link to veritifcation site and citing both the verification code above and the // verification link below. elementHeight = 2.5; manifestMark.Elements.Add(new PdfMarkText() { RelativeContainer = new PadesVisualRectangle() { Height = elementHeight, Top = verticalOffset, Right = 0, Left = 0 }, Texts = new List <PdfTextSection>() { new PdfTextSection() { Style = PdfTextStyle.Normal, FontSize = NormalFontSize, Text = string.Format("To verify the signatures, go to {0} on ", VerificationSiteNameWithArticle) }, new PdfTextSection() { Color = Color.Blue, Style = PdfTextStyle.Normal, FontSize = NormalFontSize, Text = VerificationSite }, new PdfTextSection() { Style = PdfTextStyle.Normal, FontSize = NormalFontSize, Text = " and inform the code above or follow the link below:" } } }); verticalOffset += elementHeight; // Verification link. elementHeight = 1.5; manifestMark.Elements.Add(new PdfMarkText() { RelativeContainer = new PadesVisualRectangle() { Height = elementHeight, Top = verticalOffset, Right = 0, Left = 0 }, Align = PadesHorizontalAlign.Center, Texts = new List <PdfTextSection>() { new PdfTextSection() { Color = Color.Blue, Style = PdfTextStyle.Normal, FontSize = NormalFontSize, Text = verificationLink } } }); pdfMarker.AddMark(manifestMark); // Prevent from throwing exception when the file to be marked already have a signature (default: true). pdfMarker.ThrowIfSignedPdf = false; // Note: Before applying the marks, all signature from the signed file will be removed. // Apply marks and return the printer-friendly PDF's content. byte[] pfvContent = pdfMarker.WriteMarks(pdfContent); return(pfvContent); }