How to add text to an image?

Category: 
Tags: imageswatermarkimage sequencecell rendererbackground imageimage in celliText 7

This was the original question:

Pdf vertical postion method gives the next page position instead of current page

In my project I use iText to generate a PDF document. Suppose that the height of a page measures 500pt (1 user unit = 1 point), and that I write some text to the page, followed by an image. If the content and the image require less than 450pt, the text precedes the image. If the content and the image exceed 450pt, the text is forwarded to the next page. My question is: how can I obtain the remaining available space before writing an image?

Posted on StackOverflow on Nov 6, 2014 by Madhesh

Based on the extra information added in the comments, it is now clear that the OP wants to add images that are watermarked.

There are two approaches to achieve this, depending on the actual requirement.

Approach 1:

The first approach is explained in the WatermarkedImages1 example. In iText 7 we create a PdfFormXObject template as a Rectangle with the proper width and height. From this template we create a Canvas, where we can add an image as well as some text written on top of that image. We can then wrap this PdfFormXObject inside an image and add that image together with its watermark using a single doc.add() statement.

This is the method that performs all the magic:

public Image getWatermarkedImage(PdfDocument pdfDoc, Image img, String watermark) {
    float width = img.getImageScaledWidth();
    float height = img.getImageScaledHeight();
    PdfFormXObject template = new PdfFormXObject(new Rectangle(width, height));
    new Canvas(template, pdfDoc).
            add(img).
            setFontColor(DeviceGray.WHITE).
            showTextAligned(watermark, width / 2, height / 2, TextAlignment.CENTER, (float) Math.PI / 6);
    return new Image(template);
}

This is how we add the images:

Document doc = new Document(pdfDoc);
doc.add(getWatermarkedImage(pdfDoc, new Image(ImageDataFactory.create(IMAGE1)), "Bruno"));
doc.add(getWatermarkedImage(pdfDoc, new Image(ImageDataFactory.create(IMAGE2)), "Dog"));
doc.add(getWatermarkedImage(pdfDoc, new Image(ImageDataFactory.create(IMAGE3)), "Fox"));
Image image = new Image(ImageDataFactory.create(IMAGE4));
image.scaleToFit(400, 700);
doc.add(getWatermarkedImage(pdfDoc, image, "Bruno and Ingeborg"));

As you can see, we have one very large image (a picture of my wife and me). We need to scale this image so that it fits the page. If you want to avoid this, take a look at the second approach.

Approach 2:

The second approach is explained in the WatermarkedImages2 example. In this case, we add each image to a Cell. This Cell will scale the image so that it fits the width of the page. To add the watermark, we use a cell renderer:

private class WatermarkedCellRenderer extends CellRenderer {
    private String content;
    public WatermarkedCellRenderer(Cell modelElement, String content) {
        super(modelElement);
        this.content = content;
    }
    @Override
    public CellRenderer getNextRenderer() {
        return new WatermarkedCellRenderer((Cell) modelElement, content);
    }
    @Override
    public void draw(DrawContext drawContext) {
        super.draw(drawContext);
        Paragraph p = new Paragraph(content).setFontColor(DeviceRgb.WHITE);
        Rectangle rect = getOccupiedAreaBBox();
        new Canvas(drawContext.getCanvas(), drawContext.getDocument(), getOccupiedAreaBBox())
                .showTextAligned(p, (rect.getLeft() + rect.getRight()) / 2, (rect.getBottom() + rect.getTop()) / 2,
                        getOccupiedArea().getPageNumber(), TextAlignment.CENTER, VerticalAlignment.MIDDLE, (float) Math.PI / 6);
    }
}

This cell renderer can be used like this:

Cell cell;

cell = new Cell().add(new Image(ImageDataFactory.create(IMAGE1)).setAutoScaleWidth(true));
cell.setNextRenderer(new WatermarkedCellRenderer(cell, "Bruno"));
table.addCell(cell);

cell = new Cell().add(new Image(ImageDataFactory.create(IMAGE2)).setAutoScaleWidth(true));
cell.setNextRenderer(new WatermarkedCellRenderer(cell, "Dog"));
table.addCell(cell);

cell = new Cell().add(new Image(ImageDataFactory.create(IMAGE3)).setAutoScaleWidth(true));
cell.setNextRenderer(new WatermarkedCellRenderer(cell, "Fox"));
table.addCell(cell);

cell = new Cell().add(new Image(ImageDataFactory.create(IMAGE4)).setAutoScaleWidth(true));
cell.setNextRenderer(new WatermarkedCellRenderer(cell, "Bruno and Ingeborg"));
table.addCell(cell);

You will use this approach if all images have more or less the same size, and if you don't want to worry about fitting the images on the page.

Consideration:

Obviously, both approaches have a different result because of the design choice that is made. Please compare the resulting PDFs to see the difference: watermark_template.pdf versus watermark_table.pdf

Related question:

I'm creating a PDF using iTextSharp and it contains a table that spans multiple pages. After adding the table, my pdf PDF document has 3 pages. Now I want to add a signature image and add some text on that signature image using PdfContentByte. Text added on top of an image I also want to add some text on the last page using PdfContentByte. I've tried the ImageWatermark examples, but they don't work.

Posted on StackOverflow on Feb 14, 2015 by rahlrokks

Please take a look at the WatermarkedImages3 example.

public Image getWatermarkedImage(PdfDocument pdfDoc, Image img, String watermark) {
    float width = img.getImageScaledWidth();
    float height = img.getImageScaledHeight();
    PdfFormXObject template = new PdfFormXObject(new Rectangle(width, height));
    new Canvas(template, pdfDoc).
            add(img).
            setFontColor(DeviceGray.WHITE).
            showTextAligned(watermark, width / 2, height / 2, TextAlignment.CENTER, (float) Math.PI * 30f / 180f);
    return new Image(template);
}

Rahlrokks claims that this doesn't work. It is easy to prove that rahlrokks is not telling us the truth. If we look at watermark3.pdf, we clearly see the text added on top of the image on the last page.

Text added on top of an image
Text added on top of an image

I've also answered the second question about adding text using ColumnText. In iText 7 we use doc.showTextAligned() method:

protected void manipulatePdf(String dest) throws Exception {
    PdfDocument pdfDoc = new PdfDocument(new PdfWriter(dest));
    Document doc = new Document(pdfDoc);
    Table table = new Table(1).setWidthPercent(80);
    for (int i = 0; i < 35; i++) {
        table.addCell(new Cell().add("rahlrokks doesn't listen to what people tell him"));
    }
    table.addCell(new Cell().add(getWatermarkedImage(pdfDoc, new Image(ImageDataFactory.create(IMAGE1)), "Bruno").setAutoScale(true)));
    doc.add(table);
    doc.showTextAligned("Bruno knows best", 260, 400, TextAlignment.CENTER, 45f * (float) Math.PI / 180f);
    doc.close();
}

Not only am I adding text on the image, I am also adding text on the last page using PdfContentByte:

Adding text using PdfContentByte
Adding text using PdfContentByte

I'm sorry rahlrokks, but you should not say it doesn't work in cases where it's so easy to prove that it does work!

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