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.
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
TextWatermark, all configuration is optional, except for the text to be
You see, you can use names for
text_color or HTML color notation (or any
format supported by PIL.ImageColor).
opacity takes a float
accepts tuples containing horizontal and vertical position values. The values
can be specified as strings (such as
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.
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.
ImageWatermark we can overlay one image on another. We'll use the
landscape image with this star:
The watermark can be provided to the processor as a
str with the path to
the image, an
Image object or a storage (
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
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.