无法从正在写入的文档中复制间接对象 Java
Cannot copy indirect object from the document that is being written Java
我创建了一个这样的方法:
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 添加一个新的空白页,它看起来很好并且 "seems" 可以工作。但是,当我尝试将带有空白页(通过我的方法添加)的 PdfDocument 与此方法中的其他现有 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 时,它总是有效..
您在这个问题和您的 问题中观察到的是由于 iText PdfDocument
class 的特殊性:虽然它确实表示 PDF 文档,但它不将所有内容保存在内存或一些可访问的存储中。特别是如果你向它添加内容,这个新内容默认情况下会尽快从内存中刷新到 PdfWriter
,从而使 PdfDocument
.
无法访问它
这使您能够在使用 iText 创建大型 PDF 时保持相当低的内存占用,这在高吞吐量应用程序中非常重要。
缺点是PdfDocument
个实例的使用有限制;特别是您不能从已写入的实例中自由复制,因为要复制的数据的当前状态可能无法再检索。
为了防止您复制不一致的数据,iText 不允许从 PdfDocument
可以写入 的实例进行复制,即具有 PdfWriter
。
因此,
- 如果你想复制一个文件,
PdfDocument
需要初始化没有一个PdfWriter
;
- 如果你想(非平凡地)改变一个文件,
PdfDocument
需要用初始化PdfWriter
;
- 所以如果你想改变和复制自一个文档,你不能对两者使用相同的
PdfDocument
实例动作!
因此,对于您的用例,您必须
- 要么在应用更改后使用
PdfWriter
获取 PdfDocument
的输出,并将其用作 PdfDocument
的输入,而无需 PdfWriter
进行复制;
- 或者从源文件中打开两个单独的
PdfDocument
实例,一个有一个 PdfWriter
,一个没有 PdfWriter
,然后将更改应用到第一个并从第二个复制。
如果您要复制的数据应包含您应用的更改,则前一个选项是必需的。如果它们不包含它们,则后者是必要的。如果您不关心任何一种方式,或者如果您知道复制的数据不受更改的影响,那么任何一个选项都可以。
在您的情况下,您将 pdfDocuments
中所有文档的所有页面复制到目标文档,因此您特别希望将应用的更改也复制到目标文档。因此,前一个选项适用,您必须在应用更改后 使用 PdfWriter
获取 PdfDocument
的输出,并将其用作没有 [=] 的 PdfDocument
的输入13=] 从中复制。
您可以像这样更改 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())));
}
我创建了一个这样的方法:
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 添加一个新的空白页,它看起来很好并且 "seems" 可以工作。但是,当我尝试将带有空白页(通过我的方法添加)的 PdfDocument 与此方法中的其他现有 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 时,它总是有效..
您在这个问题和您的 PdfDocument
class 的特殊性:虽然它确实表示 PDF 文档,但它不将所有内容保存在内存或一些可访问的存储中。特别是如果你向它添加内容,这个新内容默认情况下会尽快从内存中刷新到 PdfWriter
,从而使 PdfDocument
.
这使您能够在使用 iText 创建大型 PDF 时保持相当低的内存占用,这在高吞吐量应用程序中非常重要。
缺点是PdfDocument
个实例的使用有限制;特别是您不能从已写入的实例中自由复制,因为要复制的数据的当前状态可能无法再检索。
为了防止您复制不一致的数据,iText 不允许从 PdfDocument
可以写入 的实例进行复制,即具有 PdfWriter
。
因此,
- 如果你想复制一个文件,
PdfDocument
需要初始化没有一个PdfWriter
; - 如果你想(非平凡地)改变一个文件,
PdfDocument
需要用初始化PdfWriter
; - 所以如果你想改变和复制自一个文档,你不能对两者使用相同的
PdfDocument
实例动作!
因此,对于您的用例,您必须
- 要么在应用更改后使用
PdfWriter
获取PdfDocument
的输出,并将其用作PdfDocument
的输入,而无需PdfWriter
进行复制; - 或者从源文件中打开两个单独的
PdfDocument
实例,一个有一个PdfWriter
,一个没有PdfWriter
,然后将更改应用到第一个并从第二个复制。
如果您要复制的数据应包含您应用的更改,则前一个选项是必需的。如果它们不包含它们,则后者是必要的。如果您不关心任何一种方式,或者如果您知道复制的数据不受更改的影响,那么任何一个选项都可以。
在您的情况下,您将 pdfDocuments
中所有文档的所有页面复制到目标文档,因此您特别希望将应用的更改也复制到目标文档。因此,前一个选项适用,您必须在应用更改后 使用 PdfWriter
获取 PdfDocument
的输出,并将其用作没有 [=] 的 PdfDocument
的输入13=] 从中复制。
您可以像这样更改 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())));
}