PDFBOX:零星的例外,而创建PDF文档

问题描述 投票:1回答:1

我使用PDFBox的产生在一个循环一堆发票。这是工作在一般情况下,但不幸的是我得到了以下异常,不时在循环。启动再次产生一次或两次失败的发票迟早会创建所有的人。

java.io.IOException: COSStream has been closed and cannot be read. Perhaps its enclosing PDDocument has been closed?
at org.apache.pdfbox.cos.COSStream.checkClosed(COSStream.java:83)
at org.apache.pdfbox.cos.COSStream.createRawInputStream(COSStream.java:133)
at org.apache.pdfbox.pdfwriter.COSWriter.visitFromStream(COSWriter.java:1202)
at org.apache.pdfbox.cos.COSStream.accept(COSStream.java:400)
at org.apache.pdfbox.pdfwriter.COSWriter.doWriteObject(COSWriter.java:521)
at org.apache.pdfbox.pdfwriter.COSWriter.doWriteObjects(COSWriter.java:459)
at org.apache.pdfbox.pdfwriter.COSWriter.doWriteBody(COSWriter.java:443)
at org.apache.pdfbox.pdfwriter.COSWriter.visitFromDocument(COSWriter.java:1096)
at org.apache.pdfbox.cos.COSDocument.accept(COSDocument.java:417)
at org.apache.pdfbox.pdfwriter.COSWriter.write(COSWriter.java:1369)
at org.apache.pdfbox.pdfwriter.COSWriter.write(COSWriter.java:1256)
at org.apache.pdfbox.pdmodel.PDDocument.save(PDDocument.java:1279)
at org.apache.pdfbox.pdmodel.PDDocument.save(PDDocument.java:1250)
at org.apache.pdfbox.pdmodel.PDDocument.save(PDDocument.java:1238)
at de.xx.xxx.CreateLandscapePDF.createPdf(CreateLandscapePDF.java:37)
at de.xx.xxx.CreateInvoiceAsPDF.createPdf(CreateInvoiceAsPDF.java:172)
...

我已经看着一些类似的问题,如在这里PDFbox saying PDDocument closed when its not,我只是觉得它是与由垃圾收集器释放的对象,但我不认为在我的代码故障。

为了创建我使用一般的Apache PDFBox的食谱的描述在https://pdfbox.apache.org/1.8/cookbook/documentcreation.html的PDF本身。我或多或少只是添加更多的内容,图像,一些文本块,表等。

public class CreateLandscapePDF {

private ArrayList<ContentBlock> content;
private PDRectangle pageDIN;
private PDDocument doc;

public CreateLandscapePDF(ArrayList<ContentBlock> content, PDRectangle pageDIN) {
    this.content = content;
    this.pageDIN = pageDIN;
}

public void createPdf(String pdfFileName) throws IOException
{
    doc = new PDDocument();

    PDPage page = new PDPage(pageDIN);
    doc.addPage(page);
    PDPageContentStream contentStream = new PDPageContentStream(doc, page, PDPageContentStream.AppendMode.OVERWRITE, false);

    for (ContentBlock contentBlock : content) {
        contentBlock.getContentHelper().writeContentToPDF(contentStream);
        contentStream.moveTo(0, 0);
    }
    contentStream.close();
    doc.save( pdfFileName );
    doc.close();
}

}

在我的创作过程中,我必须在CreateInvoiceAsPDF.createPdf方法中的循环。在这个循环中,我创建总是CreateLandscapePDF的新对象。

CreateLandscapePDF pdf = new CreateLandscapePDF(contentList, PDRectangle.A4);
pdf.createPdf(TEMP_FILEPATH_NAME + pdfFileName);

该writeContentToPDF方法仅放置几个内容等文本,图像和线条在限定像素单元到页面中。作为一个例子,我把代码从我TextContentHelper:

    public void writeContentToPDF(PDPageContentStream contentStream) throws IOException {
    float maxTextWidth = 1;
    contentStream.beginText();
    float fontSize = content.getFontSize();
    PDFont font = content.getFont();
    contentStream.setFont(font, fontSize);
    contentStream.setLeading(content.getLineSpace() * fontSize);
    float xPos =0;
    for (Object text : content.getContent()) {
        if (text instanceof String) {
            float textWidth = UnitTranslator.getPixUnitFromTextLength(font, fontSize, (String) text);
            switch (content.getAlignment()) {
            case CENTER:
                xPos = 0.5f*(content.getXEndPosition()+content.getXPosition()-textWidth);
                contentStream.newLineAtOffset(xPos, content.getYPosition());
                break;
            case RIGHT:
                xPos = content.getXEndPosition()-textWidth;
                contentStream.newLineAtOffset(xPos, content.getYPosition());
                break;
            default:
                xPos = content.getXPosition();
                contentStream.newLineAtOffset(xPos, content.getYPosition());
                break;
            }
            contentStream.showText((String) text);
            contentStream.newLine();
            contentStream.newLineAtOffset(-xPos, -content.getYPosition());
            if (textWidth > maxTextWidth) {
                maxTextWidth = textWidth;
            }
        }
    }
    contentStream.endText();
    if (content.isBorder()) {
        createTextBlockBorder(contentStream, maxTextWidth, fontSize);

    }
}

我明白任何的提示来解决这个恼人的问题!

pdfbox
1个回答
1
投票

1)保存时,最好通过查看部分保存文件的末尾分析的COSStream has been closed and cannot be read例外。用记事本++打开它,你会看到在底部一个不完整的数据流。发布的最后几行,从有“数0 OBJ”的最后一行开始。这将表明什么样的COSStream的是麻烦。

2)你的文件显示的图像x对象(“/类型/ x对象/亚型/图像”)。

3)进一步的研究表明,你创建你的形象

PDImageXObject pdImage = PDImageXObject.createFromByteArray(new PDDocument(), ...);

你偶尔也得到了警告Warning: You did not close a PDF Document

这是因为你的new PDDocument()对象传递给createFromByteArray方法,但不能保持,PDFBox的需要,只得到那个PDDocument(“临时文件”)的内存管理的东西。所以后来(垃圾收集)这个未引用PDDocument定稿,并关闭所有相关的数据流,其中包括您创建的图像流。

因此,解决办法是通过自己的文档,而不是一些临时对象的PDDocument。

4)请注意,这也适用于字体,所以不要new PDDocument()传递到字体创建方法。 (并不适用于你,但也许人们在未来)。

© www.soinside.com 2019 - 2024. All rights reserved.