2015-01-16 1 views
1

Я использую Pdfbox (1.8.8) для добавления вложений в pdf. Моя проблема в том, что одно из вложений имеет тип .pdf и я сохраняю PDDocument в OutputStream, в окончательный документ PDF не входят вложения. Если сохранить файл PDDocument в файл, то OutputStream все будет работать нормально, и если вложения не содержат никакого PDF-файла, то сохранение в файл или OutputStream будет прекрасным.Pdfbox - добавление pdf вложенного файла и сохранение PDDocument в 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(); 
    } 
} 
+0

Вы уверены, что вы закрываете «из» правильно? Я посмотрел исходный код, сохранил (файл) вызовы save (новый FileOutputStream (файл)). –

+0

Привет @TilmanHausherr да, после вызова функции im с использованием out.flush(); и out.close(); –

ответ

3

Вы сохраняете новый PDF после оригинального PDF в out:

Посмотрите на все виды использования 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 в ByteArrayOutputStream. В зависимости от программы просмотра PDF, которую вы представляете, вам будет показано либо исходное, либо управляемое PDF-сообщение, либо (очень правильное) сообщение об ошибке, что файл является мусором.

Если вы хотите ByteArrayOutputStream содержать только манипулируют PDF, просто добавьте

((ByteArrayOutputStream) out).reset(); 

или (если вы не уверены, о состоянии потока)

out = new ByteArrayOutputStream(); 

сразу после

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

PS: Accordin g к комментариям, ПП безуспешно пробовал вышеуказанные предложенные изменения в своем коде.

Я не могу запустить код, представленный в вопросе, потому что он не является автономным. Таким образом, я свел ее к основам, чтобы получить автономный тест:

@Test 
public void test() throws IOException, COSVisitorException 
{ 
    ByteArrayOutputStream baos = new ByteArrayOutputStream(); 
    try (
      InputStream sourceStream = getClass().getResourceAsStream("test.pdf"); 
      InputStream attachStream = getClass().getResourceAsStream("artificial text.pdf")) 
    { 
     final PDDocument document = PDDocument.load(sourceStream); 

     final PDEmbeddedFile embeddedFile = new PDEmbeddedFile(document, attachStream); 
     embeddedFile.setSubtype("application/pdf"); 
     embeddedFile.setSize(10993); 

     final PDComplexFileSpecification fileSpecification = new PDComplexFileSpecification(); 
     fileSpecification.setFile("artificial text.pdf"); 
     fileSpecification.setEmbeddedFile(embeddedFile); 

     final Map<String, PDComplexFileSpecification> embeddedFileMap = new HashMap<String, PDComplexFileSpecification>(); 
     embeddedFileMap.put("artificial text.pdf", fileSpecification); 

     final PDEmbeddedFilesNameTreeNode efTree = new PDEmbeddedFilesNameTreeNode(); 
     efTree.setNames(embeddedFileMap); 

     final PDDocumentNameDictionary names = new PDDocumentNameDictionary(document.getDocumentCatalog()); 
     names.setEmbeddedFiles(efTree); 
     document.getDocumentCatalog().setNames(names); 

     document.save(baos); 
     document.close(); 
    } 
    Files.write(Paths.get("attachment.pdf"), baos.toByteArray()); 
} 

Как вы видите PDFBox здесь используются только потоки. Результат:

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

Таким образом, PDFBox без проблем сохраняет PDF, в которую он внедренный вложение PDF файла.

Проблема, таким образом, скорее всего, не имеют ничего общего с этим рабочим потоком в такой

+0

Здравствуйте, mkl, Спасибо, ваши предположения совершенно правы. Ну, создание этого «tempppp.pdf» является одним из способов заставить его работать правильно (тестирование), потому что, как я сказал в этом вопросе, когда я сохраняю PDDocument в файл («tempppp.pdf» в этом case) он создает окончательный pdf-документ со всеми вложениями, но когда я сохраняю PDDocument в OutputStream, окончательный pdf-файл не содержит вложений. Я попробовал ваше предложение, но оно не сработало, окончательный pdf, сгенерированный при сохранении документа в OutputStream, не содержит вложений .. «tempppp.pdf» содержит все прикрепленные файлы. –

+0

* «tempppp.pdf» содержит все вложения * - это интересно ... потому что вы нигде не сохраняете этот файл. – mkl

+0

В соответствии с вашим кодом переменная 'tmpfile' содержит ** tempor.pdf **, а не ** tempppp.pdf **. Итак ... вы нигде не сохраняете этот файл ** tempppp.pdf **. – mkl