How to add a border to a paragraph?

Category: 
Tags: page eventsParagraphborderiText 5

I've created a Paragraph using iText. Now I have to add a border to this paragraph, not to the whole document. How to do this?

Posted on StackOverflow on May 5, 2015 by Amit Das

Please take a look at the BorderForParagraph example. It shows how to add a border for a paragraph like this:

A paragraph with a border
A paragraph with a border

There is no method that allows you to create a border for a Paragraph, but you can create a PdfPageEvent implementation that allows you to draw a rectangle based on the start and end position of the Paragraph:

class ParagraphBorder extends PdfPageEventHelper {
    public boolean active = false;
    public void setActive(boolean active) {
        this.active = active;
    }
 
    public float offset = 5;
    public float startPosition;
 
    @Override
    public void onParagraph(
        PdfWriter writer, Document document, float paragraphPosition) {
        this.startPosition = paragraphPosition;
    }
 
    @Override
    public void onParagraphEnd(
        PdfWriter writer, Document document, float paragraphPosition) {
        if (active) {
            PdfContentByte cb = writer.getDirectContentUnder();
            cb.rectangle(document.left(), paragraphPosition - offset,
                document.right() - document.left(),
                startPosition - paragraphPosition);
            cb.stroke();
        }
    }
}

As you can see, I introduced a boolean parameter named active. By default, I've set this parameter to false. I also create an offset (change this value to fine-tune the result) and a startPosition parameter.

Each time iText starts rendering a Paragraph object, the startPosition value is updated. Each time iText ends rendering a Paragraph, a rectangle is drawn if active is true (otherwise nothing happens).

We use this event like this:

public void createPdf(String dest) throws IOException, DocumentException {
    Document document = new Document();
    PdfWriter writer =
        PdfWriter.getInstance(document, new FileOutputStream(dest));
    ParagraphBorder border = new ParagraphBorder();
    writer.setPageEvent(border);
    document.open();
    document.add(new Paragraph("Hello,"));
    document.add(new Paragraph("In this document, we'll add several paragraphs that will trigger page events. As long as the event isn't activated, nothing special happens, but let's make the event active and see what happens:"));
    border.setActive(true);
    document.add(new Paragraph("This paragraph now has a border. Isn't that fantastic? By changing the event, we can even provide a background color, change the line width of the border and many other things. Now let's deactivate the event."));
    border.setActive(false);
    document.add(new Paragraph("This paragraph no longer has a border."));
    document.close();
}

As you can see, we declare the event to the PdfWriter using the setPageEvent() method. We activate the event like this:

border.setActive(true);

and we deactivate it like this:

border.setActive(false);

This is only a proof of concept! You will need to implement the onStartPage() and onEndPage() method if you want this to work for paragraphs that span more than one page. That's shown in BorderForParagraph2:

A paragraph distributed over 2 pages
A paragraph distributed over 2 pages

The onStartPage() and onEndPage() implementation is a no-brainer:

class ParagraphBorder extends PdfPageEventHelper {
    public boolean active = false;
    public void setActive(boolean active) {
        this.active = active;
    }
 
    public float offset = 5;
    public float startPosition;
 
    @Override
    public void onStartPage(PdfWriter writer, Document document) {
        startPosition = document.top();
    }
 
    @Override
    public void onParagraph(PdfWriter writer, Document document,
        float paragraphPosition) {
        this.startPosition = paragraphPosition;
    }
 
    @Override
    public void onEndPage(PdfWriter writer, Document document) {
        if (active) {
            PdfContentByte cb = writer.getDirectContentUnder();
            cb.rectangle(document.left(), document.bottom() - offset,
                document.right() - document.left(),
                startPosition - document.bottom());
            cb.stroke();
        }
    }
 
    @Override
    public void onParagraphEnd(PdfWriter writer, Document document,
        float paragraphPosition) {
        if (active) {
            PdfContentByte cb = writer.getDirectContentUnder();
            cb.rectangle(document.left(), paragraphPosition - offset,
                document.right() - document.left(),
                startPosition - paragraphPosition);
            cb.stroke();
        }
    }
}