Skip to content
Advertisement

itext 7 pdf how to prevent text overflow on right side of the page

I am using itextpdf 7 (7.2.0) to create a pdf file. However even though the TOC part is rendered very well, in the content part the text overflows. Here is my code that generates the pdf:

public class Main {
    public static void main(String[] args) throws IOException {
        PdfWriter writer = new PdfWriter("fiftyfourthPdf.pdf");
        PdfDocument pdf = new PdfDocument(writer);
        Document document = new Document(pdf, PageSize.A4,false);
        //document.setMargins(30,10,36,10);

// Create a PdfFont
        PdfFont font = PdfFontFactory.createFont(StandardFonts.TIMES_ROMAN,"Cp1254");

        document
                .setTextAlignment(TextAlignment.JUSTIFIED)
                .setFont(font)
                .setFontSize(11);
        PdfOutline outline = null;
        java.util.List<AbstractMap.SimpleEntry<String, AbstractMap.SimpleEntry<String, Integer>>> toc = new ArrayList<>();
        for(int i=0;i<5000;i++){
            String line = "This is paragraph " + String.valueOf(i+1)+ " ";
            line = line.concat(line).concat(line).concat(line).concat(line).concat(line);
            Paragraph p = new Paragraph(line);
            p.setKeepTogether(true);
            document.add(p.setFont(font).setFontSize(10).setHorizontalAlignment(HorizontalAlignment.CENTER).setTextAlignment(TextAlignment.LEFT));

            //PROCESS FOR TOC
            String name = "para " + String.valueOf(i+1);
            outline = createOutline(outline,pdf,line ,name );
            AbstractMap.SimpleEntry<String, Integer> titlePage = new AbstractMap.SimpleEntry(line, pdf.getNumberOfPages());
            p
                    .setFont(font)
                    .setFontSize(12)
                    //.setKeepWithNext(true)
                    .setDestination(name)

                    // Add the current page number to the table of contents list
                    .setNextRenderer(new UpdatePageRenderer(p));
            toc.add(new AbstractMap.SimpleEntry(name, titlePage));

        }

        int contentPageNumber = pdf.getNumberOfPages();

        for (int i = 1; i <= contentPageNumber; i++) {

            // Write aligned text to the specified by parameters point
            document.showTextAligned(new Paragraph(String.format("Sayfa %s / %s", i, contentPageNumber)).setFontSize(10),
                    559, 26, i, TextAlignment.RIGHT, VerticalAlignment.MIDDLE, 0);
        }

        //BEGINNING OF TOC
        document.add(new AreaBreak());
        Paragraph p = new Paragraph("Table of Contents")
                .setFont(font)
                .setDestination("toc");
        document.add(p);
        java.util.List<TabStop> tabStops = new ArrayList<>();
        tabStops.add(new TabStop(580, TabAlignment.RIGHT, new DottedLine()));
        for (AbstractMap.SimpleEntry<String, AbstractMap.SimpleEntry<String, Integer>> entry : toc) {
            AbstractMap.SimpleEntry<String, Integer> text = entry.getValue();
            p = new Paragraph()
                    .addTabStops(tabStops)
                    .add(text.getKey())
                    .add(new Tab())
                    .add(String.valueOf(text.getValue()))
                    .setAction(PdfAction.createGoTo(entry.getKey()));
            document.add(p);
        }



        // Move the table of contents to the first page
        int tocPageNumber = pdf.getNumberOfPages();
        for (int i = 1; i <= tocPageNumber; i++) {

            // Write aligned text to the specified by parameters point
            document.showTextAligned(new Paragraph("n footer textn second linenthird line").setFontColor(ColorConstants.RED).setFontSize(8),
                    300, 26, i, TextAlignment.CENTER, VerticalAlignment.MIDDLE, 0);
        }

        document.flush();
        for(int z = 0; z< (tocPageNumber - contentPageNumber ); z++){
            pdf.movePage(tocPageNumber,1);
            pdf.getPage(1).setPageLabel(PageLabelNumberingStyle.UPPERCASE_LETTERS,
                    null, 1);
        }


        //pdf.movePage(tocPageNumber, 1);

        // Add page labels
        /*pdf.getPage(1).setPageLabel(PageLabelNumberingStyle.UPPERCASE_LETTERS,
                null, 1);*/
        pdf.getPage(tocPageNumber - contentPageNumber + 1).setPageLabel(PageLabelNumberingStyle.DECIMAL_ARABIC_NUMERALS,
                null, 1);


        document.close();

    }
    private static PdfOutline createOutline(PdfOutline outline, PdfDocument pdf, String title, String name) {
        if (outline == null) {
            outline = pdf.getOutlines(false);
            outline = outline.addOutline(title);
            outline.addDestination(PdfDestination.makeDestination(new PdfString(name)));
        } else {
            PdfOutline kid = outline.addOutline(title);
            kid.addDestination(PdfDestination.makeDestination(new PdfString(name)));
        }

        return outline;
    }
    private static class UpdatePageRenderer extends ParagraphRenderer {
        protected AbstractMap.SimpleEntry<String, Integer> entry;

        public UpdatePageRenderer(Paragraph modelElement, AbstractMap.SimpleEntry<String, Integer> entry) {
            super(modelElement);
            this.entry = entry;
        }
        public UpdatePageRenderer(Paragraph modelElement) {
            super(modelElement);
        }

        @Override
        public LayoutResult layout(LayoutContext layoutContext) {
            LayoutResult result = super.layout(layoutContext);
            //entry.setValue(layoutContext.getArea().getPageNumber());
            if (result.getStatus() != LayoutResult.FULL) {
                if (null != result.getOverflowRenderer()) {
                    result.getOverflowRenderer().setProperty(
                            Property.LEADING,
                            result.getOverflowRenderer().getModelElement().getDefaultProperty(Property.LEADING));
                } else {
                    // if overflow renderer is null, that could mean that the whole renderer will overflow
                    setProperty(
                            Property.LEADING,
                            result.getOverflowRenderer().getModelElement().getDefaultProperty(Property.LEADING));
                }
            }
            return result;
        }

        @Override
        // If not overriden, the default renderer will be used for the overflown part of the corresponding paragraph
        public IRenderer getNextRenderer() {
            return new UpdatePageRenderer((Paragraph) this.getModelElement());
        }

      
    }

}

Here are the screen shots of TOC part and content part :

TOC :

TOC

Content :

Content part

What am I missing? Thank you all for your help.

UPDATE

When I add the line below it renders with no overflow but the page margins of TOC and content part differ (the TOC margin is way more than the content margin). See the picture attached please :

document.setMargins(30,60,36,20);

Right Margin difference between TOC and content:  Right Margin difference between TOC and content

UPDATE 2 :

When I comment the line

document.setMargins(30,60,36,20);

and set the font size on line :

document.add(p.setFont(font).setFontSize(10).setHorizontalAlignment(HorizontalAlignment.CENTER).setTextAlignment(TextAlignment.LEFT));

to 12 then it renders fine. What difference should possibly the font size cause for the page content and margins? Are not there standard page margins and page setups? Am I unknowingly (I am newbie to itextpdf) messing some standard implementations?

Advertisement

Answer

TL; DR: either remove setFontSize in

p
                    .setFont(font)
                    .setFontSize(12)
                    //.setKeepWithNext(true)
                    .setDestination(name)

or change setFontSize(10) -> setFontSize(12) in

document.add(p.setFont(font).setFontSize(10).setHorizontalAlignment(HorizontalAlignment.CENTER).setTextAlignment(TextAlignment.LEFT));

Explanation: You are setting the Document to not immediately flush elements added to that document with the following line:

Document document = new Document(pdf, PageSize.A4,false);

Then you add an paragraph element with font size equal to 10 to the document with the following line:

document.add(p.setFont(font).setFontSize(10).setHorizontalAlignment(HorizontalAlignment.CENTER).setTextAlignment(TextAlignment.LEFT));

What happens is that the element is being laid out (split in lines etc), but now drawn on the page. Then you do .setFontSize(12) and this new font size is applied for draw only, so iText calculated that X characters would fit into one line assuming the font size is 10 while in reality the font size is 12 and obviously fewer characters can fit into one line.

There is no sense in setting the font size two times to different values – just pick one value you want to see in the resultant document and set it once.

User contributions licensed under: CC BY-SA
3 People found this is helpful
Advertisement