How to divide a page in N parts so we can fill each with a different source?

Tags: ColumnTextrectangleiText 5

I need to create an User guide, where I've to put the content in 2 different languages but on the same page. So the first half of the page would be in English while the second part would be in French like this:

Example

In the future they might ask for 3rd language also, but maximum 3. Right now each page would have 2 blocks. How can I achieve this using iTextPDF in java?

Posted on StackOverflow on Feb 13, 2012 by IT ppl

If I understand your question correctly, you need to create something like this:

Example
Example

In this screen shot, you see the first part of the first book of Caesar's Commentaries on the Gallic War. Gallia omnia est divisa in partes tres, and so is each page in this document: the upper part shows the text in Latin, the middle part shows the text in English, the lower part shows the text in French. If you read the text, you'll discover that Belgians like me are considered being the bravest of all (although we aren't as civilized as one would wish). See three_parts.pdf if you want to take a look at the PDF.

This PDF was created with the ThreeParts example. In this example, I have 9 text files: liber1_1_la.txt, liber1_1_en.txt, liber1_1_fr.txt, liber1_2_la.txt, liber1_2_en.txt, liber1_2_fr.txt, liber1_3_la.txt, liber1_3_en.txt, and liber1_3_fr.txt.

Liber is the latin word for book, so all files are snippets from the first book, more specifically sections 1, 2, and 3, in Latin, English and French.

This is how I defined the languages and he rectangles for each language:

public static final String[] LANGUAGES = { "la", "en", "fr" };
public static final Rectangle[] RECTANGLES = {
    new Rectangle(36, 581, 559, 806),
    new Rectangle(36, 308.5f, 559, 533.5f),
    new Rectangle(36, 36, 559, 261) };

In my code, I loop over the different sections, and I create a ColumnText object for each language:

PdfContentByte cb = writer.getDirectContent();
ColumnText[] columns = new ColumnText[3];
for (int section = 1; section <= 3; section++) {
    for (int la = 0; la < 3; la++) {
        columns[la] = createColumn(cb, section, LANGUAGES[la], RECTANGLES[la]);
    }
    while (addColumns(columns)) {
        document.newPage();
        for (int la = 0; la < 3; la++) {
            columns[la].setSimpleColumn(RECTANGLES[la]);
        }
    }
    document.newPage();
}

If you examine the body of the inner loop, you see that I first define three ColumnText objects, one for each language:

public ColumnText createColumn(
    PdfContentByte cb, int i, String la, Rectangle rect)
    throws IOException {
    ColumnText ct = new ColumnText(cb);
    ct.setSimpleColumn(rect);
    Phrase p = createPhrase(
        String.format("resources/text/liber1_%s_%s.txt", i, la));
    ct.addText(p);
    return ct;
}

In this case, I'm using ColumnText in text mode, and I read the text from the different files into a Phrase like this:

public Phrase createPhrase(String path) throws IOException {
    Phrase p = new Phrase();
    BufferedReader in = new BufferedReader(
        new InputStreamReader(new FileInputStream(path), "UTF8"));
    String str;
    while ((str = in.readLine()) != null) {
        p.add(str);
    }
    in.close();
    return p;
}

Once I have defined the ColumnText objects and added their content, I need to render the content to one of more pages until all the text is rendered from all columns. To achieve this, we use this method:

public boolean addColumns(ColumnText[] columns) throws DocumentException {
    int status = ColumnText.NO_MORE_TEXT;
    for (ColumnText column : columns) {
        if (ColumnText.hasMoreText(column.go()))
            status = ColumnText.NO_MORE_COLUMN;
    }
    return ColumnText.hasMoreText(status);
}

As you can see, I also create a new page for every new section I start. This isn't really necessary: I could add all the section to a single ColumnText, but depending on how the Latin text translated into English and French, you could end up with large discrepancies where section X of the Latin text starts on one page and the same section in English or French starts on another page. Hence my choice to start a new page, although it's not really necessary in this small proof of concept.