Miguel Ventura's blog : django-imagekit watermarks

I've been playing around implementing watermark processors for django-imagekit. There was an open request for an overlay processor (which is kind of the same thing), and I wanted to explore a bit more PIL and imagekit processors.

So far, I've created processors that take text and images to overlay in the base image. At the time, the code is available in a fork of imagekit.

Examples

Overlaying text

Drave

Using TextWatermark we can overlay some text in the following manner

img = Image.open("drave_base.jpg")

title_mark = TextWatermark("Views from Drave",
    font=("/Library/Fonts/Arial Bold.ttf", 16),
    text_color="red",
    position=(20,20),
    opacity=1)

copy_mark = TextWatermark("Photo taken by myself. No copyright.",
    font=("/Library/Fonts/Arial Bold.ttf", 16),
    text_color="#ff0",
    position=(-20,-20),
    opacity=0.5)

img = title_mark.process(img)
img = copy_mark.process(img)

And the resulting img would be

Drave with captions

In TextWatermark, all configuration is optional, except for the text to be written.

You see, you can use names for text_color or HTML color notation (or any format supported by PIL.ImageColor). opacity takes a float ranging from 0 to 1. The position parameter accepts tuples containing horizontal and vertical position values. The values can be specified as strings (such as top, left, bottom, right and center), strings containing percentages (such as "25%") or integers. If the percentages or integers are negative, they're measured form the bottom-right instad of the top-left point.

The font parameter may be a path to a TrueType font file or a tuple with a path and a size. Unfortunely there's no font discovery: you have to specify the full path to the font file.

Overlaying images

With ImageWatermark we can overlay one image on another. We'll use the landscape image with this star:

star image

The watermark can be provided to the processor as a str with the path to the image, an Image object or a storage (file-like object).

Here's some sample code on how we could use this processor.

img = Image.open("drave_base.jpg")

# any of these could be used
watermark = "200-star.png"
watermark = Image.open("200-star.png")
watermark = open("200-star.png") # if you use a file-like object
                                 # remember to close your file when done

scaled = ImageWatermark(watermark,
    position=('center', 'center'),
    scale=True,
    opacity=0.2)

repeated = ImageWatermark(watermark,
    position=('right', 'bottom'),
    repeat=True,
    opacity=0.2)

img_scaled = scaled.process(img)
img_repeated = repeated.process(img)

Would result in img_scaled:

Drave with big star

And img_repeated:

Drave full of stars

For performance tuning, it's better to setup the watermark image to be used by path or storage object. Using an Image object will require the Image to be kept in memory forever (which may be a problem depending on the size and amount of images you'll be using). By default, the watermark will be cached using a weak reference, so the image processor doesn't need to constantly fetch it from storage and the image may be collected in case your process gets low on memory.

I hope this code can be of use to you. If you have any issues or requests, please send them through GitHub.