How to add a watermark to a page with an opaque image?

Tags: watermarkPdfStampertransparencyimagesgraphics stateiText 5

Is it possible to add a watermark that will be transparent on top of an image? I currently use:

PdfContentByte canvas = pdfStamper.getUnderContent(i);
ColumnText.showTextAligned(
    canvas, Element.ALIGN_CENTER, watermark, 298, 421, 45);
It works fine, but if the content consists of an image, the watermark is hidden by that image.

Posted on JIRA (our closed ticketing system for customers) on Mar 19, 2015

If you have opaque shapes in your PDF (such as images, but also colored shapes), you need to add the Watermark on top of the existing content:

PdfContentByte canvas = pdfStamper.getOverContent(i);

Now the text will cover the images, but it may hide some important information. If you want to avoid this, you need to introduce transparency.

I have written a simple example that shows how this is done. It is called TransparentWatermark Let's take a look at the result:

Three different watermarks
Three different watermarks

First I add the text "This watermark is added UNDER the existing content" under the existing content. Part of the text is hidden (as you indicate in your question). Then I add the text "This watermark is added ON TOP OF the existing content" on top of the existing content. This may be sufficient, unless you fear that some crucial information will get lost by covering the existing content. In that case, take a look at how I add the text "This TRANSPARENT watermark is added ON TOP OF the existing content":

public void manipulatePdf(String src, String dest) throws IOException, DocumentException {
    PdfReader reader = new PdfReader(src);
    int n = reader.getNumberOfPages();
    PdfStamper stamper = new PdfStamper(reader, new FileOutputStream(dest));
    PdfContentByte under = stamper.getUnderContent(1);
    Font f = new Font(FontFamily.HELVETICA, 15);
    Phrase p = new Phrase(
        "This watermark is added UNDER the existing content", f);
    ColumnText.showTextAligned(under, Element.ALIGN_CENTER, p, 297, 550, 0);
    PdfContentByte over = stamper.getOverContent(1);
    p = new Phrase("This watermark is added ON TOP OF the existing content", f);
    ColumnText.showTextAligned(over, Element.ALIGN_CENTER, p, 297, 500, 0);
    p = new Phrase(
        "This TRANSPARENT watermark is added ON TOP OF the existing content", f);
    over.saveState();
    PdfGState gs1 = new PdfGState();
    gs1.setFillOpacity(0.5f);
    over.setGState(gs1);
    ColumnText.showTextAligned(over, Element.ALIGN_CENTER, p, 297, 450, 0);
    over.restoreState();
    stamper.close();
    reader.close();
}

Some extra tips and tricks:

  • Always use saveState() and restoreState() when you change the graphics state. If you don't you may get undesirable effects such as other content that is affected by the changes you make (e.g. you don't want all the content to become transparent).

  • The default rendering mode of text is "fill", hence I change the fill opacity.

  • In this case, I defined a fill opacity of 50% (0.5f). Choose any value between 0.0f and 1.0f if you want to change the transparency of the text.