Вопрос:

Динамический заголовок страницы iText 7

itext7

478 просмотра

1 ответ

11 Репутация автора

Я пытаюсь создать динамический заголовок страницы с itext7, используя EventHandlers. Я использую код ниже для этого:

    public static void main(String[] args) throws Exception {
    File file = new File("C:\\Test\\variable_header.pdf");
    file.getParentFile().mkdirs();
    new VariableHeader().manipulatePdf(DEST);
}

protected void manipulatePdf(String dest) throws Exception {
    PdfDocument pdfDoc = new PdfDocument(new PdfWriter(DEST));
    Document doc = new Document(pdfDoc);
    VariableHeaderEventHandler handler = new VariableHeaderEventHandler();
    pdfDoc.addEventHandler(PdfDocumentEvent.END_PAGE, handler);
    handler.setHeader("First Header");
    for (int i = 1; i <= 50; i++) {
        doc.add(new Paragraph("Added First content"));
     }
    doc.add(new AreaBreak());
    handler.setHeader("Second Header");
    for (int i = 1; i <= 15; i++) {
        doc.add(new Paragraph("Added Second content"));
    }
    doc.close();
}

protected class VariableHeaderEventHandler implements IEventHandler {
    protected String header;

    public void setHeader(String header) {
        this.header = header;
    }

    @Override
    public void handleEvent(Event event) {
        PdfDocumentEvent documentEvent = (PdfDocumentEvent) event;
        try {
            new PdfCanvas(documentEvent.getPage())
                    .beginText()
                    .setFontAndSize(PdfFontFactory.createFont(FontConstants.HELVETICA), 12)
                    .moveText(450, 806)
                    .showText(header)
                    .endText()
                    .stroke();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

}

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

Первоначально я установил заголовок страницы как «Первый заголовок» и добавил текст «Добавлено первое содержимое» в документ 50 раз. Затем я добавил разрыв области, в результате чего дальнейшая часть страницы остается пустой после рендеринга предыдущего содержимого, а любое другое содержимое будет отображаться на новой странице. Затем я изменил заголовок страницы как «Второй заголовок» и добавил текст «Добавлен второй контент» в документ 15 раз.

Таким образом, согласно приведенному выше коду, заголовок страницы «Второй заголовок» должен отображаться ТОЛЬКО со страницы, на которой отображается текст «Добавлено второе содержимое». Но «Второй заголовок» отображается на предыдущей странице, где отображается текст «Добавлено первое содержимое», как показано ниже:

Динамический заголовок iText7:

Скриншот

Похоже, что есть проблема с механизмом обработки событий в iText 7.0.1.

Есть ли способ решить эту проблему? Любая помощь будет оценена.

Автор: Hari Krishna Источник Размещён: 03.02.2017 03:28

Ответы (1)


3 плюса

5597 Репутация автора

Вы используете низкоуровневые события PdfDocumentвместе с высокоуровневым макетом через Document. END_PAGEСобытие инициируется, когда страница сбрасывается в выходной поток. Хотя низкоуровневый PdfDocumentи высокоуровневый Documentвзаимосвязаны, не существует договора, который бы Documentсбрасывал страницу сразу после перехода на новую. На самом деле, по умолчанию Documentсбрасывает страницы с некоторой задержкой , которая требуется для более тонких возможностей макета. Тот факт, что страницы сбрасываются с некоторой задержкой, заставляет вновь установленный заголовок появляться на «старых» страницах с первым типом контента. Так что это ожидаемое поведение, по крайней мере, на данный момент.

Есть много способов обойти это поведение и достичь желаемого. Я расскажу об одном из них.

После того, как вы добавили AreaBreakк Document, вы можете запросить DocumentRendererтекущую область, доступную для рендеринга остального содержимого, и эта область будет содержать номер текущей страницы:

doc.add(new AreaBreak());
int secondContentStartPageNumber = doc.getRenderer().getCurrentArea().getPageNumber();

Затем вы можете передать эту информацию вашему обработчику событий:

handler.setSecondAreaStartPage(secondContentStartPageNumber);

И используйте эту информацию при принятии решения, какой заголовок вывести на страницу:

int pageNumber = documentEvent.getDocument().getPageNumber(documentEvent.getPage());
String textToShow = pageNumber < secondAreaStartPage ? firstHeader : secondHeader;

Полный VariableHeaderEventHandlerкласс будет выглядеть так:

protected class VariableHeaderEventHandler implements IEventHandler {
    private String firstHeader = "First Header";
    private String secondHeader = "Second Header";
    private int secondAreaStartPage = Integer.MAX_VALUE;

    public void setSecondAreaStartPage(int newValue) {
        secondAreaStartPage = newValue;
    }

    @Override
    public void handleEvent(Event event) {
        PdfDocumentEvent documentEvent = (PdfDocumentEvent) event;
        int pageNumber = documentEvent.getDocument().getPageNumber(documentEvent.getPage());
        try {
            new PdfCanvas(documentEvent.getPage())
                    .beginText()
                    .setFontAndSize(PdfFontFactory.createFont(FontConstants.HELVETICA), 12)
                    .moveText(450, 806)
                    .showText(pageNumber < secondAreaStartPage ? firstHeader : secondHeader)
                    .endText()
                    .stroke();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

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

Автор: Alexey Subach Размещён: 03.02.2017 06:13
Вопросы из категории :
32x32