Itext7 генерирует pdf с исключительным косвенным объектом Pdf, принадлежащим другому PDF-документу. Скопировать объект в текущий PDF-документ.

Я хочу создать PDF-файл с помощью itext 7, но с нами происходит что-то не так:

com.itextpdf.kernel.PdfException: Pdf indirect object belongs to other PDF document. Copy object to current pdf document.
at com.itextpdf.kernel.pdf.PdfOutputStream.write(PdfOutputStream.java:195) ~[kernel-7.0.2.jar:na]
at com.itextpdf.kernel.pdf.PdfOutputStream.write(PdfOutputStream.java:185) ~[kernel-7.0.2.jar:na]
at com.itextpdf.kernel.pdf.PdfOutputStream.write(PdfOutputStream.java:115) ~[kernel-7.0.2.jar:na]
at com.itextpdf.kernel.pdf.PdfOutputStream.write(PdfOutputStream.java:187) ~[kernel-7.0.2.jar:na]
at com.itextpdf.kernel.pdf.PdfOutputStream.write(PdfOutputStream.java:115) ~[kernel-7.0.2.jar:na]
at com.itextpdf.kernel.pdf.PdfOutputStream.write(PdfOutputStream.java:187) ~[kernel-7.0.2.jar:na]
at com.itextpdf.kernel.pdf.PdfOutputStream.write(PdfOutputStream.java:115) ~[kernel-7.0.2.jar:na]
at com.itextpdf.kernel.pdf.PdfWriter.writeToBody(PdfWriter.java:383) ~[kernel-7.0.2.jar:na]
at com.itextpdf.kernel.pdf.PdfWriter.flushObject(PdfWriter.java:289) ~[kernel-7.0.2.jar:na]
at com.itextpdf.kernel.pdf.PdfDocument.flushObject(PdfDocument.java:1572) ~[kernel-7.0.2.jar:na]
at com.itextpdf.kernel.pdf.PdfObject.flush(PdfObject.java:159) ~[kernel-7.0.2.jar:na]
at com.itextpdf.kernel.pdf.PdfObject.flush(PdfObject.java:127) ~[kernel-7.0.2.jar:na]
at com.itextpdf.kernel.pdf.PdfObjectWrapper.flush(PdfObjectWrapper.java:94) ~[kernel-7.0.2.jar:na]
at com.itextpdf.kernel.pdf.PdfPage.flush(PdfPage.java:495) ~[kernel-7.0.2.jar:na]
at com.itextpdf.kernel.pdf.PdfPage.flush(PdfPage.java:454) ~[kernel-7.0.2.jar:na]
at com.itextpdf.kernel.pdf.PdfDocument.close(PdfDocument.java:785) ~[kernel-7.0.2.jar:na]
at com.itextpdf.layout.Document.close(Document.java:120) ~[layout-7.0.2.jar:na]
at com.xcz.afbp.thirdparty.service.impl.GeneratePDFService.generatePDF(GeneratePDFService.java:160) ~[classes/:na]

мой код генерации:

public void generatePDF(CreditQueryData creditQueryData, Map<String, UserCreditContentView> contentViewMap, List<PackageCreditContentView> needRetrievedCreditContentList, File pdfFile, BigDecimal score) throws Exception {

    if (!pdfFile.exists()) {
        boolean x = pdfFile.createNewFile();
        if (!x) {
            LOG.error("生成文件出错" + pdfFile.getPath());
            return;
        }
    }

    PdfDocument pdf = new PdfDocument(new PdfWriter(new FileOutputStream(pdfFile)));
    Document document = new Document(pdf, PageSize.A4);
    document.setRenderer(new DocumentRenderer(document));

    pdf.addEventHandler(PdfDocumentEvent.END_PAGE, new WatermarkingEventHandler());

    try {
        //operate code just add tableA tableB tableC...

    } catch (Exception e) {
        LOG.info();
    } finally {
        document.close(); //exception throws here
    }


}

мой единственный код стиля в itext7:

 private PdfFont bfChinese = null;

будет инициализирован при вызове конструктора службы:

 public GeneratePDFService() {
    String PdfFontPath = EnvironmentUtils.getClasspathFilePath("font/MSYH.TTF");
    try {
        bfChinese =  PdfFontFactory.createFont(PdfFontPath, "Identity-H", true);
    } catch (Exception e) {
        e.printStackTrace();
    }
}

Я попытался установить для своего шрифта значение static, но не работает.

это исключение выброса места:

private void write(PdfIndirectReference indirectReference) {
        if (document != null && !indirectReference.getDocument().equals(document)) {
            throw new PdfException(PdfException.PdfIndirectObjectBelongsToOtherPdfDocument);
        }
        if (indirectReference.getRefersTo() == null) {
            write(PdfNull.PDF_NULL);
        } else if (indirectReference.getGenNumber() == 0) {
            writeInteger(indirectReference.getObjNumber()).
                    writeBytes(endIndirectWithZeroGenNr);
        } else {
            writeInteger(indirectReference.getObjNumber()).
                    writeSpace().
                    writeInteger(indirectReference.getGenNumber()).
                    writeBytes(endIndirect);
        }
    }

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


person Cheng.T    schedule 20.06.2017    source источник


Ответы (3)


Я сам столкнулся с той же проблемой (и мне потребовались часы, чтобы понять, что я делаю не так). Как оказалось, вы можете использовать конкретный экземпляр PdfFont только для одного документа. Как только вы используете экземпляр PdfFont, он связывается с этим документом, и вы больше не можете использовать его в другом документе.

Например:

class ThisGoesWrong {

    protected PdfFont font;

    public ThisGoesWrong() {
        font = PdfFontFactory.createFont(...);
    }

    public void createPdf() {
        ...
        Paragraph p = new Paragraph("test").setFont(font);
        document.add(p);
        ...
    }
}

Класс ThisGoesWrong создает правильный PDF-файл при первом вызове createPdf(), но при втором вызове он показывает исключение, которое возникает у вас.

Я обнаружил, что это решает проблему:

class ThisWorksOK {

    public ThisWorksOK() {
    }

    public void createPdf() {
        ...
        PdfFont font = PdfFontFactory.createFont(...);
        Paragraph p = new Paragraph("test").setFont(font);
        document.add(p);
        ...
    }
}

Я не знаю, является ли это ошибкой (это определенно похоже на ошибку), поэтому я создам внутреннюю заявку в iText Group.

person Bruno Lowagie    schedule 20.06.2017
comment
Я не знаю, является ли это ошибкой (это определенно похоже на ошибку) - если шрифт в конечном итоге может быть встроен как подмножество глифов из какой-либо программы шрифтов, используемой в документе, он имеет смысл считать его связанным с документом. В противном случае вам пришлось бы собирать данные об используемых глифах для каждого документа. Конечно, можно возразить, что имя класса PdfFont неверно, что оно должно быть PdfDocumentFont. - person mkl; 20.06.2017
comment
@ Cheng.T Слева, рядом с нулевым баллом за мой ответ, стоит галочка. Установите этот флажок, поскольку мой ответ решил вашу проблему. - person Bruno Lowagie; 21.06.2017
comment
Большое спасибо за сэкономленные часы отладки. - person VaibS; 04.05.2020
comment
@ bruno-lowagie, довольно забавно слышать, как вы обсуждаете собственное творение отстраненно, как будто имеете в виду переезжающего сына. Во всяком случае, я столкнулся с этим сообщением сегодня, 3 года спустя ... Означает ли это, что было решено, что это функция, а не ошибка? Тем не менее, спасибо за руководство. Мне потребовалась бы целая вечность и день, чтобы понять это. - person Wellspring; 10.12.2020

Чтобы улучшить производительность, вы должны повторно использовать FontProgram:

private FontProgram bfChinese = null;

public GeneratePDFService() {
    String PdfFontPath = EnvironmentUtils.getClasspathFilePath("font/MSYH.TTF");
    try {
        bfChinese =  FontProgramFactory.createFont(PdfFontPath);
    } catch (Exception e) {
        e.printStackTrace();
    }
}

А потом:

public void createPdf() {
    ...
    PdfFont font = PdfFontFactory.createFont(bfChinese, "Identity-H", true);
    Paragraph p = new Paragraph("test").setFont(font);
    document.add(p);
    ...
}
person Pavel Alay    schedule 06.07.2017
comment
да, сделайте шрифт приватным, я решил эту проблему, в любом случае спасибо. - person Cheng.T; 09.07.2017

Вот как я решил проблему.

  1. Создан класс DocumentUtil
  2. Добавить статический метод

    public class DocumentUtils {    
        public static PdfFont setFont() throws Exception {
                return PdfFontFactory.createFont(StandardFonts.TIMES_ROMAN);
        }
    }
    
  3. Используйте шрифт, например:

    PDfFont font = DocumentUtil.setFont();
    
person Gil Nz    schedule 27.09.2018