How to add a background image to a cell?

Tags: tablesimagescell eventimage in celliText 5

I have the following requirements:

  1. I want to create a document which contains one table. Inside that table, there are cells.
  2. I want to make each cell with specific height.
  3. each cell have the same background image.
  4. I want to put a text in front the image in the position I want inside the cell. For example: top left of the cell, bottom right of the cell.

Posted on StackOverflow on Jul 1, 2015 by lasheul

In other words: you want something like this: position_content_in_cell.pdf

Image in cell
Image in cell

There is more than one way to do this.

In the PositionContentInCell example, I used a method that allows you to really fine-tune the exact position of the text. I created an ImageEvent to scale and center the image:

class ImageEvent implements PdfPCellEvent {
    protected Image img;
    public ImageEvent(Image img) {
        this.img = img;
    }
    public void cellLayout(PdfPCell cell, Rectangle position, PdfContentByte[] canvases) {
        img.scaleToFit(position.getWidth(), position.getHeight());
        img.setAbsolutePosition(position.getLeft() + (position.getWidth() - img.getScaledWidth()) / 2,
                position.getBottom() + (position.getHeight() - img.getScaledHeight()) / 2);
        PdfContentByte canvas = canvases[PdfPTable.BACKGROUNDCANVAS];
        try {
            canvas.addImage(img);
        } catch (DocumentException ex) {
            // do nothing
        }
    }
}

I created a PositionEvent to add the text inside the cell:

class PositionEvent implements PdfPCellEvent {
    protected Phrase content;
    protected POSITION pos;
 
    public PositionEvent(Phrase content, POSITION pos) {
        this.content = content;
        this.pos = pos;
    }
 
    public void cellLayout(PdfPCell cell, Rectangle position, PdfContentByte[] canvases) {
        PdfContentByte canvas = canvases[PdfPTable.TEXTCANVAS];
        float x = 0;
        float y = 0;
        int alignment = 0;
        switch (pos) {
            case TOP_LEFT:
                x = position.getLeft(3);
                y = position.getTop(content.getLeading());
                alignment = Element.ALIGN_LEFT;
                break;
            case TOP_RIGHT:
                x = position.getRight(3);
                y = position.getTop(content.getLeading());
                alignment = Element.ALIGN_RIGHT;
                break;
            case BOTTOM_LEFT:
                x = position.getLeft(3);
                y = position.getBottom(3);
                alignment = Element.ALIGN_LEFT;
                break;
            case BOTTOM_RIGHT:
                x = position.getRight(3);
                y = position.getBottom(3);
                alignment = Element.ALIGN_RIGHT;
                break;
        }
        ColumnText.showTextAligned(canvas, alignment, content, x, y, 0);
    }
}

This is how I use these events:

public void createPdf(String dest) throws IOException, DocumentException {
    // 1. Create a Document which contains a table:
    Document document = new Document();
    PdfWriter.getInstance(document, new FileOutputStream(dest));
    document.open();
    PdfPTable table = new PdfPTable(2);
    PdfPCell cell1 = new PdfPCell();
    PdfPCell cell2 = new PdfPCell();
    PdfPCell cell3 = new PdfPCell();
    PdfPCell cell4 = new PdfPCell();
    // 2. Inside that table, make each cell with specific height:
    cell1.setFixedHeight(50);
    cell2.setFixedHeight(50);
    cell3.setFixedHeight(50);
    cell4.setFixedHeight(50);
    // 3. Each cell has the same background image
    ImageEvent imgEvent = new ImageEvent(Image.getInstance(IMG));
    cell1.setCellEvent(imgEvent);
    cell2.setCellEvent(imgEvent);
    cell3.setCellEvent(imgEvent);
    cell4.setCellEvent(imgEvent);
    // 4. Add text in front of the image at specific position
    cell1.setCellEvent(new PositionEvent(new Phrase("Top left"), POSITION.TOP_LEFT));
    cell2.setCellEvent(new PositionEvent(new Phrase("Top right"), POSITION.TOP_RIGHT));
    cell3.setCellEvent(new PositionEvent(new Phrase("Bottom left"), POSITION.BOTTOM_LEFT));
    cell4.setCellEvent(new PositionEvent(new Phrase("Bottom right"), POSITION.BOTTOM_RIGHT));
    // Wrap it all up!
    table.addCell(cell1);
    table.addCell(cell2);
    table.addCell(cell3);
    table.addCell(cell4);
    document.add(table);
    document.close();
}

Normally, I would write this code in a more efficient way, but I order the code lines in a way so that they reflect your requirements 1, 2, 3 and 4 literally.

OK, but how can I stretch the image?

Scaled image in cell
Scaled image in cell

You could use the scaleAbsolute() method:

public void cellLayout(PdfPCell cell, Rectangle position, PdfContentByte[] canvases) {
    img.scaleAbsolute(position.getWidth(), position.getHeight());
    img.setAbsolutePosition(position.getLeft(), position.getBottom());
    PdfContentByte canvas = canvases[PdfPTable.BACKGROUNDCANVAS];
    try {
        canvas.addImage(img);
    } catch (DocumentException ex) {
        // do nothing
    }
}

How can I position the image inside a cell using x and y coordinates

That required an extra example: PositionContentInCell2

Instead of using the POSITION enumeration, you asked if it was possible to pass x and y values. You could do that, but you probably won't always know the width and the height of the cells, so why not define percentages such as wPct and hPct, along with an alignment:

class PositionEvent implements PdfPCellEvent {
    protected Phrase content;
    protected float wPct;
    protected float hPct;
    protected int alignment;
    public PositionEvent(Phrase content, float wPct, float hPct, int alignment) {
        this.content = content;
        this.wPct = wPct;
        this.hPct = hPct;
        this.alignment = alignment;
  1. }
    public void cellLayout(PdfPCell cell, Rectangle position, PdfContentByte[] canvases) {
        PdfContentByte canvas = canvases[PdfPTable.TEXTCANVAS];
        float x = position.getLeft() + wPct * position.getWidth();
        float y = position.getBottom() + hPct * (position.getHeight() - content.getLeading());
        ColumnText.showTextAligned(canvas, alignment, content, x, y, 0);
  1. }
  1. }

Now you can add these events like this:

cell1.setCellEvent(new PositionEvent(new Phrase(14, "Top left"), 0, 1, Element.ALIGN_LEFT));
cell2.setCellEvent(new PositionEvent(new Phrase(14, "Top right"), 1, 1, Element.ALIGN_RIGHT));
cell3.setCellEvent(new PositionEvent(new Phrase(14, "Top center"), 0.5f, 1, Element.ALIGN_CENTER));
cell4.setCellEvent(new PositionEvent(new Phrase(14, "Bottom center"), 0.5f, 0, Element.ALIGN_CENTER));
cell5.setCellEvent(new PositionEvent(new Phrase(14, "Middle center"), 0.5f, 0.5f, Element.ALIGN_CENTER));
cell6.setCellEvent(new PositionEvent(new Phrase(14, "Middle center"), 0.5f, 0.5f, Element.ALIGN_CENTER));
cell7.setCellEvent(new PositionEvent(new Phrase(14, "Bottom left"), 0, 0, Element.ALIGN_LEFT));
cell8.setCellEvent(new PositionEvent(new Phrase(14, "Bottom right"), 1, 0, Element.ALIGN_RIGHT));