Невозможно скопировать косвенный объект из документа, который пишется Java - PullRequest
0 голосов
/ 16 октября 2019

Я создал метод, подобный следующему:

  public PdfDocument addBlankPage(final MediaModel pdfDocument) throws IOException {

    final InputStream inputStream = mediaService.getStreamFromMedia(pdfDocument);
    byte[] bytes = IOUtils.toByteArray(inputStream);
    final PdfReader reader = new PdfReader(new ByteArrayInputStream(bytes));
    final PdfWriter writer = new PdfWriter(pdfDocument.getRealFileName());
    final PdfDocument document = new PdfDocument(reader, writer);
    int index = document.getNumberOfPages();
    final PageSize ps = new PageSize(document.getFirstPage().getPageSize());
    document.addNewPage(index + 1, ps);
    reader.close();
    writer.close();
    return document;

}

Чтобы добавить новую пустую страницу в PdfDocument, она выглядит хорошо, и ее «кажется» работает. Однако, когда я пытаюсь объединить документ PDF с пустой страницей (добавленной моим методом) с другими существующими документами PDF в этом методе:

 public .... {

    ByteArrayOutputStream mergedPdfStream = new ByteArrayOutputStream();
    PdfDocument mergedPdf = new PdfDocument(new PdfWriter(mergedPdfStream));

    for (PdfDocument doc : pdfDocuments) {
        int n = doc.getNumberOfPages();

        for (int i = 1; i <= n; i++) {

            PdfPage page = doc.getPage(i).copyTo(mergedPdf);
            mergedPdf.addPage(page);

        }
    }
    ....

}

Он выдает:

 com.itextpdf.kernel.PdfException: Cannot copy indirect object from the document that is being written.
at com.itextpdf.kernel.pdf.PdfObject.copyTo(PdfObject.java:318) ~[kernel-7.1.1.jar:?]
at com.itextpdf.kernel.pdf.PdfDictionary.copyTo(PdfDictionary.java:443) ~[kernel-7.1.1.jar:?]
at com.itextpdf.kernel.pdf.PdfPage.copyTo(PdfPage.java:379) ~[kernel-7.1.1.jar:?]
at com.itextpdf.kernel.pdf.PdfPage.copyTo(PdfPage.java:364) ~[kernel-7.1.1.jar:?]

Iпогуглил, и я не нашел никакой соответствующей информации. Любой намек?

PD: Я на 100% уверен, что мой метод виноват, потому что когда я объединяю другие PDF-файлы без использования метода пустой страницы, он всегда работает ..

1 Ответ

1 голос
/ 17 октября 2019

То, что вы наблюдали в этом и в вашем предыдущем вопросе, связано с особенностью класса iText PdfDocument: хотя он представляет документ PDF, он не хранит все его в памятиили в каком-то доступном хранилище. В частности, если вы добавляете к нему контент, этот новый контент по умолчанию выгружается из памяти в PdfWriter как можно скорее, делая его недоступным для PdfDocument.

Это позволяет вам сохранитьобъем памяти довольно низкий при создании больших PDF-файлов с помощью iText, что может быть очень актуально в приложениях с высокой пропускной способностью.

Недостатком является то, что существуют ограничения на использование экземпляров PdfDocument;в частности, вы не можете свободно копировать из экземпляров, которые были записаны, поскольку текущее состояние копируемых данных может больше не быть доступным.

Чтобы предотвратить копирование противоречивых данных, iText запрещает копирование из PdfDocument экземпляров. куда можно записать, т. е. которые имеют PdfWriter.

Таким образом,

  • , если вы хотите скопировать из aдокумент, PdfDocument необходимо инициализировать без a PdfWriter;
  • , если вы хотите (нетривиально) изменить документ, PdfDocument необходимо инициализировать с a PdfWriter;
  • , поэтому, если вы хотите изменить и скопировать из документ, вы не можете использоватьодин и тот же PdfDocument экземпляр для обоих действий!

Поэтому для вашего случая использования вы должны

  • либо взять вывод PdfDocument с PdfWriter после применения изменений и использования его в качестве ввода PdfDocument без PdfWriter для копирования с;
  • или открытия двух отдельныхPdfDocument экземпляры из исходного файла, один с и один без PdfWriter, и применить изменения к первому и скопировать со второго.

Первый вариант необходим, если данные, которые выхочу скопировать должен содержать изменения, которые вы применяете. Последнее необходимо, если они не содержат их. Если вам все равно, или если вы знаете, что на скопированные данные не влияют изменения, любой из этих вариантов подходит.


В вашем случае вы копируете все страницы из всех документов в pdfDocumentsв целевой документ, поэтому, в частности, вы хотите, чтобы внесенные изменения также были скопированы в целевой документ. Таким образом, применяется первый вариант, вам нужно взять вывод PdfDocument с PdfWriter после применения изменений и использовать его в качестве ввода PdfDocument без PdfWriter для копирования.

Вы можете сделать это, изменив addBlankPage следующим образом:

public PdfDocument addBlankPage(final MediaModel pdfDocument) throws IOException {
    try (   InputStream inputStream = mediaService.getStreamFromMedia(pdfDocument);
            PdfReader reader = new PdfReader(inputStream);
            PdfWriter writer = new PdfWriter(pdfDocument.getRealFileName());
            PdfDocument document = new PdfDocument(reader, writer)) {
        document.addNewPage(document.getFirstPage().getPageSize());
    }
    return new PdfDocument(new PdfReader(pdfDocument.getRealFileName()));
}

или если вы на самом деле не хотите записывать PDF-файл в файловую систему:

public PdfDocument addBlankPage(final MediaModel pdfDocument) throws IOException {
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    try (   InputStream inputStream = mediaService.getStreamFromMedia(pdfDocument);
            PdfReader reader = new PdfReader(inputStream);
            PdfWriter writer = new PdfWriter(baos);
            PdfDocument document = new PdfDocument(reader, writer)) {
        document.addNewPage(document.getFirstPage().getPageSize());
    }
    return new PdfDocument(new PdfReader(new ByteArrayInputStream(baos.toByteArray())));
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...