Adding a Watermark

A watermark is a pasted image with a transparent background and less than 100% opacity, so the underlying image is still partly visible.

Here’s a picture of a crab pasted onto the Crab Nebula:

We begin with the background image and a crab image with transparent background. (see Removing Image Background)

Let’s say we used this code:

from PIL import Image
nebula = Image.open('nebula.jpg')
crab = Image.open('crab.png')
nebula.paste(crab, (50, 115), mask=crab)
nebula.save('output.png')

Notice that the pasted image and the mask are the same RGBA image, crab.

That would would produce output like this:

The crab completely covers the background nebula, completely removing the sense of mystery. That’s because the image mask (alpha channel) stored in the crab.png file looks like this if you convert it to a grayscale image:

Alpha = 255 (fully opaque)

The light parts are completely opaque (a=255).

What we need instead is a mask like this:

Alpha = 150 (partially opaque)

The outside is still completely transparent (black / alpha = 0). The inside colors now have a=150 (gray) instead of a=255 (white), so the crab shape would be pasted in a ghostly way instead of completely covering up the nebula background.

Once you have a mask like this, it’s easy to paste the crab onto the nebula as a translucent watermark.
Let’s say the mask image is called crab_mask:

nebula.paste(crab, (50, 100), mask=crab_mask)

So how can you create that mask? Here’s one method.

from PIL import Image
crab = Image.open('crab.png')
crab_mask = Image.new('L', crab.size, 0)
crab_mask.paste(150, mask=crab)
crab_mask.save('mask.png')

We’re starting with a new 'L' mode image, all black (0), the same size as the crab. Then we paste a gray color (150) onto it in the shape of a crab with thisĀ  command:
crab_mask.paste(150, mask=crab)

(You don’t need to save the mask as a file, but that lets you see the mask.)

Alternate Method: Edit the Pixels

In case the method above confuses you, here’s another way to do it. We will loop through the pixel colors, and for any large alpha values (greater than 125), we will reduce alpha to exactly 125.

This method preserves the black (zero) alpha values, so it will still have a transparent background.

from PIL import Image
crab = Image.open('crab.png')
pix = crab.load()
for y in range(crab.height):
    for x in range(crab.width):
        r, g, b, a = pix[x,y]
        if a > 125:
            pix[x,y] = (r, g, b, 125)
crab.save('crab2.png')

# paste crab, using crab as its own mask
stars.paste(crab, (50, 100), mask=crab)

Tweak the Opacity of the Watermark

You can vary the alpha value etween 0 and 255 to set how visible the crab will be. You’ll need to try some values to see what looks good. Here’s the difference between 120 and 180 for the crab example:

Alpha = 120
Alpha = 180

Hopefully you will come up with something less lame than a crab in the Crab Nebula! Have fun!