Search code examples
javapdfitextpdf-generationpdfa

iText difference between PdfCopy and PdfACopy


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!


Solution

  • 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;
    
    }