Watermark images like a pro using Python + Wand + librsvg

This is a Python 2.7 code recipe for applying a semi-transparent vector (SVG) watermark with overlay blending like so:

What’s special about it:

  • The watermark is a vector image (SVG), which means it’d look sharp when placed on images of any sizes. The function scales the watermark proportionally to the width of the source image.
  • Supports blending modes (what’s that?), including my favorite “overlay”.
  • Watermark transparency level is a function argument. SVG transparency is also supported, so different parts of the watermark can have varying opaqueness.

Prerequisites: Wand, imagemagick (for Wand) and librsvg:

sudo apt-get/yum install librsvg imagemagick

If you’re on OS X and use Homebrew: brew install librsvg imagemagick

Install Wand using pip: pip install wand

Make sure rsvg-convert command is available in your shell.

import subprocess

from wand.image import Image as WandImage

def watermark(source, target, watermark, blend_mode='overlay', ratio=1, transparency=0.3):
    source_obj = WandImage(filename=source)
    watermark_obj = WandImage(filename=watermark)
    
    if ratio > 1:
        ratio = 1
    
    watermark_width = int(source_obj.size[0] * ratio)
    watermark_height = int(float(watermark_width) / float(watermark_obj.size[0]) * watermark_obj.size[1])
    
    rsvg = subprocess.Popen(
        ['rsvg-convert', '-a', '-h', str(watermark_height), watermark], 
        stdout=subprocess.PIPE
    )
    watermark_obj = WandImage(blob=rsvg.stdout.read())
    del rsvg
    
    watermark_obj.transparentize(transparency)
    source_obj.composite_channel(
        'all_channels', watermark_obj, blend_mode, 
        source_obj.size[0] / 2 - watermark_obj.size[0] / 2, 
        source_obj.size[1] / 2 - watermark_obj.size[1] / 2
    )
    
    source_obj.save(filename=target)
    
    return True

Minimal usage:

watermark('photo.jpg', 'photo+watermark.jpg', 'watermark.svg')

Why do you use librsvg? Because Imagemagick (which we use via Wand) isn’t as flexible when it comes to scaling vectors. When you ask Imagemagick to scale an SVG, it converts it to a raster PNG of arbitrary size and then scales the PNG, often making it very blurry.

Why don’t you use some librsvg binding? Because it works fine from subprocess and I’m lazy.

What other blend modes are available? See Wand docs under wand.image.COMPOSITE_OPERATORS.

Thanks to Alexander Norov who has helped me assemble this code.
License: MIT.

This entry was posted in Programming and tagged , . Bookmark the permalink.

4 Responses to Watermark images like a pro using Python + Wand + librsvg

  1. vaib says:

    pip install librsvg
    not working for windows system

    • Dae says:

      It seems librsvg isn’t available for Windows at all. But even if it was, I’m not sure my code would work on Windows because it relies on subprocess, sorry.

  2. Amy says:

    Mind if I ask what’s the font you used for example.com watermark (https://dae.me/storage/images/watermark.svg)?
    And what tools did you use to create this svg? I’ve tried 5 different png to svg converters and they all failed :(

    • Dae says:

      The font is probably Proxima Nova. I used Adobe Illustrator CC. PNG is a raster image, SVG contains vectors. Vectors can be scaled and this is cool because photos come in different sizes. Some photos are really big, some are small, yet the watermark should look crisp and sharp on either. PNG cannot be used the same way, but if your photos are the same size and you don’t need to scale the watermark, its perfectly fine to use PNG.

Leave a Reply

Your email address will not be published. Required fields are marked *