How can you eliminate white-space in multiple colu

2019-08-31 06:53发布

问题:

I'd like to add a Paragraph of text to pages in 2 columns. I understand that MultiColumnText has been eliminated. I know I can create column 1, write to it, and if there is more text create column 2 and write to it. If there is still more text, go to the next page and repeat.

However I always end up with either:

  1. a long chunk of text orphaned in the left column.
  2. a full left column and partially used right column.

How can I format my content in 2 columns while reducing white space, such as compressing the columns so I end with 2 full columns of equal length?

Thanks!

回答1:

You should add your column twice, once in simulation mode and once for real.

I have adapted the ColumnTextParagraphs example to show what is meant by simulation mode. Take a look at the ColumnTextParagraphs2 example:

We add the column in simulation mode to obtain the total height needed for the column. This is done in the following method:

public float getNecessaryHeight(ColumnText ct) throws DocumentException {
    ct.setSimpleColumn(new Rectangle(0, 0, COLUMN_WIDTH, -500000));
    ct.go(true);
    return -ct.getYLine();
}

We use this height when we add the left and right column:

Rectangle left;
float top = COLUMNS[0].getTop();
float middle = (COLUMNS[0].getLeft() + COLUMNS[1].getRight()) / 2;
float columnheight;
int status = ColumnText.START_COLUMN;
while (ColumnText.hasMoreText(status)) {
    if (checkHeight(height)) {
        columnheight = COLUMNS[0].getHeight();
        left = COLUMNS[0];
    }
    else {
        columnheight = (height / 2) + ERROR_MARGIN;
        left = new Rectangle(
            COLUMNS[0].getLeft(),
            COLUMNS[0].getTop() - columnheight,
            COLUMNS[0].getRight(),
            COLUMNS[0].getTop()
        );
    }
    // left half
    ct.setSimpleColumn(left);
    ct.go();
    height -= COLUMNS[0].getTop() - ct.getYLine();
    // separator
    canvas.moveTo(middle, top - columnheight);
    canvas.lineTo(middle, top);
    canvas.stroke();
    // right half
    ct.setSimpleColumn(COLUMNS[1]);
    status = ct.go();
    height -= COLUMNS[1].getTop() - ct.getYLine();
    // new page
    document.newPage();
}

This is how we check the height:

public boolean checkHeight(float height) {
    height -= COLUMNS[0].getHeight() + COLUMNS[1].getHeight() + ERROR_MARGIN;
    return height > 0;
}

As you can see, we add the full columns as long as the height of both columns is smaller than the remaining height. When columns are added, we adjust the remaining height. As soon as the height is lower than the height of to columns, we adapt the height of the first column.

Note that we work with an ERROR_MARGIN because dividing by two often leads to a situation where the second column has one line more than the first column. It is better when it's the other way around.

This is the full example at your request:

/**
 * Example written by Bruno Lowagie in answer to:
 * http://stackoverflow.com/questions/29378407/how-can-you-eliminate-white-space-in-multiple-columns-using-itextsharp
 */
package sandbox.objects;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;

import com.itextpdf.text.Document;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.Paragraph;
import com.itextpdf.text.Rectangle;
import com.itextpdf.text.pdf.ColumnText;
import com.itextpdf.text.pdf.PdfContentByte;
import com.itextpdf.text.pdf.PdfWriter;

public class ColumnTextParagraphs2 {

    public static final String DEST = "results/objects/column_paragraphs2.pdf";

    public static final String TEXT = "This is some long paragraph that will be added over and over again to prove a point.";
    public static final float COLUMN_WIDTH = 254;
    public static final float ERROR_MARGIN = 16;
    public static final Rectangle[] COLUMNS = {
        new Rectangle(36, 36, 36 + COLUMN_WIDTH, 806),
        new Rectangle(305, 36, 305 + COLUMN_WIDTH, 806)
    };

    public static void main(String[] args) throws IOException, DocumentException {
        File file = new File(DEST);
        file.getParentFile().mkdirs();
        new ColumnTextParagraphs2().createPdf(DEST);
    }

    public void createPdf(String dest) throws IOException, DocumentException {
        // step 1
        Document document = new Document();
        // step 2
        PdfWriter writer = PdfWriter.getInstance(document, new FileOutputStream(dest));
        // step 3
        document.open();
        // step 4
        PdfContentByte canvas = writer.getDirectContent();
        ColumnText ct = new ColumnText(canvas);
        addContent(ct);
        float height = getNecessaryHeight(ct);
        addContent(ct);
        Rectangle left;
        float top = COLUMNS[0].getTop();
        float middle = (COLUMNS[0].getLeft() + COLUMNS[1].getRight()) / 2;
        float columnheight;
        int status = ColumnText.START_COLUMN;
        while (ColumnText.hasMoreText(status)) {
            if (checkHeight(height)) {
                columnheight = COLUMNS[0].getHeight();
                left = COLUMNS[0];
            }
            else {
                columnheight = (height / 2) + ERROR_MARGIN;
                left = new Rectangle(
                    COLUMNS[0].getLeft(),
                    COLUMNS[0].getTop() - columnheight,
                    COLUMNS[0].getRight(),
                    COLUMNS[0].getTop()
                );
           }
            // left half
            ct.setSimpleColumn(left);
            ct.go();
            height -= COLUMNS[0].getTop() - ct.getYLine();
            // separator
            canvas.moveTo(middle, top - columnheight);
            canvas.lineTo(middle, top);
            canvas.stroke();
            // right half
            ct.setSimpleColumn(COLUMNS[1]);
            status = ct.go();
            height -= COLUMNS[1].getTop() - ct.getYLine();
            // new page
            document.newPage();
        }
        // step 5
        document.close();
    }

    public void addContent(ColumnText ct) {
        for (int i = 0; i < 35; i++) {
            ct.addElement(new Paragraph(String.format("Paragraph %s: %s", i, TEXT)));
        }
    }

    public float getNecessaryHeight(ColumnText ct) throws DocumentException {
        ct.setSimpleColumn(new Rectangle(0, 0, COLUMN_WIDTH, -500000));
        ct.go(true);
        return -ct.getYLine();
    }

    public boolean checkHeight(float height) {
        height -= COLUMNS[0].getHeight() + COLUMNS[1].getHeight() + ERROR_MARGIN;
        return height > 0;
    }
}