How to add text to an image?

2019-01-09 18:29发布

问题:

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 preceded 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?

回答1:

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. In this case, 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