"
This article is part of in the series
Last Updated: Friday 10th May 2013
The module we use in this recipe to resize an image with Python is PIL. At the time of writing, it is only available for Python 2.x. Also, if you wish to do other things with images, checkout our article on how to resize an image with Python.

When you take photographs and post it onto the internet, it is often handy adding a watermark to prevent and discourage unauthorized copies or image theft.

Below is a simple Python script that uses the PIL module to watermark your images. It adds a visible text watermark to the image using the system font.

[python]
from PIL import Image, ImageDraw, ImageFont, ImageEnhance
import os, sys

FONT = 'Arial.ttf'
[/python]

We start with importing the PIL modules and load the Truetype font 'Arial.ttf'. By default, it searches for the font in the same folder and then it looks into your font directory (eg. C:/Windows/Fonts)

[python]
def add_watermark(in_file, text, out_file='watermark.jpg', angle=23, opacity=0.25):
[/python]

We define a function add_watermark and declare some default parameters.

  • in_file – Input file name.
  • text – Watermark text.
  • out_file – Output file name (default: watermark.jpg).
  • angle – Angle of the watermark (default: 23 degrees).
  • opacity – Level of opacity (default: 0.25)

[python]
img = Image.open(in_file).convert('RGB')
watermark = Image.new('RGBA', img.size, (0,0,0,0))
[/python]

First, we open the input file and create a watermark image of similar dimensions. Both files need to be in RGB mode since we are working with the alpha channel.

[python]
size = 2
n_font = ImageFont.truetype(FONT, size)
n_width, n_height = n_font.getsize(text)
[/python]

Starting with font size 2, we create the text and obtain the width and height of the text.

[python]
while (n_width+n_height < watermark.size[0]):
size += 2
n_font = ImageFont.truetype(FONT, size)
n_width, n_height = n_font.getsize(text)
[/python]

By incrementing the font size, we search for a text length that doesn't exceed the dimension (width) of the image.

[python]
draw = ImageDraw.Draw(watermark, 'RGBA')
draw.text(((watermark.size[0] - n_width) / 2,
(watermark.size[1] - n_height) / 2),
text, font=n_font)
[/python]

With the correct font size, we draw the text onto the center of the watermark image, using the system font declared in the header section.

[python]
watermark = watermark.rotate(angle, Image.BICUBIC)
[/python]

We then rotate the image (default is 23 degrees), using the Image.BICUBIC (algorithm) approximation.

[python]
alpha = watermark.split()[3]
alpha = ImageEnhance.Brightness(alpha).enhance(opacity)
watermark.putalpha(alpha)
[/python]

On the alpha channel, we reduce the opacity of the watermark (eg: reduce brightness and contrast) by the default value of 0.25. (Note: value 1 returns the original image).

[python]
Image.composite(watermark, img, watermark).save(out_file, 'JPEG')
[/python]

Lastly, we merge the watermark back into the original image and save it as a new JPEG file.

The entire code is as follows:

[python]
from PIL import Image, ImageDraw, ImageFont, ImageEnhance
import os, sys

FONT = 'Arial.ttf'

def add_watermark(in_file, text, out_file='watermark.jpg', angle=23, opacity=0.25):
img = Image.open(in_file).convert('RGB')
watermark = Image.new('RGBA', img.size, (0,0,0,0))
size = 2
n_font = ImageFont.truetype(FONT, size)
n_width, n_height = n_font.getsize(text)
while n_width+n_height < watermark.size[0]:
size += 2
n_font = ImageFont.truetype(FONT, size)
n_width, n_height = n_font.getsize(text)
draw = ImageDraw.Draw(watermark, 'RGBA')
draw.text(((watermark.size[0] - n_width) / 2,
(watermark.size[1] - n_height) / 2),
text, font=n_font)
watermark = watermark.rotate(angle,Image.BICUBIC)
alpha = watermark.split()[3]
alpha = ImageEnhance.Brightness(alpha).enhance(opacity)
watermark.putalpha(alpha)
Image.composite(watermark, img, watermark).save(out_file, 'JPEG')

if __name__ == '__main__':
if len(sys.argv) < 3:
sys.exit('Usage: %s <input-image> <text> <output-image> ' \
'<angle> <opacity> ' % os.path.basename(sys.argv[0]))
add_watermark(*sys.argv[1:])
[/python]