vandeseer / easytable

Small table drawing library built upon Apache PDFBox
MIT License
239 stars 91 forks source link

Not able to draw a page title when table spans multiple pages #91

Open imod opened 4 years ago

imod commented 4 years ago

How do I draw a page title on a document which has a table that spans multiple pages?

e.g. this draws a table over multiple pages

                    TableDrawer.builder()
                            .table(createLongTable())
                            .startX(50)
                            .startY(750F)
                            .endY(50F) // note: if not set, table is drawn over the end of the page
                            .build()
                            .draw(() -> document, () -> new PDPage(PDRectangle.A4), 50f);

but how can I add a title/content outside of the table on each page when I have a table that spans multiple pages? or how do I add a header with the number of pages to each page like in this example with a https://github.com/vandeseer/easytable/blob/master/src/test/java/org/vandeseer/integrationtest/FinalYTest.java but with a table that spans multiple pages?

imod commented 4 years ago

sorry, I found a solution by adding a specific annotation like this:

    private PDPage newPage(String title) {
        PDPage page = new PDPage(PDRectangle.A4);
        PDAnnotationText titleAnnotation = new PDAnnotationText();
        titleAnnotation.setAnnotationName("title");
        titleAnnotation.setName(title);
        titleAnnotation.setHidden(true);
        page.setAnnotations(List.of(titleAnnotation));
        return page;
    }

and then at the end I iterate all pages to draw the title for each page:

            for (int i = 0; i < document.getNumberOfPages(); i++) {
                PDPage page = document.getPage(i);
                try (final PDPageContentStream contentStream = new PDPageContentStream(document, page, APPEND, false)) {
                    headLine(page, createdAt, contentStream);
                }
            }

    private void headLine(PDPage page, String createdAt, PDPageContentStream contentStream) throws IOException {
        Optional<String> pageTitle = page.getAnnotations()
                .stream()
                .filter(PDAnnotationText.class::isInstance)
                .map(PDAnnotationText.class::cast)
                .filter(a -> a.getAnnotationName().equals("title"))
                .map(PDAnnotationText::getName)
                .findFirst();

        contentStream.beginText();
        contentStream.newLineAtOffset(100, 780);
        contentStream.setFont(FONT_BOLD, 10);
        contentStream.showText(pageTitle.get());
        contentStream.endText();
imod commented 4 years ago

@vandeseer But I still face one Problem: how do I tell the table to also consider the given .startY(750F) on the next pages? So my problem is, that .startY(750F) is only used on the first page, but not on the next ones, therefore I don't have large enough header section to draw the title on the second, third, ... pages. How can I keep a header area free on the subsequent pages where the table is expanded to?

vandeseer commented 4 years ago

Hi @imod,

please have a look at this PDF and the corresponding code.

Basically like so (please check the comments I made):

try (final PDDocument document = new PDDocument()) {

        TableDrawer.builder()
                .table(createTable())
                .startX(50)
                .startY(200f) // <-- First page
                .endY(50f) // <--  If not set, table is drawn over the end of the page
                .build()
                .draw(() -> document, () -> new PDPage(PDRectangle.A4), 50f); // <-- 3rd parameter is offset on next page! 

        document.save(TestUtils.TARGET_FOLDER + "/severalPagesTableRepeatedHeaderMultipleRows.pdf");
    }

Hope this helps, Stefan

imod commented 4 years ago

awesome - thats the link I was missing, many thanks! Just to also confirm this: my experience is that if I omit .startY(..), then a new page is created also for the first page - but when I do set .startY(..) then it appended to the last page. Is this correct?

vandeseer commented 4 years ago

Hi @imod,

well, the default value for startY is 0. Basically because it's not explicitly initialized and is of type float; maybe it should be a different default value though. Because 0 is the lower border of the page it will start on a new page if endY(...) is set, because the program sees that it doesn't fit on the page (how should it if one starts on the border already? 😉 ).

But one can think about setting a different default value or maybe issue a warning in case the startY is not set. That would make sense, I guess. I will leave this issue open as a reminder.

Best, Stefan