Sign PDF file on last page - c#

I am using C# and iTextSharp 3.1 to sign PDF files. The signing is working, but I want to sign on the last page of the file. The code I use is such :
reader = new PdfReader(inputPDF);
int numberOfPages = reader.NumberOfPages;
PdfStamper st = PdfStamper.CreateSignature(reader, new FileStream(outputPDF, FileMode.Create, FileAccess.Write), '\0', null, true);
PdfSignatureAppearance sap = st.SignatureAppearance;
if (logoSign != null)
{
// Scale img to fit
logoSign.ScaleToFit(100, 50);
// Set Signature position on page
logoSign.SetAbsolutePosition(300, 80);
sap.Image = logoSign;
}
sap.SetCrypto(this.myCert.Akp, this.myCert.Chain, null, PdfSignatureAppearance.VERISIGN_SIGNED);
if (SigReason.Length > 0)
sap.Reason = SigReason;
if (SigContact.Length > 0)
sap.Contact = SigContact;
if (SigLocation.Length > 0)
sap.Location = SigLocation;
if (visible)
sap.SetVisibleSignature(mySignRect, 1, null);
try
{
st.Close();
} catch(Exception e) { }
This code signs of the 1st page of the file. I want o sign on the last page of the file. How do I set to sign on last page.
I also wonder, the same code doesn't work in iTextSharp5.4.2. It gives error on sap.SetCrypto() and st.Close(). Any idea how to I make it work in 5.4.2.
Thanks

Please try the C# version of the examples that come with the white paper referenced by mkl: http://sourceforge.net/p/itextsharp/code/HEAD/tree/tutorial/signatures/

Related

iText7 converting signature as an invisible signature after using append mode property

I am getting issue that if I use UseAppendMode property while creating signature field in the document, upon signing it creates invisible signature. Otherwise it displays the content of my custom signature appearance and creates a visible signature into PDF.
Following is my code snippet:
SigningResponse signingResponse = new SigningResponse();
Stream outputStream = new MemoryStream();
Org.BouncyCastle.X509.X509Certificate x509Certificate = null;
int estimatedSize = SigningProfile.ContainsKey(ProfileCommon.DICTIONARY_SIZE.ToString()) ?
int.Parse(SigningProfile[ProfileCommon.DICTIONARY_SIZE.ToString()]) * 1024 : 600 * 1024;
Stream readerStream = new MemoryStream(documentBytes);
PdfReader pdfReader = new PdfReader(readerStream);
PdfSigner pdfSigner = new PdfSigner(pdfReader, outputStream, new StampingProperties().UseAppendMode());
pdfSigner.SetFieldName("Signature1");
pdfSigner.GetDocument().GetCatalog().SetModified();
if (signingRequest.CertifyPolicy != (int)CertifyPolicy.NOT_CERTIFIED)
pdfSigner.SetCertificationLevel(signingRequest.CertifyPolicy);
PdfSignatureAppearance signatureAppearance = pdfSigner.GetSignatureAppearance();
signatureAppearance.SetContact("Contact Info");
signatureAppearance.SetLocation("Location");
signatureAppearance.SetPageNumber(1);
signatureAppearance.SetReason("Signing Reason");
PdfFormXObject n0 = signatureAppearance.GetLayer0();
float x = n0.GetBBox().ToRectangle().GetLeft();
float y = n0.GetBBox().ToRectangle().GetBottom();
float width = n0.GetBBox().ToRectangle().GetWidth();
float height = n0.GetBBox().ToRectangle().GetHeight();
PdfCanvas canvas = new PdfCanvas(n0, pdfSigner.GetDocument());
canvas.SetFillColor(ColorConstants.LIGHT_GRAY);
canvas.Rectangle(x, y, width, height);
canvas.Fill();
// Set the signature information on layer 2
PdfFormXObject n2 = signatureAppearance.GetLayer2();
Paragraph p = new Paragraph("This document was signed by Bruno Specimen.");
new Canvas(n2, pdfSigner.GetDocument()).Add(p);
signatureAppearance.SetCertificate(x509Certificate);
PreSigning external = new PreSigning(PdfName.Adobe_PPKLite, PdfName.Adbe_pkcs7_detached);
pdfSigner.SignExternalContainer(external, estimatedSize);
signingResponse.DocumentHash = external.getHash();
signingResponse.D2S = signingResponse.DocumentHash;
signingResponse.DocumentBytes = ((MemoryStream)outputStream).ToArray();
return signingResponse;
And the code of creating signature field is as follows:
byte[] documentBytes = null;
foreach (PDFSignatureField field in signatureFields)
{
using (Stream memoryStream = new MemoryStream())
using (PdfReader _pdfReader = new PdfReader(new MemoryStream(_documentBytes)).SetUnethicalReading(true))
using (PdfDocument pdfDocument = new PdfDocument(_pdfReader, new PdfWriter(memoryStream)))
{
PdfAcroForm pdfAcroForm = PdfAcroForm.GetAcroForm(pdfDocument, true);
//Initializing signature position object
PDFSignaturePosition SigPosition = field.Position;
for (int i = 0 ; i < SigPosition.Pages.Length ; ++i)
{
//Getting PDF document page
PdfPage page = pdfDocument.GetPage(SigPosition.Pages[i]);
if (page == null)
{
page = pdfDocument.GetPage(SigPosition.PageNumber);
}
//Getting PDF document page rotation
int rotation = page.GetRotation();
//Getting signature field rects according to PDF page
iText.Kernel.Geom.Rectangle rect;
if (rotation > 0 && SigPosition.Position == PDFSignaturePosition.DefaultSignaturePosition.Custom)
{
rect = GetSignaturePositionAccordingToRotation(SigPosition.Rect, page.GetCropBox(), rotation);
}
else
{
rect = GetSignaturePositionRect(SigPosition.Position, SigPosition.Rect, page.GetCropBox());
}
//Creating signature field into PDF page
PdfFormField sig = PdfFormField.CreateSignature(pdfDocument, rect);
//Setting signature field visible flag
if (field.Display == (int)SignatureDisplayType.INVISIBLE)
{
sig.SetFieldFlags(PdfFormField.HIDDEN);
sig.SetVisibility(PdfFormField.HIDDEN);
}
else
{
sig.SetFieldFlags(PdfFormField.VISIBLE);
}
//Setting signature field font information
sig.Put(PdfName.DA, new PdfString("/Helv 0 Tf 0 g"));
//Setting signature field name
sig.SetFieldName(i == 0 ? field.Name : field.Name + " - " + SigPosition.Pages[i]);
//Setting signature field page
sig.SetPage(SigPosition.Pages[i]);
//Adding signature field into AcroForm
pdfAcroForm.AddField(sig, page);
//Making indirect reference of the added signature field into PDF
sig.MakeIndirect(pdfDocument);
//Closing PDF document object
pdfDocument.Close();
//Getting latest document bytes after adding PDF field
documentBytes = ((MemoryStream)memoryStream).ToArray();
if (i + 1 == SigPosition.Pages.Length)
{
break;
}
}
_documentBytes = documentBytes;
}
}
As you use a lot of variables defined, declared, and filled outside of the code you show, I had to reduce your code considerably. Furthermore, I don't have your example documents to tests with and, therefore, had to test with documents I have at hand here.
Nonetheless, I could reproduce the issue and found a solution for it in my setup. I hope that in spite of all the differences in setup you can use this solution.
The reason for the signature field becoming invisible in my setup turned out to be that while adding the signature fields to the document in append mode, the Fields array in the document-wide AcroForms dictionary was not marked as modified. The signer on the other hand relies on the signature field to sign to be found in that Fields array. The signer, therefore, did not find the prepared, visible field and created a new, invisible field with that name.
A work-around is to manually mark the array in question as modified:
pdfAcroForm.GetPdfObject().Get(PdfName.Fields).SetModified();
pdfAcroForm.GetPdfObject().SetModified();
//Closing PDF document object
pdfDocument.Close();

PDFSharp is cutting landscape pages with C# and WPF

thanks for take the time to read my odd issue with PDFSharp.
I use PDFSharp Library Version 1.50.4000.0 (I update from 1.3.2 and have the same issue) at the time to protect a PDF file with a password.
The program works very good with portrait documents but some times I have documents with mixed orientations.
But all the times when a landscape page it's in the document the page is cutted.
The code for your reference:
PdfDocument document = PdfReader.Open(System.IO.Path.Combine("H:/Bloq1/", file.Name), "PasswordHere");
PdfSecuritySettings securitySettings = document.SecuritySettings;
securitySettings.OwnerPassword = "PasswordHere";
securitySettings.PermitAccessibilityExtractContent = false;
securitySettings.PermitAnnotations = false;
securitySettings.PermitAssembleDocument = false;
securitySettings.PermitExtractContent = false;
securitySettings.PermitFormsFill = true;
securitySettings.PermitFullQualityPrint = true;
securitySettings.PermitModifyDocument = false;
securitySettings.PermitPrint = true;
document.Save(System.IO.Path.Combine("H:/Bloq1/", file.Name));
tbx.Text = "Complete";
tbx.Background = Brushes.ForestGreen;
Thanks in advance for your time reading or answering this question =D
*****************************Solved*********************************************
I switch to iTextSharp and test a couple of documents and works pretty well I'll share the code for reference:
private void Button_Full(object sender, RoutedEventArgs e)//PROTEGE PDF PERMITIENDO IMPRESION
{
string Password = "password";
DirectoryInfo dir = new DirectoryInfo("H:/Bloq1/");
if(dir.GetFiles("*.pdf").Length ==0)
{
MessageBox.Show("There are no files in the default directory", "No Files", MessageBoxButton.OK, MessageBoxImage.Warning);
tbx.Background = Brushes.OrangeRed;
tbx.Text = "No Files Found";
}
else
{
tbx.Background = Brushes.White;
tbx.Text = "Protecting....";
foreach (FileInfo file in dir.GetFiles("*.pdf"))
{
try
{
string InputFile = System.IO.Path.Combine("H:/Bloq1/", file.Name);
string OutputFile = System.IO.Path.Combine("H:/Bloq1/", "#"+file.Name);
using (Stream input = new FileStream(InputFile, FileMode.Open, FileAccess.Read, FileShare.Read))
{
using (Stream output = new FileStream(OutputFile, FileMode.Create, FileAccess.Write, FileShare.None))
{
PdfReader.unethicalreading = true;
PdfReader reader = new PdfReader(input);
PdfEncryptor.Encrypt(reader, output, true, null, Password, PdfWriter.AllowPrinting);
}
}
file.Delete();
File.Move(#"H:\Bloq1\#"+file.Name, #"H:\Bloq1\"+file.Name);
tbx.Text = "Full Protected";
tbx.Background = Brushes.ForestGreen;
}
catch (Exception ex)
{
tbx.Text = "Error in: " + file.Name + ex;
tbx.Background = Brushes.IndianRed;
}
}
}
}
For those that believe "I switched to iText" is not an answer, I've found a "fix" for PDFSharp.
Without diving into the source code PDFSharp appears to do a redundant rotation on landscape pages. This corrected the landscape pages in documents I worked with that had both portrait and landscape pages.
PdfPages pageCollection = pdfDoc.Pages;
for (int i = 0; i < pageCollection.Count; i++)
{
if (pageCollection[i].Orientation.ToString().Equals("Landscape"))
{
if (pageCollection[i].Rotate == 90)
{
pageCollection[i].Orientation = PageOrientation.Portrait;
}
}
}
If you use the source code version of PDFsharp you can make this change in PdfPage.cs to see if it solves your problem:
internal PdfPage(PdfDictionary dict)
: base(dict)
{
// Set Orientation depending on /Rotate.
//int rotate = Elements.GetInteger(InheritablePageKeys.Rotate);
//if (Math.Abs((rotate / 90)) % 2 == 1)
// _orientation = PageOrientation.Landscape;
}
I'd be glad to see feedback if you have to make further changes to get it working.
See also:
http://forum.pdfsharp.net/viewtopic.php?p=9591#p9591
I switch to iTextSharp and test a couple of documents and works pretty well I'll share the code for reference in the top.
Thank You to all
Since PDFSharp can only properly handle transformations on portrait pages, my work-around was converting the landscape pages to portrait with .page.Rotate = 0 and then applying my transformations while accounting for that the page was now sideways. Before saving the file, I converted the page back to landscape with .page.Rotate = 90. Worked fine!
I had this same problem with my pages getting cut off. That's why its important to rotate the pages instead of directly changing the Page.Orientation attribute!

Import pdf at a specific page

I have the requirement to merge pdf together. I need to import a pdf at a specific page into another one.
Let me illustrate this to you.
I have two pdf, first one is 50 pages long and the second one is 4pages long. I need to import the second one at the 13th page of the first pdf.
I don't find any exemple. There are plenty exemple on how to merge pdf but nothing about merging at a specific page.
Based on this exemple it look like I need to iterate over all pages one by one and import them in a new pdf. That look a bit painfull espicially if you have big pdf and need to merge many. I would create x new pdf to merge x+1 pdf.
Is there something I don't understand or is it really the way to go?
Borrowing from the example, this should be easy to do with a few modifications. You just need to add all the pages before the merge, then all the pages from the second document, then all the rest of the original pages.
Try something like this (not tested or robust - just a starting point maybe):
// Used the ExtractPages as a starting point.
public void MergeDocuments(string sourcePdfPath1, string sourcePdfPath2,
string outputPdfPath, int insertPage) {
PdfReader reader1 = null;
PdfReader reader2 = null;
Document sourceDocument1 = null;
Document sourceDocument2 = null;
PdfCopy pdfCopyProvider = null;
PdfImportedPage importedPage = null;
try {
reader1 = new PdfReader(sourcePdfPath1);
reader2 = new PdfReader(sourcePdfPath2);
// Note, I'm assuming pages are 0 based. If that's not the case, change to 1.
sourceDocument1 = new Document(reader1.GetPageSizeWithRotation(0));
sourceDocument2 = new Document(reader2.GetPageSizeWithRotation(0));
pdfCopyProvider = new PdfCopy(sourceDocument1,
new System.IO.FileStream(outputPdfPath, System.IO.FileMode.Create));
sourceDocument1.Open();
sourceDocument2.Open();
int length1 = reader1.NumberOfPages;
int length2 = reader2.NumberOfPages;
int page1 = 0; // Also here I'm assuming pages are 0-based.
// Having these three loops is the key. First is pages before the merge.
for (;page1 < insertPage && page1 < length1; page1++) {
importedPage = pdfCopyProvider.GetImportedPage(reader1, page1);
pdfCopyProvider.AddPage(importedPage);
}
// These are the pages from the second document.
for (int page2 = 0; page2 < length2; page2++) {
importedPage = pdfCopyProvider.GetImportedPage(reader2, page2);
pdfCopyProvider.AddPage(importedPage);
}
// Finally, add the remaining pages from the first document.
for (;page1 < length1; page1++) {
importedPage = pdfCopyProvider.GetImportedPage(reader1, page1);
pdfCopyProvider.AddPage(importedPage);
}
sourceDocument1.Close();
sourceDocument2.Close();
reader1.Close();
reader2.Close();
} catch (Exception ex) {
throw ex;
}
}

ITextsharp invalidates signatures when using lines or rectangles

When I use ITextSharp to digitally sign a document that is already digitally signed using this code it invalidates the other signatures. If I digitally sign using a text or image it works fine. Is this an Adobe/Itextsharp limitation or is something wrong with the code?
public void SignWithLine(string pdfFilePath, string outputFilePath, LineAnnotation lineAnnotation)
{
double xStartPoint = 89.285969238281268, yStartPoint = 343.08978515624881, xEndPoint = 72.7515234375, yEndPoint = 496.03341796874878, lineStroke = .24;
CertificateWrapper certificate = CertificateWrapper.GetCertificateInformationFromSignature(GetCertificateInformation());
PdfReader reader = new PdfReader(pdfFilePath);
PdfTemplate layer = null;
using (PdfStamper signature = PdfStamper.CreateSignature(reader, null, '\0', outputFilePath, true))
{
PdfSignatureAppearance signatureAppearance = signature.SignatureAppearance;
signatureAppearance.SignatureRenderingMode = PdfSignatureAppearance.RenderingMode.GRAPHIC;
Rectangle rect = new Rectangle((float)Math.Min(xStartPoint, xEndPoint), (float)Math.Min(yStartPoint, yEndPoint), (float)Math.Min(xStartPoint, xEndPoint) + (float)Math.Abs(xEndPoint - xStartPoint), (float)Math.Min(yStartPoint, yEndPoint) + (float)Math.Abs(yEndPoint - yStartPoint));
signatureAppearance.SetVisibleSignature(rect, lineAnnotation.PageIndex + 1, GetCertificateFieldName());
layer = signatureAppearance.GetLayer(2);
PdfContentByte cb = signature.GetUnderContent(lineAnnotation.PageIndex + 1);
cb.SetLineWidth((float)lineStroke);
cb.MoveTo((float)xStartPoint, (float)yStartPoint);
cb.LineTo((float)(xEndPoint), (float)(yEndPoint));
cb.Stroke();
signatureAppearance.CertificationLevel = PdfSignatureAppearance.NOT_CERTIFIED;
// Normal signature, not a certification
MakeSignature.SignDetached(signatureAppearance, certificate.DigitalSignature, certificate.Chain, null, null, null, 0, true);
signature.Close();
}
}
signature is your PdfStamper. You draw a line on
PdfContentByte cb = signature.GetUnderContent(lineAnnotation.PageIndex + 1);
i.e. You draw it in the content stream of a page. This counts as a change of the page content and, therefore, is forbidden by the original signature. For details on the allowed changes cf. this answer.
I found a way to do this by modifying the iTextSharp library.
// First I overloaded the SetVisibleSignature to pass a list of int
public void SetVisibleSignature(Rectangle pageRect, String fieldName, List pageList)
{
pages = pageList; // pages is a private List pages;
...
}
// Secondly, in the PreClose event you update it as shown below
sigField.Page = pagen;
if (pagen != 0)
writer.AddAnnotation(sigField, pagen);
else if (pages != null && pages.Count > 0)
pages.ForEach(f => writer.AddAnnotation(sigField, f)); // this annotates all pages with the same signature
else
throw new DocumentException("No pages specified for signature.");

PDFNet trying to add a text not working

I am basically trying out PDFNet and tweaking one of the samples of PDFNet. Here is the code:
PDFNet.Initialize();
// Relative path to the folder containing test files.
string input_path = "../../../../TestFiles/";
string output_path = "../../../../TestFiles/Output/";
PDFDoc doc = new PDFDoc(input_path + "form1.pdf");
for (int index = 1; index <= doc.GetPageCount(); index++)
{
Page page = doc.GetPage(index);
ElementBuilder eb = new ElementBuilder(); // ElementBuilder is used to build new Element objects
eb.Reset(); // Reset GState to default
ElementWriter writer = new ElementWriter(); // ElementWriter is used to write Elements to the page
writer.Begin(page);
// Begin writing a block of text
string data = "Page " + index;
Element element = eb.CreateTextRun(data, Font.Create(doc, Font.StandardType1Font.e_times_roman, true), 100.0);
element.SetTextMatrix(10, 0, 0, 10, 100, 100);
GState gstate = element.GetGState();
gstate.SetTextRenderMode(GState.TextRenderingMode.e_stroke_text);
gstate.SetStrokeColorSpace(pdftron.PDF.ColorSpace.CreateDeviceRGB());
gstate.SetStrokeColor(new pdftron.PDF.ColorPt(1, 0, 0));
writer.WriteElement(element);
writer.End();
writer.Dispose(); // save changes to the current page
}
doc.Save(output_path + "element_builder.pdf", SDFDoc.SaveOptions.e_linearized);
doc.Close();
But problem is, no text is added to element_builder.pdf. It is just copied as it is and looks same as form1.pdf. Can anybody help me out?
This is the link to PDFNet http://www.pdftron.com/pdfnet/downloads.html
I am using 64 bit version for .Net 4.0
It seems that you are missing the calls eb.CreateTextBegin() and eb.CreateTextEnd(). You should try something like this:
PDFNet.Initialize();
// Relative path to the folder containing test files.
string input_path = "../../../../TestFiles/";
string output_path = "../../../../TestFiles/Output/";
PDFDoc doc = new PDFDoc(input_path + "form1.pdf");
ElementWriter writer = new ElementWriter();
ElementBuilder eb = new ElementBuilder();
for (int index = 1; index <= doc.GetPageCount(); index++)
{
Page page = doc.GetPage(index);
writer.Begin(page);
eb.Reset();
// Begin writing a block of text
string data = "Page " + index;
Element element = eb.CreateTextBegin(Font.Create(doc, Font.StandardType1Font.e_times_roman, true), 10.0);
writer.WriteElement(element);
eb.CreateTextRun(data);
element.SetTextMatrix(10, 0, 0, 10, 100, 100);
GState gstate = element.GetGState();
gstate.SetTextRenderMode(GState.TextRenderingMode.e_fill_text);
gstate.SetStrokeColorSpace(pdftron.PDF.ColorSpace.CreateDeviceRGB());
gstate.SetStrokeColor(new pdftron.PDF.ColorPt(1, 0, 0));
writer.WriteElement(element);
writer.WriteElement(eb.CreateTextEnd());
writer.End();
}
writer.Dispose();
eb.Dispose();
doc.Save(output_path + "element_builder.pdf", SDFDoc.SaveOptions.e_linearized);
doc.Close();
Btw. a possibly simpler way to add text to an existing page may be to use 'pdftron.PDF.Stamper' as shown in Stamper sample.

Categories

Resources