How to add a background image to a cell?

Tags: tablesimagescell rendererimage in celliText 7

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. Note that PdfPCell class does not exist in iText 7 anymore. You should use Cell instead. To add your own custom image and text you need to extend CellRenderer and override draw() method:

private class ImageAndPositionRenderer extends CellRenderer {
    private Image img;
    private String content;
    private POSITION position;

    public ImageAndPositionRenderer(Cell modelElement, Image img, String content, POSITION position) {
        super(modelElement);
        this.img = img;
        this.content = content;
        this.position = position;
    }

    @Override
    public void draw(DrawContext drawContext) {
        super.draw(drawContext);
        img.scaleToFit(getOccupiedAreaBBox().getWidth(), getOccupiedAreaBBox().getHeight());

        img.getProperty(Property.HORIZONTAL_SCALING);

        drawContext.getCanvas().addXObject(img.getXObject(),
                getOccupiedAreaBBox().getX() +
                        (getOccupiedAreaBBox().getWidth()
                                - img.getImageWidth() * (float) img.getProperty(Property.HORIZONTAL_SCALING)) / 2,
                getOccupiedAreaBBox().getY() +
                        (getOccupiedAreaBBox().getHeight()
                                - img.getImageHeight() * (float) img.getProperty(Property.VERTICAL_SCALING)) / 2,
                img.getImageWidth() * (float) img.getProperty(Property.HORIZONTAL_SCALING));
        drawContext.getCanvas().stroke();

        Paragraph p = new Paragraph(content);
        Leading leading = p.getDefaultProperty(Property.LEADING);
        Float defaultFontSize = new DocumentRenderer(new Document(drawContext.getDocument())).getPropertyAsFloat(Property.FONT_SIZE);

        float x;
        float y;
        TextAlignment alignment;
        switch (position) {
            case TOP_LEFT:
                x = getOccupiedAreaBBox().getLeft() + 3;
                y = getOccupiedAreaBBox().getTop() - defaultFontSize * leading.getValue();
                alignment = TextAlignment.LEFT;
                break;
            case TOP_RIGHT:
                x = getOccupiedAreaBBox().getRight() - 3;
                y = getOccupiedAreaBBox().getTop() - defaultFontSize * leading.getValue();
                alignment = TextAlignment.RIGHT;
                break;
            case BOTTOM_LEFT:
                x = getOccupiedAreaBBox().getLeft() + 3;
                y = getOccupiedAreaBBox().getBottom() + 3;
                alignment = TextAlignment.LEFT;
                break;
            case BOTTOM_RIGHT:
                x = getOccupiedAreaBBox().getRight() - 3;
                y = getOccupiedAreaBBox().getBottom() + 3;
                alignment = TextAlignment.RIGHT;
                break;
            default:
                x = 0;
                y = 0;
                alignment = TextAlignment.CENTER;
        }
        new Canvas(drawContext.getCanvas(), drawContext.getDocument(), getOccupiedAreaBBox()).showTextAligned(p, x, y, alignment);
    }
}

So we’ve set the rules too add an image and draw some text inside the cell. We’ll use ImageAndPositionRenderer in setNextRenderer() method like this:

cell1.setNextRenderer(new ImageAndPositionRenderer(cell1,
            new Image(ImageDataFactory.create(IMG)), "Top left", POSITION.TOP_LEFT));

Where cell1 is a Cell object. Don’t forget to set the specific height for each cell:

cell1.setHeight(50);

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?

Please check the PositionContentInCell example for the full code. As you see, we’ve used scaleToFit() method to stretch the image. Without this line, you’ll get the following result:

Scaled image in cell
Scaled image in cell

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:

private class ImageAndPositionRenderer extends CellRenderer {
    private Image img;
    private String content;
    private TextAlignment alignment;
    private float wPct;
    private float hPct;

    public ImageAndPositionRenderer(Cell modelElement, float wPct, float hPct,
                                    Image img, String content, TextAlignment alignment) {
        super(modelElement);
        this.img = img;
        this.content = content;
        this.alignment = alignment;
        this.wPct = wPct;
        this.hPct = hPct;
    }

    @Override
    public void draw(DrawContext drawContext) {
        super.draw(drawContext);

        drawContext.getCanvas().addXObject(img.getXObject(), getOccupiedAreaBBox());
        drawContext.getCanvas().stroke();

        float x = getOccupiedAreaBBox().getX() + wPct * getOccupiedAreaBBox().getWidth();
        float y = getOccupiedAreaBBox().getY() + hPct * (getOccupiedAreaBBox().getHeight() - drawContext.getCanvas().getGraphicsState().getLeading());
        new Document(drawContext.getDocument()).showTextAligned(content, x, y, alignment);

    }
}

Now you can add these events like this:

cell1.setNextRenderer(new ImageAndPositionRenderer(cell1, 0, 1,
            new Image(ImageDataFactory.create(IMG)), "Top left", TextAlignment.LEFT));

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