iText Documentation - c#

I have a PDF document that has a number of fill-in fields (text and checkboxes). How do you go about referencing these objects so I can manipulate its value, then push that updated PDF to the user where they can save it to their desired location. I'm not finding any good documentation on how to do this.
Any information you could give me would be greatly appreciated.
Right now I am using the following code, but when I go to open it my PDF reader tells me that it is damaged or corrupt.
String srcPath = Server.MapPath("~/App_Data/w9.pdf");
String dstPath = Server.MapPath("~/App_Data/w9_" + Session.SessionID + "_updated.pdf");
if (File.Exists(dstPath)) {
File.Delete(dstPath);
}
File.Copy(srcPath, dstPath);
PdfReader reader = new PdfReader(dstPath);
try
{
PdfStamper stamper = new PdfStamper(reader, Response.OutputStream);
stamper.FormFlattening = true;
stamper.AcroFields.SetField("topmostSubform[0].Page1[0].f1_01_0_[0]", "Homer J Simpson");
Response.ContentType = "application/pdf";
Response.BufferOutput = true;
Response.AppendHeader("Content-Disposition", "attachment; filename=W9_" +Session.SessionID + "_Complete.pdf");
Response.TransmitFile(dstPath);
}
catch (Exception ex)
{
Response.Write(ex.Message);
}

I'm the author of the iText documentation. If you have a static form, then you can use the methods described in this chapter to fill out your form: http://www.manning.com/lowagie2/samplechapter6.pdf
Read section 6.3.5 to find out how to fill out a form created with Open Office. However, it looks as if you are using a form created with Adobe LiveCycle (fieldnames like topmostSubform[0].Page1[0].f1_01_0_[0] are typical for XFA forms).
Section 6.3.5 concludes with the following remark:
"There’s much more to say about forms, but we can’t go into further
detail until we’ve talked about annotations. Also, I haven’t said
anything about the different types of PDF forms yet: there are forms
based on AcroForm technology (like the form you created using Open
Office), and there are XFA forms (created with Adobe Designer). This
will have to wait until chapter 8, because we have one more group of
PDF manipulation classes left to cover."
If your form is a dynamic XFA form without any AcroForm technology inside, you need XFA Worker to flatten it. You can download a trial version of XFA Worker here: http://itextsupport.com/download/xfaworker.html
The first question you have to answer before you continue is: do I have an AcroForm or an XFA form? If you have an XFA form, you'll need either Adobe LiveCycle ES or XFA Worker to fill and flatten such a form. Both are closed source products. I don't know of any free / open source library that supports XFA flattening.
PS: if by "damaged" you mean that you get a message saying This document enabled extended features... then you are breaking the Reader enabling. You should read chapter 8 of "iText in Action - Second Edition" to find out how to avoid this message.

Related

Visible signature created using iText 7 not shown in chrome

I am using iText 7 to sign pdf documents.
This works without problems, and the signature is shown as valid.
In addition to the digital signature, i want to show a visual representation on the pdf. This is described in the digital signature book chapter 2.4 Creating different signature appearances.
The produced pdf shows this appearance if i open it using adobe reader.
The first image is a pdf created using word and the save as pdf functionality.
The second image is a demo pdf i just downloaded random.
If i open the first pdf in chrome, the signature appearance text is not shown, but if i open the pdf which was initially created using word, the signature apperance is missing.
Any ideas on whats wrong with the pdf which doesn't show the signature appearance in chrome?
edit: Links to the documents
Pdf which shows signature in chrome
https://1drv.ms/b/s!AkROTDoCWFJnkd5VOFjUHZfpQXzJWQ?e=MeyZje
Pdf which doesn't show signature in chrome
https://1drv.ms/b/s!AkROTDoCWFJnkd5W5P3MCbb8fwLASA?e=zsmks0
edit 2: Code sample
The following code sample will sign a pdf document using a local certificate and place some text into the SignatureAppearance which is not shown in chrome.
using iText.Kernel.Geom;
using iText.Kernel.Pdf;
using iText.Signatures;
using System.IO;
using System.Security.Cryptography.X509Certificates;
namespace PdfSigning.Lib.Helpers
{
public class SignPdfTest
{
public static byte[] SingPdfUsingCertificate(X509Certificate2 cert2, byte[] pdfToSign)
{
var apk = Org.BouncyCastle.Security.DotNetUtilities.GetKeyPair(cert2.PrivateKey).Private;
IExternalSignature pks = new PrivateKeySignature(apk, DigestAlgorithms.SHA512);
var cp = new Org.BouncyCastle.X509.X509CertificateParser();
var chain = new[] { cp.ReadCertificate(cert2.RawData) };
using (PdfReader reader = new PdfReader(new MemoryStream(pdfToSign)))
{
using (MemoryStream fout = new MemoryStream())
{
StampingProperties sp = new StampingProperties();
sp.UseAppendMode();
PdfSigner signer = new PdfSigner(reader, fout, sp);
PdfSignatureAppearance appearance = signer.GetSignatureAppearance();
appearance.SetPageNumber(1);
appearance.SetLayer2Text("Hello world");
appearance.SetLayer2FontSize(8);
Rectangle pr = new Rectangle(10, 10, 200, 100);
appearance.SetPageRect(pr);
appearance.SetRenderingMode(PdfSignatureAppearance.RenderingMode.DESCRIPTION);
appearance.SetPageRect(pr);
signer.SignDetached(pks, chain, null, null, null, 0, PdfSigner.CryptoStandard.CMS);
return fout.ToArray();
}
}
}
}
}
private static void SignDocumentUsingCertificateConfiguration()
{
try
{
var certificateSignatureConfiguration = new CertificateSignatureConfiguration();
var cert2 = new X509Certificate2(#"C:\temp\MyCertificate.pfx", "mypassword", X509KeyStorageFlags.Exportable);
CertificatePdfSigner certPdfSigner = new CertificatePdfSigner(certificateSignatureConfiguration);
byte[] signedPdf = PdfSigning.Lib.Helpers.SignPdfTest.SingPdfUsingCertificate(cert2, File.ReadAllBytes(#"C:\temp\WordSaveAsPdf.pdf"));
File.WriteAllBytes(#"C:\temp\WordSaveAsPdf_Signed.pdf", signedPdf);
Console.WriteLine("Done");
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
In short
Chrome appears to not read object streams of hybrid reference PDFs, in particular not in the incremental update added during signature creation.
iText, on the other hand, puts nearly all its changes during signing into an object stream.
Thus, Chrome is not aware of the added signature and its appearance.
One can resolve the situation by forcing iText not to create an object stream here.
What is special about the Word generated source PDF?
PDF files contain object cross reference information which map object numbers to offsets of the respective starts of these objects in the file. These information can be stored in two ways, as cross reference table and (since PDF 1.5) also as cross reference stream. Also since PDF 1.5 the format allows to put non-stream objects into so called object streams which allows superior compression as only stream contents can be compressed.
As most PDF viewers at the time PDF 1.5 has been introduced did not support cross reference and object streams, a mixed, hybrid reference style was also introduced then. In this style the basic objects in a PDF which are strictly necessary to display it, are added normally (not in object streams) and are referenced from cross reference tables. Extra information which is not strictly necessary is then added in object streams and referenced from cross reference streams.
MS Word creates PDFs in this hybrid style and is virtually the only software to do so.
What is special about the iText signed result PDF?
iText put nearly all the changes into an object stream in a new incremental update.
Apparently, though, Chrome does not fully support object and cross reference streams, in particular not if combined with further incremental updates.
Thus, Chrome is not aware of the added signature and its visualization.
How to resolve the problem?
What we need to do, therefore, is convince iText that it shall not add important data in an object stream during signing. Due to member variable visibilities this is not as easy as one would like; I used reflection here for that.
In your code simply use the following PdfSignerNoObjectStream instead of PdfSigner:
public class PdfSignerNoObjectStream : PdfSigner
{
public PdfSignerNoObjectStream(PdfReader reader, Stream outputStream, StampingProperties properties) : base(reader, outputStream, properties)
{
}
protected override PdfDocument InitDocument(PdfReader reader, PdfWriter writer, StampingProperties properties)
{
try
{
return base.InitDocument(reader, writer, properties);
}
finally
{
FieldInfo propertiesField = typeof(PdfWriter).GetField("properties", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic);
WriterProperties writerProperties = (WriterProperties) propertiesField.GetValue(writer);
writerProperties.SetFullCompressionMode(false);
}
}
}
Beware, though, tweaking iText functionality like this is not guaranteed to work across versions. I tested it for a recent iText-7.1.7-SNAPSHOT development state; I expect it to also work for the previous 7.1.x versions.
Is this a Chrome bug? Or an iText bug? Or what?
Most likely it's kind of both.
On one hand the Chrome PDF viewer appears to have issues with hybrid reference PDFs. Considering how long they have been part of the PDF format, that is somewhat disappointing.
And on the other hand the PDF specification requires in the context of hybrid reference documents:
In general, the objects that may be hidden are optional objects specified by indirect references. [...]
Items that shall be visible include the entire page tree, fonts, font descriptors, and width tables. Objects that may be hidden in a hybrid-reference file include the structure tree, the outline tree, article threads, annotations, destinations, Web Capture information, and page labels.
(ISO 32000-1, section 7.5.8.4 Compatibility with Applications That Do Not Support Compressed Reference Streams)
In the case at hand an (updated) page object is in the object stream, i.e. hidden from viewers not supporting cross reference and object streams.
Currently iText 7 PdfDocument attempts to enforce FullCompression on PdfWriters if the underlying PdfReader has any cross reference stream (HasXrefStm):
writer.properties.isFullCompression = reader.HasXrefStm();
(PdfDocument method Open)
Probably it shouldn't enforce that if the PdfReader also is identified as hybrid reference stream (HasHybridXref).
This might be simply caused by the chrome build-in PDF reader. As far as I understood his case, the person who requested help from Chrome devs in this question has received some answers and was redirected to another part of the forum where he could get help. I can try to recreate the problem with itext-sharp 5 (I used that in a previous project) and see if that signature is not shown in Chrome but the odds won't be good.
This sounds an awful lot like a case of the "Needs Appearances" flag not being set. Back in my day (wheeze) iText form fields were generated with as little graphical data as possible, and would set the \NeedsAppearances flag to true, letting the PDF viewer in question (Acrobat Reader was about it back then) that it needed to generate the form fields' appearances before trying to draw them to screen.
And visible PDF Signatures are held in form fields.
So its at least theoretically possible that you can fix this programmatically by telling iText to (re?)generate the form field appearances.

Syncfusion DocIO: When converting from word document to pdf, footer is nowhere to be found

I am trying to simply convert a word document to a pdf and render it to the browser. When I do so, the converted PDF doesn't has the word document footer.
Here is my method:
private int ConvertShowPDF(WordDocument RevisionWordDocument)
{
RevisionWordDocument.ChartToImageConverter = new ChartToImageConverter();
DocToPDFConverter converter = new DocToPDFConverter();
try
{
PdfDocument pdfDocument = converter.ConvertToPDF(RevisionWordDocument);
MemoryStream pdfStream = new MemoryStream();
pdfDocument.Save(pdfStream);
HttpContext.Current.Response.ContentType = "application/pdf";
HttpContext.Current.Response.AddHeader("content-disposition", "inline; filename=RevisionesAdministrativas.PDF");
HttpContext.Current.Response.AddHeader("content-length", pdfStream.Length.ToString());
HttpContext.Current.Response.BinaryWrite(pdfStream.ToArray());
HttpContext.Current.Response.End();
pdfDocument.Close();
RevisionWordDocument.Save(HttpContext.Current.Server.MapPath("~/App_Data/Edited.docx"), FormatType.Docx);
RevisionWordDocument.Close();
return 0;
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
return 1;
}
}
What I am doing wrong?? This is some kind of bug? Help please. Thank you!
Thank you for using Syncfusion products.
On further analyzing with the given input document from forum #132027, we have found that document contains group shape in the footer.
Currently DocIO doesn’t provide support for grouped shapes preservation in Word to PDF conversion. We have already logged this as a feature request in our database. We will implement this feature in any of our upcoming releases and we don’t have any immediate plans to implement this feature. We usually have an interval of at least three months between releases. The feature implementation would also greatly depend on the factors such as product design, code compatibility and complexity. We will update you when this feature has been implemented.
As a work-around kindly modify the group shape as ungroup shape in the input Word document thereby it will be preserved properly in the PDF document. We have modified your Word document with image. Please find the modified document from below link.
Modified document link:
http://www.syncfusion.com/downloads/support/forum/132027/doc/RevisionesAdministrativas-Multiples_Modified-139642195.docx
Please let us know if you have any other questions.
Regards,
Ramanan H
I found the problem in my Word document
My Word document has a footer with a custom shape. As noted in the documentation, custom shapes are not supported in the DocIO Syncfusion library yet.
The workaround for me was saving the document as PDF from Microsoft Word, and with Snipping Tool, taking a cropped screenshot of the the footer, saving it as a .jpg image and inserting this image in the Word document footer.
In order to be allowed to put the image edge to edge in the document footer, you can follow this workaround.
That's it.

Error in siging a pdf filled using itext

I am using iText to fill a pdf. This pdf contains a xfa from, I fill this form through a xml file . After filling the form user need to download it and sign it manually. So far so good everything works fine every field in form filled properly. If user sign the file adobe reader make a new copy of file with signature.
But when user try to sign that pdf it gives following error and the newly generated file with signature doesn't save data, It make all field blank.
At least one signature has problems
When user sign pdf adobe reader also give a popup on signature verification
But if i fill the same pdf manually without using itext it allow me to sign pdf successfully
this is the code that i am using to fill pdf with xml data :
public static byte[] FillXfaForm(byte[] byteArray, String xmlFilePath)
{
PdfReader reader = new PdfReader(byteArray);
using (MemoryStream ms = new MemoryStream())
{
using (PdfStamper stamper = new PdfStamper(reader, ms,'\0',true))
{
stamper.Writer.CloseStream = false;
stamper.AcroFields.Xfa.FillXfaForm(xmlFilePath);
}
if(File.Exists(xmlFilePath))
{
File.Delete(xmlFilePath);
}
return ms.ToArray();
}
}
And here is the screen shot of error message
Please help me to solve this issue.
Finally I fix this problem
The cause of this problem is that i update whole xml document to fill xfa from but when i only update the data part not the whole xml it works without any error.
I don't know what is the difference it really create as in this similar question "Bruno Lowagie" state that you can either use full xml replace or you can change data part only.
How can I set XFA data in a static XFA form in iTextSharp and get it to save?
But for me it allow me to sign the document only if I replace data part not the whole xml data.
I hope it will help someone facing similar problem.

Strip Adobe Reader and Version requirements from PDF before outputting it to browser

I am planning on using pdf.js to have PDF context via the browser with Javascript. The problem is that some PDFs, the ones I am using, require Adobe's Reader with a specific Version. pdf.js does does not yet(ever?) support spoofing of these. What I need to know is if there's a way in C# to open the PDF and remove these Reader and Version requirements and how to do it. I was planning on using itextsharp to do other PDF manipulation server-side so an example using this would be most helpful. I plan on serving these as an ActionResult from an ajax request via MVC 4, so a MemoryStream would be most helpful at the end of this manipulation.
So in the end pdf.js was unable to do what I needed it too, however, what I was able to do was convert the Xfa/Pdf to a C# object then send the pages as needed via Json to my Javascript for rendering in the HTML5 Canvas. The code below takes an xfa-in-a-pdf file and turns it into a C# object with the help of itextsharp:
PdfReader.unethicalreading = true;
PdfReader reader = new PdfReader(new FileStream(Statics.PdfUploadLocation + PdfFileName, FileMode.Open, FileAccess.Read));
XfaForm xfaForm = new XfaForm(reader);
XDocument xDoc = XDocument.Parse(xfaForm.DomDocument.InnerXml);
string xfaNamespace = #"{http://www.xfa.org/schema/xfa-template/2.6/}";
List<XElement> formPages = xDoc.Descendants(xfaNamespace + "subform").Descendants(xfaNamespace + "subform").ToList();
TotalPages = formPages.Count();
var fieldIndex = 0;
RawPdfFields = new List<XfaField>();
for (int page = 0; page < formPages.Count(); page++)
{
RawPdfFields.AddRange(formPages[page].Descendants(xfaNamespace + "field")
.Select(x => new XfaField
{
Page = page,
Index = fieldIndex++,
Name = (string)x.Attribute("name"),
Height = GetUnitFromPossibleString((string)x.Attribute("h")),
Width = GetUnitFromPossibleString((string)x.Attribute("w")),
XPosition = GetUnitFromPossibleString((string)x.Attribute("x")),
YPosition = GetUnitFromPossibleString((string)x.Attribute("y")),
Reference = GetReference(x.Descendants(xfaNamespace + "traverse")),
AssistSpeak = GetAssistSpeak(x.Descendants(xfaNamespace + "speak"))
}).ToList());
}
Your PDF file n-400.pdf uses the Adobe XML Forms Architecture (XFA). This means you require a viewer that also supports XFA which pdf.js seemingly does not.
Such a PDF normally contains some standard PDF content which indicates that the PDF requires some viewer that supports XFA. In your case the content contains
If this message is not eventually replaced by the proper contents of the document, your PDF viewer may not be able to display this type of document.
This actually indicates what a XFA enabled viewer does, it renders some pages based upon information in the XFA XML data and displays it instead of the PDF style page descriptions.
While being defined proprietarily by Adobe, the PDF specification ISO 32000-1 describes how XFA data is to be embedded in a PDF document, cf. section 12.7.8 XFA Forms.
If you only need those forms in a flattened state, you might want to have a look at iText Demo: Dynamic XFA forms in PDF.

Can I fill in an encrypted PDF with iTextSharp?

I have a fillable, saveable PDF file that has an owner password (that I don't have access to). I can fill it out in Adobe reader, export the FDF file, modify the FDF file, and then import it.
Then I tried to do it with iText for .NET. I can't create a PdfStamper from my PdfReader because I didn't provide the owner password to the reader. Is there any way to do this programmatically or must I recreate the document?
Even using FdfReader requires a PdfStamper. Am I missing anything? Anything legal that is - I'm pretty sure I could hack the document, but I can't. Ironically, recreating it would probably be ok.
This line will bypass edit password checking in iTextSharp:
PdfReader.unethicalreading = true;
[I found this question several months after it was posted and I'm posting this solution now for anyone who comes across this question in a search.]
I was in the exact same situation: my customer had a PDF with fillable fields that I needed to programmatically access. Unfortunately the PDF was password protected and they didn't have the password so I found couldn't work with their file.
What I discovered was that iTextSharp version 4.0.4 (and later) enforces password restrictions, earlier versions did not.
So I downloaded version 4.0.3 and sure enough it worked. In my case I didn't even have to change my code to use this older version.
You can download 4.0.3 (and all other versions) at SourceForge.
Two important things
Set PdfReader.unethicalreading = true to prevent BadPasswordException.
Set append mode in PdfStamper's constructor, otherwise the Adobe Reader Extensions signature becomes broken and Adobe Reader will display following message: "This document contained certain rights to enable special features in Adobe Reader. The document has been changed since it was created and these rights are no longer valid. Please contact the author for the original version of this document."
So all you need to do is this:
PdfReader.unethicalreading = true;
using (var pdfReader = new PdfReader("form.pdf"))
{
using (var outputStream = new FileStream("filled.pdf", FileMode.Create, FileAccess.Write))
{
using (var stamper = new iTextSharp.text.pdf.PdfStamper(pdfReader, outputStream, '\0', true))
{
stamper.AcroFields.Xfa.FillXfaForm("data.xml");
}
}
}
See How to fill XFA form using iText?
Unless someone else chimes in, I'll assume the answer is "No"
I wound up regenerating the PDF in an unencrypted form.

Categories