Search code examples
javapdfbox

PDFBox: Validation of created PDF/A-3A document with attachment fails with stream length mismatch


I'm trying to create a PDF/A-3A file with an attached plaint text file using the example CreatePDFA but the validation of the resulting file fails using VeraPDF validator. I'm using PDFBox v.3.0.0 RC1.

Error: The value of the Length key specified in the stream dictionary shall match the number of bytes in the file following the LINE FEED (0Ah) character after the stream keyword and preceding the EOL marker before the endstream keyword.

Error location is: root/indirectObjects[0](22 0)/directObject[0]

How can I add the correct length to the PDF file? The attachment code is as follows:

    private void attachFile(PDDocument doc, File file, String mediaType, String description) throws IOException {

        long fileSize = file.length();
        BasicFileAttributes fileAttr = Files.readAttributes(file.toPath(), BasicFileAttributes.class);

        GregorianCalendar creationTimeCal = new GregorianCalendar();
        creationTimeCal.setTimeInMillis(fileAttr.creationTime().toMillis());

        GregorianCalendar modifiedTimeCal = new GregorianCalendar();
        modifiedTimeCal.setTimeInMillis(fileAttr.lastModifiedTime().toMillis());

        // embedded files are stored in a named tree
        PDEmbeddedFilesNameTreeNode efTree = new PDEmbeddedFilesNameTreeNode();

        // first create the file specification, which holds the embedded file
        PDComplexFileSpecification fs = new PDComplexFileSpecification();

        // use both methods for backwards, cross-platform and cross-language compatibility.
        fs.setFile(file.getName());
        fs.setFileUnicode(file.getName());

        COSDictionary dict = fs.getCOSObject();
        dict.setName("AFRelationship", "Alternative");

        try (InputStream is = Files.newInputStream(file.toPath(), StandardOpenOption.READ)) {

            PDEmbeddedFile ef = new PDEmbeddedFile(doc, is);

            // now lets some of the optional parameters
            ef.setSubtype(mediaType);
            ef.setSize((int) fileSize);
            ef.setCreationDate(creationTimeCal);
            ef.setModDate(modifiedTimeCal);
            ef.setDecodedStreamLength((int) fileSize);

            // use both methods for backwards, cross-platform and cross-language compatibility.
            fs.setEmbeddedFile(ef);
            fs.setEmbeddedFileUnicode(ef);
            fs.setFileDescription(StringUtils.defaultString(description, file.getName()));

            // create a new tree node and add the embedded file
            String attachmentName = StringUtils.defaultString(file.getName(),description);
            PDEmbeddedFilesNameTreeNode treeNode = new PDEmbeddedFilesNameTreeNode();
            treeNode.setNames(Collections.singletonMap(attachmentName, fs));

            // add the new node as kid to the root node
            List<PDEmbeddedFilesNameTreeNode> kids = new ArrayList<>();
            kids.add(treeNode);
            efTree.setKids(kids);

            // add the tree to the document catalog
            PDDocumentNameDictionary names = new PDDocumentNameDictionary(doc.getDocumentCatalog());
            names.setEmbeddedFiles(efTree);
            doc.getDocumentCatalog().setNames(names);

            // AF entry (Array) in catalog with the FileSpec
            COSArray cosArray = new COSArray();
            cosArray.add(fs);
            doc.getDocumentCatalog().getCOSObject().setItem("AF", cosArray);

            // show attachments panel in some viewers
            doc.getDocumentCatalog().setPageMode(PageMode.USE_ATTACHMENTS);
        }
    }

The PDF file can be found here: https://gofile.io/d/FuWIdV


Solution

  • The latest version 3.0.0-alpha2 of PdfBox seems to resolve this problem.