Pdfbox - 添加pdf嵌入式文件并将PDDocument保存到OutputStream不保留嵌入式文件

时间:2015-01-16 11:43:08

标签: pdf attachment pdfbox

我正在使用Pdfbox(1.8.8)向pdf添加附件。我的问题是,当其中一个附件是.pdf类型并且我将PDDocument保存到OutputStream时,最终的pdf文档不包含附件。如果将PDDocument保存到文件而不是OutputStream都可以正常工作,如果附件不包含任何pdf,则保存到文件或OutputStream都可以正常工作。

我想知道是否有任何方法可以添加pdf嵌入式文件并将PDDocument保存到OutputStream,从而将附加文件保存在生成​​的最终pdf中。

我正在使用的代码是:

 private void insertAttachments(OutputStream out, ArrayList<Attachment> attachmentsResources) {

            final PDDocument doc;
            Boolean hasPdfAttach = false;
            try {
                doc = PDDocument.load(new ByteArrayInputStream(((ByteArrayOutputStream) out).toByteArray()));
                // final PDFTextStripper pdfStripper = new PDFTextStripper();
                // final String text = pdfStripper.getText(doc);
                final PDEmbeddedFilesNameTreeNode efTree = new PDEmbeddedFilesNameTreeNode();
                final Map embeddedFileMap = new HashMap();
                PDEmbeddedFile embeddedFile;
                File file = null;

                for (Attachment attach : attachmentsResources) {

                    // first create the file specification, which holds the embedded file
                    final PDComplexFileSpecification fileSpecification = new PDComplexFileSpecification();
                    fileSpecification.setFile(attach.getFilename());
                    file = AttachmentUtils.getAttachmentFile(attach);
                    final InputStream is = new FileInputStream(file.getAbsolutePath());

                    embeddedFile = new PDEmbeddedFile(doc, is);
                    // set some of the attributes of the embedded file
                    if ("application/pdf".equals(attach.getMimetype())) {
                        hasPdfAttach = true;
                    }
                    embeddedFile.setSubtype(attach.getMimetype());
                    embeddedFile.setSize((int) (long) attach.getFilesize());
                    fileSpecification.setEmbeddedFile(embeddedFile);

                    // now add the entry to the embedded file tree and set in the document.
                    embeddedFileMap.put(attach.getFilename(), fileSpecification);
                    // final String text2 = pdfStripper.getText(doc);
                }
                // final String text3 = pdfStripper.getText(doc);
                efTree.setNames(embeddedFileMap);
                // ((COSDictionary) efTree.getCOSObject()).removeItem(COSName.LIMITS); (this not work for me)
                // attachments are stored as part of the "names" dictionary in the document catalog
                final PDDocumentNameDictionary names = new PDDocumentNameDictionary(doc.getDocumentCatalog());
                names.setEmbeddedFiles(efTree);
                doc.getDocumentCatalog().setNames(names);
                // final ByteArrayOutputStream pdfboxToDocumentStream = new ByteArrayOutputStream();
                final String tmpfile = "temporary.pdf";
                if (hasPdfAttach) {
                    final File f = new File(tmpfile);
                    doc.save(f);
                    doc.close();
                     //i have try with parser but without success too
                    // PDFParser parser = new PDFParser(new FileInputStream(tmpfile));
                    // parser.parse();
                    // PDDocument doc2 = parser.getPDDocument();
                    final PDDocument doc2 = PDDocument.loadNonSeq(f, new RandomAccessFile(new File(getHomeTMP()
                            + "tempppp.pdf"), "r"));
                    doc2.save(out);
                    doc2.close();
                } else {
                    doc.save(out);
                    doc.close();
                }
                 //that does not work too
                // final InputStream in = new FileInputStream(tmpfile);
                // IOUtils.copy(in, out);
                // out = new FileOutputStream(tmpFile);
                // doc.save (out);

            } catch (IOException e1) {
                e1.printStackTrace();
            } catch (Exception e2) {
                e2.printStackTrace();
            }
        }
 

祝你好运

解决方案:

private void insertAttachments(OutputStream out, ArrayList<Attachment> attachmentsResources) {

    final PDDocument doc;
    try {
        doc = PDDocument.load(new ByteArrayInputStream(((ByteArrayOutputStream) out).toByteArray()));
        ((ByteArrayOutputStream) out).reset();
        final PDEmbeddedFilesNameTreeNode efTree = new PDEmbeddedFilesNameTreeNode();
        final Map embeddedFileMap = new HashMap();
        PDEmbeddedFile embeddedFile;
        File file = null;

        for (Attachment attach : attachmentsResources) {

            // first create the file specification, which holds the embedded file
            final PDComplexFileSpecification fileSpecification = new PDComplexFileSpecification();
            fileSpecification.setFile(attach.getFilename());
            file = AttachmentUtils.getAttachmentFile(attach);
            final InputStream is = new FileInputStream(file.getAbsolutePath());

            embeddedFile = new PDEmbeddedFile(doc, is);
            // set some of the attributes of the embedded file
            embeddedFile.setSubtype(attach.getMimetype());
            embeddedFile.setSize((int) (long) attach.getFilesize());
            fileSpecification.setEmbeddedFile(embeddedFile);

            // now add the entry to the embedded file tree and set in the document.
            embeddedFileMap.put(attach.getFilename(), fileSpecification);

        }
        efTree.setNames(embeddedFileMap);
        ((COSDictionary) efTree.getCOSObject()).removeItem(COSName.LIMITS);
        // attachments are stored as part of the "names" dictionary in the document catalog
        final PDDocumentNameDictionary names = new PDDocumentNameDictionary(doc.getDocumentCatalog());
        names.setEmbeddedFiles(efTree);
        doc.getDocumentCatalog().setNames(names);
        ((COSDictionary) efTree.getCOSObject()).removeItem(COSName.LIMITS);
        doc.save(out);
        doc.close();

    } catch (IOException e1) {
        e1.printStackTrace();
    } catch (Exception e2) {
        e2.printStackTrace();
    }
}

1 个答案:

答案 0 :(得分:3)

您可以在out

中的原始PDF之后存储新的PDF

查看方法中out的所有用法:

private void insertAttachments(OutputStream out, ArrayList<Attachment> attachmentsResources) {
    ...
            doc = PDDocument.load(new ByteArrayInputStream(((ByteArrayOutputStream) out).toByteArray()));
    ...
                doc2.save(out);
    ...
                doc.save(out);

因此,您输入ByteArrayOutputStream并将其当前内容作为输入(即ByteArrayOutputStream不为空,但已包含PDF),经过一些处理后,您将修改后的PDF附加到{ {1}}。根据您提供的PDF查看器,您将显示原始PDF或操作的PDF或文件是垃圾的(非常正确的)错误消息。

如果您希望ByteArrayOutputStream仅包含受操纵的PDF,只需添加

即可
ByteArrayOutputStream

或(如果您不确定流的状态)

((ByteArrayOutputStream) out).reset();

之后

out = new ByteArrayOutputStream();

PS:根据评论,OP尝试了上述修改后的代码,但没有成功。

我无法运行问题中提供的代码,因为它不是自包含的。因此,我将其简化为必要的测试:

doc = PDDocument.load(new ByteArrayInputStream(((ByteArrayOutputStream) out).toByteArray()));

如您所见,此处PDFBox仅使用流。结果:

Adobe Reader screenshot showing "attachment.pdf" with attachment "artificial text.pdf"

因此,没有问题的PDFBox存储了嵌入PDF文件附件的PDF。

因此,问题很可能与此工作流无关