How to add text to an image?

Category: 
Tags: imageswatermarkimage sequencePdfTemplatecell eventbackground imageimage in celliText 5

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

This is a good example of a question that is phrased in a way that nobody can answer it correctly. After a lot of back and forth comments, it was finally clear that the OP wanted to add a text watermark to an image. Badly phrase questions can be very frustrating. Please take that in consideration when asking a question. In this case, I gave several wrong answers before it became clear what was actually asked.

First things first: when adding text and images to a page, iText sometimes changes the order of the textual content and the image. You can avoid this by using:

writer.setStrictImageSequence(true);

If you want to know the current position of the "cursor", you can use the method getVerticalPosition(). Unfortunately, this method isn't very elegant: it requires a Boolean parameter that will add a newline (if true) or give you the position at the current line (if false).

I do not understand why you want to get the vertical position. Is it because you want to have a caption followed by an image, and you want the caption and the image to be at the same page?

In that case, you could put your text and images inside a table cell and instruct iText not to split rows. iText will forward both text and image, in the correct order to the next page if the content doesn't fit the current page.

Update:

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 this example, we create a PdfTemplate to which we add an image as well as some text written on top of that image. We can then wrap this PdfTemplate inside an image and add that image together with its watermark using a single document.add() statement.

This is the method that performs all the magic:

public Image getWatermarkedImage(PdfContentByte cb, Image img, String watermark)
    throws DocumentException {
    float width = img.getScaledWidth();
    float height = img.getScaledHeight();
    PdfTemplate template = cb.createTemplate(width, height);
    template.addImage(img, width, 0, 0, height, 0, 0);
    ColumnText.showTextAligned(template, Element.ALIGN_CENTER,
            new Phrase(watermark, FONT), width / 2, height / 2, 30);
    return Image.getInstance(template);
}

This is how we add the images:

PdfContentByte cb = writer.getDirectContentUnder();
document.add(getWatermarkedImage(cb, Image.getInstance(IMAGE1), "Bruno"));
document.add(getWatermarkedImage(cb, Image.getInstance(IMAGE2), "Dog"));
document.add(getWatermarkedImage(cb, Image.getInstance(IMAGE3), "Fox"));
Image img = Image.getInstance(IMAGE4);
img.scaleToFit(400, 700);
document.add(getWatermarkedImage(cb, img, "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 PdfPCell. This PdfPCell will scale the image so that it fits the width of the page. To add the watermark, we use a cell event:

class WatermarkedCell implements PdfPCellEvent {
    String watermark;
    public WatermarkedCell(String watermark) {
        this.watermark = watermark;
    }
    public void cellLayout(PdfPCell cell, Rectangle position,
        PdfContentByte[] canvases) {
        PdfContentByte canvas = canvases[PdfPTable.TEXTCANVAS];
        ColumnText.showTextAligned(canvas, Element.ALIGN_CENTER,
            new Phrase(watermark, FONT),
            (position.getLeft() + position.getRight()) / 2,
            (position.getBottom() + position.getTop()) / 2, 30);
    }
}

This cell event can be used like this:

PdfPCell cell;
cell = new PdfPCell(Image.getInstance(IMAGE1), true);
cell.setCellEvent(new WatermarkedCell("Bruno"));
table.addCell(cell);
cell = new PdfPCell(Image.getInstance(IMAGE2), true);
cell.setCellEvent(new WatermarkedCell("Dog"));
table.addCell(cell);
cell = new PdfPCell(Image.getInstance(IMAGE3), true);
cell.setCellEvent(new WatermarkedCell("Fox"));
table.addCell(cell);
cell = new PdfPCell(Image.getInstance(IMAGE4), true);
cell.setCellEvent(new WatermarkedCell("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 PdfContentByteText 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(PdfContentByte cb, Image img, String watermark)
    throws DocumentException {
    float width = img.getScaledWidth();
    float height = img.getScaledHeight();
    PdfTemplate template = cb.createTemplate(width, height);
    template.addImage(img, width, 0, 0, height, 0, 0);
    ColumnText.showTextAligned(template, Element.ALIGN_CENTER,
            new Phrase(watermark, FONT), width / 2, height / 2, 30);
    return Image.getInstance(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:

public void createPdf(String dest) throws IOException, DocumentException {
    Document document = new Document();
    PdfWriter writer = PdfWriter.getInstance(document, new FileOutputStream(dest));
    document.open();
    PdfPTable table = new PdfPTable(1);
    for (int i = 0; i < 50; i++) {
        table.addCell("rahlrokks doesn't listen to what people tell him");
    }
    PdfContentByte cb = writer.getDirectContentUnder();
    table.addCell(getWatermarkedImage(cb, Image.getInstance(IMAGE1), "Bruno"));
    document.add(table);
    ColumnText.showTextAligned(cb, Element.ALIGN_CENTER,
        new Phrase("Bruno knows best"), 260, 400, 45);
    document.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!