How to fit a String inside a rectangle?

Tags: measure textiText 7

I'm trying to add some strings, images and tables into my pdf file (there have to be several pages) but when I try to use ColumnText (I use this because I want to place strings at absolute positions), I encounter a problem. When the column height is not sufficient to add the content of the strings, the content is incomplete. How can I avoid that content gets lost?

Here's the related code :

PdfContentByte cb = writer.getDirectContent();
Image imageust = Image.getInstance(imageUrl);
Image imageAlt = imageAlt = Image.getInstance(imageUrlAlt);
imageust.setAbsolutePosition(0f,
    document.getPageSize().getHeight() - imageust.getHeight()-10);
imageAlt.setAbsolutePosition(0f, 10f);
document.add(imageust);
document.add(imageAlt);
// now draw a line below the headline
cb.setLineWidth(1f); 
cb.moveTo(0, 200);
cb.lineTo(200, 200);
cb.stroke();
// first define a standard font for our text
Font helvetica8BoldBlue = FontFactory.getFont(FontFactory.HELVETICA,16);
// create a column object
ColumnText ct = new ColumnText(cb);
// define the text to print in the column
Phrase myText = new Phrase("Very Very Long String!!!" , helvetica8BoldBlue);
ct.setSimpleColumn(myText, 60, 750,
    /* width*/document.getPageSize().getWidth() - 40, 100,
    20, Element.ALIGN_LEFT);
ct.go();
Posted on StackOverflow on Nov 23, 2012 by Adnan Bal

There are three options:

  1. Either you provide a bigger rectangle, so that the content fits inside,
  2. or you reduce the content (e.g. smaller font, less text),...
  3. or you keep the size of the rectangle, keep the font size, etc... but add the content that doesn't fit on the next page.

How do you know if the content doesn't fit?

You can manipulate with a ParagraphRenderer a bit and test if all the content was 'consumed':

ParagraphRenderer renderer = (ParagraphRenderer) paragraph.createRendererSubTree();
LayoutResult layoutResult = renderer.layout(new LayoutContext(new LayoutArea(pageNumber, area)));
boolean fits = (layoutResult.getStatus() == LayoutResult.FULL);

Based on the value of fits, you can decide to change the size of the rectangle or the content. In iText 7 LayoutResult class has the following available constants:

  • LayoutResult.FULL

  • LayoutResult.PARTIAL

  • LayoutResult.NOTHING

If you can distribute the content over different pages you would need to insert a pdfDoc.addNewPage();

public void fitString(PdfDocument pdfDoc, Paragraph paragraph, int pageNumber, Rectangle area) throws IOException {
    LayoutResult layoutResult;
    ParagraphRenderer renderer = (ParagraphRenderer) paragraph.createRendererSubTree();
    renderer.setParent(new DocumentRenderer(new Document(pdfDoc)));
    while (((layoutResult = renderer.layout(new LayoutContext(new LayoutArea(pageNumber, area))))).getStatus() != LayoutResult.FULL) {
        if (pdfDoc.getNumberOfPages() < pageNumber) {
            pdfDoc.addNewPage();
        }
        layoutResult.getSplitRenderer().draw(new DrawContext(pdfDoc, new PdfCanvas(pdfDoc.getPage(pageNumber++)), false));
        renderer = (ParagraphRenderer) layoutResult.getOverflowRenderer();
    }
    if (pdfDoc.getNumberOfPages() < pageNumber) {
        pdfDoc.addNewPage();
    }
    renderer.draw(new DrawContext(pdfDoc, new PdfCanvas(pdfDoc.getPage(pageNumber)), false));
}

In this example, area contains the coordinates of the desired rectangle.

Click this link if you want to see how to answer this question in iText 5.