当前位置: 首页 > 知识库问答 >
问题:

无法从正在编写的文档中复制间接对象Java

宗项禹
2023-03-14

我创建了这样一个方法:

  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:?]

我谷歌了一下,没有找到任何相关信息。有什么提示吗?

PD:我100%确信我的方法是有罪的,因为当我合并其他PDF而不使用空白页方法时,它总是有效的。

共有1个答案

广绪
2023-03-14

您在这个问题和之前的问题中观察到的是由于iTextPdfDocument类的一个特性:虽然它确实表示一个PDF文档,但它并没有将所有文档保存在内存或一些可访问的存储中。特别是如果您向其添加内容,默认情况下,新内容会尽快刷新内存溢出到PdfWriter,使PdfDocument无法访问它。

这使您能够在使用iText创建大型PDF的同时保持相当低的内存占用,这在高通量应用程序中非常重要。

缺点是PdfDocument实例的使用受到限制;尤其是,由于要复制的数据的当前状态可能不再可检索,因此无法从已写入的实例中自由复制。

为防止复制不一致的数据,iText禁止从可写入的PdfDocument实例(即具有PdfWriter的实例)复制数据。

因此

  • 如果要从文档中复制,则需要在不使用PdfWriter的情况下初始化PdfDocument
  • 如果您想(非常简单地)更改文档,PdfDocument需要用PdfWriter初始化
  • 因此,如果您想从文档中进行更改和复制,就不能对这两个操作使用相同的PdfDocument实例

因此,对于您的用例,您必须

  • 在应用更改后,使用PdfWriter获取PdfDocument的输出,并将其用作PdfDocument的输入,而不使用PdfWriter进行复制
  • 或者从源文件中打开两个独立的PdfDocument实例,一个带有PdfWriter,另一个没有PdfWriter>,然后将更改应用于第一个实例,并从第二个实例复制

如果您要复制的数据包含您所应用的更改,前一个选项是必要的。如果它们不包含更改,后者是必要的。如果您不关心任何一种方式,或者如果您知道复制的数据不受更改的影响,任何一个选项都是可以的。

在本例中,您将pdfDocuments中所有文档的所有页面复制到目标文档中,因此您尤其希望您应用的更改也复制到目标文档中。因此,前一个选项适用,在应用更改后,您必须使用PdfWriter获取PdfDocument的输出,并将其用作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())));
}

 类似资料:
  • 问题内容: 我想用itext 7生成pdf,但是我们发生了一些错误: 我的生成代码: 我在itext7中唯一的样式代码: 将在服务构造函数中初始化init: 我尝试将我的字体设置为 static ,但是不起作用。 这是地方抛出异常: 这意味着我有两个不同的文档,但是我不知道何时创建另一个文档。在此先感谢您的建议。 问题答案: 我本人也遇到过同样的问题(花了我几个小时才能发现我做错了什么)。事实证明

  • 我想写这样的东西: 正如你所看到的,我不能只写像<代码>这样的东西。文档(id),因为我使用了查询对象(where调用)。 我已经看到了这个问题的一些答案,但不是Java。事实上: https://stackoverflow.com/a/52252264/6500085

  • 我了解到,当您在Java中修改变量时,它不会改变它所基于的变量 我对对象也假设了类似的情况。考虑一下这个类。 在我试过这个代码后,我搞糊涂了。

  • 作为开放平台,必须要提供API文档。 SOP采用微服务架构实现,因此文档应该由各个微服务各自实现。难点就是如何统一归纳各个微服务端提供的文档信息,并且统一展示。 写完接口后使用swagger注解来定义自己的文档信息。步骤如下: maven添加swagger <!-- swagger2 --> <dependency> <groupId>io.springfox</groupId>

  • 我想生成一个pdf与itext7,但一些错误发生在我们身上: 我的生成代码: itext7中我唯一的样式代码: 将在服务构造函数中调用init: 我试过将字体设置为静态,但不起作用。 这是地方抛异常: 这意味着我有两个不同的文件,但我不知道我什么时候创建了另一个文件。提前感谢您的建议。