NullPointerException when decrypting pdf with itext - pdf

We are decrypting a pdf file with itext 5.5.8. The source code is as follows:
FileOutputStream outputstream = new FileOutputStream(outfile);
PDFReader reader = new PdfReader(new FileInputStream(infile), password.getBytes());
PDFStamper stamper = new PdfStamper(reader, outputstream);
stamper.close();
reader.close();
At the end I get the following exception:
java.lang.NullPointerException
at com.itextpdf.text.pdf.StandardDecryption.finish(StandardDecryption.java:102)
at com.itextpdf.text.pdf.PdfEncryption.decryptByteArray(PdfEncryption.java:776)
at com.itextpdf.text.pdf.PdfReader.getStreamBytesRaw(PdfReader.java:2634)
at com.itextpdf.text.pdf.PdfReader.getStreamBytesRaw(PdfReader.java:2650)
at com.itextpdf.text.pdf.PRStream.toPdf(PRStream.java:230)
at com.itextpdf.text.pdf.PdfIndirectObject.writeTo(PdfIndirectObject.java:158)
at com.itextpdf.text.pdf.PdfWriter$PdfBody.write(PdfWriter.java:403)
at com.itextpdf.text.pdf.PdfWriter$PdfBody.add(PdfWriter.java:381)
at com.itextpdf.text.pdf.PdfWriter.addToBody(PdfWriter.java:870)
at com.itextpdf.text.pdf.PdfStamperImp.close(PdfStamperImp.java:434)
at com.itextpdf.text.pdf.PdfStamperImp.close(PdfStamperImp.java:409)
at com.itextpdf.text.pdf.PdfStamper.close(PdfStamper.java:231)
The same pdf (PDF-1.4) file can be decrypted with itext version 2.1.7.5. With this we've never had any problem.
Am I missing something? Can this problem be solved in a simple way?

Related

what will be the alternative for Pdfstamper in itext7?

I tried to find the alternative for Pdfstamper in itext7 but didn't get how to use? I've already implemented code in itextshap its working but not in itext7.
I've one more doubt what will be the alternative for Acro Fields in itext7?
public byte[] GeneratePDF(string pdfPath, Dictionary<string, string> formFieldMap, bool formFlattening = true)
{
var output = new MemoryStream();
var reader = new PdfReader(pdfPath);
var stamper = new PdfStamper(reader, output);
//PdfDocument pdfDocument = new PdfDocument(reader, writer);
var formFields = stamper.AcroFields;
foreach (var fieldName in formFieldMap.Keys)
formFields.SetField(fieldName, formFieldMap[fieldName]);
stamper.FormFlattening = formFlattening;
stamper.Close();
reader.Close();
return output.ToArray();
}
The iText API got completely overhauled between versions 5.x and 7.x. Thus, you do not always have a one-to-one correspondence between classes here and there. Thus, I would propose studying the introductory ebooks on the iText knowledge base site before porting code.
There actually is an example in those ebooks very similar to your code:
//Initialize PDF document
PdfDocument pdf = new PdfDocument(new PdfReader(src), new PdfWriter(dest));
PdfAcroForm form = PdfAcroForm.GetAcroForm(pdf, true);
IDictionary<String, PdfFormField> fields = form.GetFormFields();
PdfFormField toSet;
fields.TryGetValue("name", out toSet);
toSet.SetValue("James Bond");
fields.TryGetValue("language", out toSet);
toSet.SetValue("English");
fields.TryGetValue("experience1", out toSet);
toSet.SetValue("Off");
fields.TryGetValue("experience2", out toSet);
toSet.SetValue("Yes");
fields.TryGetValue("experience3", out toSet);
toSet.SetValue("Yes");
fields.TryGetValue("shift", out toSet);
toSet.SetValue("Any");
fields.TryGetValue("info", out toSet);
toSet.SetValue("I was 38 years old when I became an MI6 agent.");
form.FlattenFields();
pdf.Close();
("Flattening a Form" in "Chapter 4: Making a PDF interactive | .NET" of "iText 7: Jump-Start Tutorial for .NET")

Unable to merge streams with PDFBox

Currently i am able to merge two PDF files when using java.io.File but unable to do merge them when using input and outputstreams.
Below the code works and generates merged PDF with success.
File mainDoc = new File(path...);
File additionalDoc = new File(path...);
PDFMergerUtility pdfMerger = new PDFMergerUtility();
pdfMerger.setDestinationFileName(path + "/merged.pdf");
pdfMerger.addSource(mainDoc);
pdfMerger.addSource(additionalDoc);
pdfMerger.mergeDocuments(null);
I then tried to do the same by using streams.
ByteArrayOutputStream out = new ByteArrayOutputStream();
InputStream mainDocStream = new FileInputStream(path...);
InputStream additionalDocSteam = new FileInputStream(path...);
PDFMergerUtility pdfMerger = new PDFMergerUtility();
pdfMerger.addSource(mainDocStream);
pdfMerger.addSource(additionalDocSteam);
pdfMerger.setDestinationStream(out);
pdfMerger.mergeDocuments(null);
The code above when reaching line pdfMerger.mergeDocuments(null); throws following exception :
java.io.IOException: Error: End-of-File, expected line at
org.apache.pdfbox.pdfparser.BaseParser.readLine(BaseParser.java:1119)
at
org.apache.pdfbox.pdfparser.COSParser.parseHeader(COSParser.java:2005)
at
org.apache.pdfbox.pdfparser.COSParser.parsePDFHeader(COSParser.java:1988)
at org.apache.pdfbox.pdfparser.PDFParser.parse(PDFParser.java:269)
at org.apache.pdfbox.pdmodel.PDDocument.load(PDDocument.java:1143)
at org.apache.pdfbox.pdmodel.PDDocument.load(PDDocument.java:1059)
at
org.apache.pdfbox.multipdf.PDFMergerUtility.mergeDocuments(PDFMergerUtility.java:263)
At last i tried to follow this answer (Merge Pdf Files Using PDFBox) as an example but my generated pdf does not seem to have merged those two pdfs.
This is the code that i tried.
public InputStream createPDF() {
try{
// Note, i have also tried to use java.io.File instead of an
// InputStream but the result was the same
// File mainDoc = new File(path...);
// PDDocument document = PDDocument.load(mainDoc);
InputStream pdfInputStream = null;
InputStream mainDocStream = new FileInputStream(path...);
PDDocument document = PDDocument.load(mainDocStream);
InputStream additionalDocSteam = new FileInputStream(path...);
PDDocument additionalDocument = PDDocument.load(additionalDocSteam);
PDFMergerUtility pdfMerger = new PDFMergerUtility();
pdfMerger.appendDocument(additionalDocument, document);
document.save(out);
document.close();
PDDocument.load(out.toByteArray());
pdfInputStream = new ByteArrayInputStream(out.toByteArray());
}catch(...){
....
}
return pdfInputStream;
}
The code above does generate a PDF but the newly created PDF contains only the content of the main document and not from the second one. So it looks that i am missing something and the documents are not merged.
I was able to find a solution, but i still cannot understand what is going wrong when using streams. In detail:
While the following code throws an exception (java.io.IOException: Error: End-of-File, expected line) :
ByteArrayOutputStream out = new ByteArrayOutputStream();
InputStream mainDocStream = new FileInputStream(path...);
InputStream additionalDocStream = new FileInputStream(path...);
PDFMergerUtility pdfMerger = new PDFMergerUtility();
pdfMerger.addSource(mainDocStream);
pdfMerger.addSource(additionalDocStream);
pdfMerger.setDestinationStream(out);
pdfMerger.mergeDocuments(null);
When using a File in the addSource method, everything seems to work as required.
public InputStream createPDF() {
InputStream pdfInputStream = null;
try{
File mainDoc = new File(...);
File additionalDoc = new File(path...);
PDFMergerUtility pdfMerger = new PDFMergerUtility();
pdfMerger.addSource(mainDoc);
pdfMerger.addSource(additionalDoc);
pdfMerger.setDestinationStream(out);
pdfMerger.mergeDocuments(null);
pdfInputStream = new ByteArrayInputStream(out.toByteArray());
}catch(...){
...
}
return pdfInputStream;
}
Now, why the first approach using streams throws an exception while using directly the file works, is something i would also like to know.

Insert pages into PDF

Is there any function like Document.InsertPage(pageIndex)? Or any alternative solution?
What you are looking for is PdfStamper.insertPage(int, Rectangle).
See a full example of how to use it here, but in short, it should boil down to:
PdfReader reader = new PdfReader(src);
PdfStamper stamper = new PdfStamper(reader, new FileOutputStream(dest));
stamper.insertPage(pageIndex, reader.getPageSizeWithRotation(1));
// insert content via stamper.getUnderContent() or stamper.getOverContent()
stamper.close();
reader.close();
Note that this is Java code, but the C# counterpart can be deduced quite easily.

Certify XFA document using iTextSharp

I'm using iTextSharp 5.5.2 and I want to certify an XFA document with a digital certificate.
My code looks as follows:
PdfReader reader = new PdfReader(path);
FileStream os = new FileStream(dest, FileMode.Create);
PdfStamper stamper = PdfStamper.createXmlSignature(reader, os);
XmlSignatureAppearance appearance = stamper.XmlSignatureAppearance;
appearance.SetXmlLocator(new XfaXmlLocator(stamper));
appearance.SetXpathConstructor(new XfaXpathConstructor(XfaXpathConstructor.XdpPackage.Datasets)); // Optional Line
appearance.SetCertificate(myCert);
var pk = Org.BouncyCastle.Security.DotNetUtilities.GetKeyPair(myCert.PrivateKey).Private;
IExternalSignature pks = new PrivateKeySignature(pk, DigestAlgorithms.SHA1);
MakeXmlSignature.SignXmlDSig(appearance, pks, GenerateKeyInfo(myChain));
Unfortunately, when I open the PDF after certification, it pops up that the "verify operation failed."
If I comment out the optional line related to the XfaXpathConstructor, I get the banner message along the type of the PDF that says that "At least one data signature is invalid".
Either way, I am unable to open the Signature Panel and the PDF does not successfully certify... What am I missing?

Existing PDF to PDF/A "conversion"

I am trying to make an existing pdf into pdf/a-1b. I understand that itext cannot convert a pdf to pdf/a in the sense making it pdf/a compliant. But it definitely can flag the document as pdf/a. However, I looked at various examples and I cannot seem to figure out how to do it. The major problem is that
writer.PDFXConformance = PdfWriter.PDFA1B;
does not work anymore. First PDFA1B is not recognized, second, pdfwriter seems to have been rewritten and there is not much information about that.
It seems the only (in itext java version) way is:
PdfAWriter writer = PdfAWriter.getInstance(document, new FileOutputStream(filename), PdfAConformanceLevel.PDF_A_1B);
But that requires a document type, ie. it can be used when creating a pdf from scratch.
Can someone give an example of pdf to pdf/a conversion with the current version of itextsharp?
Thank you.
I can't imagine a valid reason for doing this but apparently you have one.
The conformance settings in iText are intended to be used with a PdfWriter and that object is (generally) only intended to be used with new documents. Since iText was never intended to convert documents to conformance that's just the way it was built.
To do what you want to do you could either just open the original document and update the appropriate tags in the document's dictionary or you could create a new document with the appropriate entries set and then import your old document. The below code shows the latter route, it first creates a regular non-conforming PDF and then creates a second document that says it is conforming even though it may or may not. See the code comments for more details. This targets iTextSharp 5.4.2.0.
//Folder that we're working from
var workingFolder = Environment.GetFolderPath(Environment.SpecialFolder.Desktop);
//Create a regular non-conformant PDF, nothing special below
var RegularPdf = Path.Combine(workingFolder, "File1.pdf");
using (var fs = new FileStream(RegularPdf, FileMode.Create, FileAccess.Write, FileShare.None)) {
using (var doc = new Document()) {
using (var writer = PdfWriter.GetInstance(doc, fs)) {
doc.Open();
doc.Add(new Paragraph("Hello world!"));
doc.Close();
}
}
}
//Create our conformant document from the above file
var ConformantPdf = Path.Combine(workingFolder, "File2.pdf");
using (var fs = new FileStream(ConformantPdf, FileMode.Create, FileAccess.Write, FileShare.None)) {
using (var doc = new Document()) {
//Use PdfSmartCopy to get every page
using (var copy = new PdfSmartCopy(doc, fs)) {
//Set our conformance levels
copy.SetPdfVersion(PdfWriter.PDF_VERSION_1_3);
copy.PDFXConformance = PdfWriter.PDFX1A2001;
//Open our new document for writing
doc.Open();
//Bring in every page from the old PDF
using (var r = new PdfReader(RegularPdf)) {
for (var i = 1; i <= r.NumberOfPages; i++) {
copy.AddPage(copy.GetImportedPage(r, i));
}
}
//Close up
doc.Close();
}
}
}
Just to be 100% clear, this WILL NOT MAKE A CONFORMANT PDF, just a document that says it conforms.