0
votes

I wrote a function to embed a file as attachment inside a PDF/A-3a document using iText 5.5.13 (using instructions from iText tutorials).

If I attach the file using the class PdfCopy, the result is a correct PDF file, but it does not claim to be PDF/A (maybe it matches all the requirements, but it doesn't say).

If I do the same using PdfACopy, I get an wrongly built document:

InvalidPdfException: Rebuild failed: trailer not found.; Original message: PDF startxref not found.

Here is my code a little simplified. Commented is the line to use a PdfCopy instead.

public static File embedFile(File inputPdf) {

    File outputPdf = new File("./test.pdf");

    PdfReader reader = new PdfReader(inputPdf.getAbsolutePath());
    Document document = new com.itextpdf.text.Document();
    OutputStream os = new FileOutputStream(outputPdf.getAbsolutePath());
    PdfACopy copy = new PdfACopy(document, os, PdfAConformanceLevel.PDF_A_3A); // Output doc doesn't work
    // PdfCopy copy = new PdfCopy(document, os); // Output doc works but doesn't claim to be PDF/A

    document.open();
    copy.addDocument(reader);

    // Include attachment (extactly as in the sample tutorial)
    PdfDictionary parameters = new PdfDictionary();
    parameters.put(PdfName.MODDATE, new PdfDate());
    PdfFileSpecification fileSpec = PdfFileSpecification.fileEmbedded(
        writer, "./src/main/resources/com/itextpdf/invoice.xml",
        "invoice.xml", null, "application/xml", parameters, 0);
    fileSpec.put(new PdfName("AFRelationship"), new PdfName("Data"));
    writer.addFileAttachment("invoice.xml", fileSpec);
    PdfArray array = new PdfArray();
    array.add(fileSpec.getReference());
    writer.getExtraCatalog().put(new PdfName("AF"), array);

    os.flush();
    reader.close();
    document.close();
    os.close();
    copy.close();

    return outputPdf;
}

The input file is already a PDF/A-3a document, so I think I don't need to redefine all the required things like embedded fonts, output intent...

Is there maybe a missing step that is mandatory when using PdfACopy that is not required with PdfCopy?

Would it help to try with iText 7?

Many thanks in advance!

1
You have a PDF/A-3a document with the a of accessibility. Concatenating accessible PDF's wasn't implemented up until iText 7 and you're using iText 5.Bruno Lowagie
Is not that I want to concatenate, but I think this is the only way in order to add an attachment to an existing PDF. Do you know if the attachment can be added without concatenating in iText 5? If not, I will try with iText 7Daniel Rodríguez
It works as a charm in iText 7. Many thanks @BrunoLowagie!!Daniel Rodríguez

1 Answers

0
votes

As pointed by Bruno Lowagie in the comments, this is possible with iText 7. Here the function in case it helps someone:

public static File embedFile(File inputPdf, File embeddedFile, String embeddedFileName, String embeddedFileMimeType)
        throws IOException {

    File outputPdf = new File("./test.pdf");

    PdfReader reader = new PdfReader(inputPdf.getAbsolutePath());
    PdfWriter writer = new PdfWriter(outputPdf.getAbsolutePath());
    PdfADocument pdfDoc = new PdfADocument(reader, writer);

    // Add attachment
    PdfDictionary parameters = new PdfDictionary();
    parameters.put(PdfName.ModDate, new PdfDate().getPdfObject());
    PdfFileSpec fileSpec = PdfFileSpec.createEmbeddedFileSpec(pdfDoc, embeddedFile.getAbsolutePath(), embeddedFileName,
            embeddedFileName, new PdfName(embeddedFileMimeType), parameters, PdfName.Data);
    fileSpec.put(new PdfName("AFRelationship"), new PdfName("Data"));
    pdfDoc.addFileAttachment(embeddedFileName, fileSpec);
    PdfArray array = new PdfArray();
    array.add(fileSpec.getPdfObject().getIndirectReference());
    pdfDoc.getCatalog().put(new PdfName("AF"), array);

    pdfDoc.close();
    reader.close();
    writer.close();

    return outputPdf;

}