Image Watermarks with Imagick

Imagine a friend of yours approaches you one day and would like you to build her a website so she can showcase her photography. She wants to be able to easily upload her photographs and have them watermarked so that people can’t easily steal them. “Don’t worry!” you tell her, because you know there are functions provided by the Imagick extension that makes watermarking images a breeze in PHP.

This article shares a few pointers on what makes an effective watermark, and then shows you how to use the Imagick functions to add a watermark to your image. Before you get started, make sure the Imagick extension is available on your host. It’s also advisable to find a few pictures you can test the watermark on to gauge it’s effectiveness.

What Makes a Good Watermark

For a watermark to be effective, it needs to visible against a wide variety of backgrounds. I suggest that you try to find at least one test photo that is very light, and another that is very dark. For example, these two prairie dog pictures from Shutterstock make a good test pair:

2 prairie dog pictures

It’s important that the watermark is transparent enough for you to still be able to see the original image, but opaque enough so it’s difficult for an unscrupulous person to remove. A 40% opacity level is probably a good starting point, and you can increase it or decrease it depending on the situation.

You also want the watermark to be large enough. If you simply put a small watermark in the lower right-hand corner, it’s a prime target for being cropped out. Watermarks that cover a large portion of the original image are more effective. See how iStockPhoto and Shutterstock watermark their work for an example.

Finally, the watermark should have contrast. Consider making the watermark dark with a light stroke or visa-versa. This is what iStockPhoto and Shutterstock do, and their mark is easily visible on all of their images whether the original image is light or dark.

For this article I’ll be using this as my watermark, a PNG file with about 40% opacity:

watermark

Adding a Watermark

Adding the watermark is a simple 4-step process: first you open the original image, next you open the watermark, then you overlay the watermark on top of the first image, and then either save or output the result. Here’s the code:

<?php
// Open the original image
$image = new Imagick();
$image->readImage("/path/to/image.jpg");

// Open the watermark
$watermark = new Imagick();
$watermark->readImage("/path/to/watermark.png");

// Overlay the watermark on the original image
$image->compositeImage($watermark, imagick::COMPOSITE_OVER, 0, 0);

// send the result to the browser
header("Content-Type: image/" . $image->getImageFormat());
echo $image;

You can open images from a path by creating a new instance of the Imagick class and using its readImage() method. One nice thing about Imagick is that it can open any time of file that ImageMagick was compiled to support, so you don’t need to explicitly tell it that the file is a JPEG or PNG; it’s smart enough to figure it out on its own.

To overlay the watermark image, you use the compositeImage() method. In this example, the method accepts four parameters: the first is the image that will be overlaid, the second is a predefined constant representing which type of composition operation Imagick should perform (there’s a whole slew to choose from to achieve different effects), and the third and fourth parameters are the X and Y coordinates at which to place the watermark measured in pixels from the top-left corner.

By default, PHP assumes your script’s output is HTML and sends a text/html Content-Type header automatically. If you output the image, the browser won’t handle it properly since the headers tell it you’re sending text. To avoid your visitors being greeted with a page of gibberish, you need to instruct PHP to send a more appropriate header using header() before sending the image. Instead of just hard-coding the Content-Type header’s value, the example accesses the image’s type using Imagick itself which is then used to construct an appropriate MIME type on the fly.

Here’s the end result, a watermarked image:

Scaling the Watermark

The previous example positioned the watermark at the top-left of the original image. While this approach is fine if you know the size of the original images beforehand since you can create the watermark with the appropriate dimensions, you might want a more robust approach in case the sizes of the original images vary. Such an approach might be to place the watermark in the center of the image, and scaling the watermark beforehand if it is larger than the original image.

<?php
$image = new Imagick();
$image->readImage("/path/to/image.jpg");

$watermark = new Imagick();
$watermark->readImage("/path/to/watermark.png");

// how big are the images?
$iWidth = $image->getImageWidth();
$iHeight = $image->getImageHeight();
$wWidth = $watermark->getImageWidth();
$wHeight = $watermark->getImageHeight();

if ($iHeight < $wHeight || $iWidth < $wWidth) {
    // resize the watermark
    $watermark->scaleImage($iWidth, $iHeight);

    // get new size
    $wWidth = $watermark->getImageWidth();
    $wHeight = $watermark->getImageHeight();
}

// calculate the position
$x = ($iWidth - $wWidth) / 2;
$y = ($iHeight - $wHeight) / 2;

$image->compositeImage($watermark, imagick::COMPOSITE_OVER, $x, $y);

header("Content-Type: image/" . $image->getImageFormat());
echo $image;

The getImageWidth() and getImageHeight() methods return the width and height of an image respectively, measured in pixels. By comparing the width and height of the watermark image to the those of the the original image, you can determine whether or not it is necessary to resize the watermark so it will fit on smaller images.

Resizing the watermark is accomplished by calling the scaleImage() method which takes an allowed width and height. The method will scale the image down so that the maximum width is no larger than the allowed width, and the maximum height is no larger than the allowed height, while maintaining the image’s aspect ratio.

And here’s the watermarked image that results from this example:

another watermarked prairie dog image

Summary

The Imagick library provides a comprehensive image processing API. Indeed, you’ve seen how easy it is to open images files, determine their dimensions and image format, scale them, and overlay one on top of another to watermark them.

Usually I suggest the documentation on php.net if you want to learn more about about the capabilities of an extension, but in the case of Imagick the documentation is spotty. Many methods have just their parameter list given. So if you want to learn more, php.net is still a good place to start but you may have to look for more information for the methods in some other form (the command line application, for example) on the ImageMagick site itself and Google.

Free book: Jump Start HTML5 Basics

Grab a free copy of one our latest ebooks! Packed with hints and tips on HTML5's most powerful new features.

  • http://harikt.com/blog Hari K T

    Good Post Tim.

  • Zlati Pehlivanov

    It would be great if there was a proper explanation how to install the imagick on php on Windows.

  • http://brianswebdesign.com Brian Temecula

    I had a project that I needed to do for a friend, and had procrastinated for many weeks before this article got me motivated to do it. I needed to apply a watermark to a gallery of artwork we put online. Thanks for the motivation!

  • http://web-majster.blogspot.com/ Web Majster

    You can use htaccess to add watermark to all images like here:
    http://web-majster.blogspot.com/2011/12/znak-wodny-na-wszystkich-obrazkach-w.html

  • http://www.kablowie.com Greg Bulmash

    I love ImageMagick and use it on FunDraw.com, but getting it installed on your server and getting the IMagick extension installed can be a difficult DIY project, and in cases of shared servers, you may not be able to do it at all.

    GD2, while not as capable is more widespread, which is why I wrote my heatmap overlay generator using it. I had to find out the mathematics of a multiply blend and write my own function to do it, because it’s not in GD2 (but is easy to do with ImageMagick). In the end, I went with GD2 and did the extra work because I wanted to open source the class and wanted people on shared servers to be able to use it.

  • Colin

    Thanks for a great ‘how to’… I noticed a typo in this line of text,: ‘One nice thing about Imagick is that it can open any *time* of file that ImageMagick was compiled to support’

    mahalo,

  • http://www.zakochaniwfotografii.pl Alex

    Hey, awesome script.
    I have a question though: if you want to use one watermark image for a portrait orientation and another one for a landscape orientation say portrait.png and landscape.png how would you append that to your script?

    Sorry I’m no programmer but this imagemagick is so awesome! :)

    Alex

  • blaaze

    works like charm, only thing is you should give absolute path to the images, else you will kill the httpd of the server

    have fun coding

  • zazah

    Hi,
    I want to know ho to use this post
    Please help me.
    I need to protect my pics.
    Thanks

  • http://bartmcleod.nl Bart McLeod

    Great post, I was looking for this.
    Just one minor thing, a typo:
    Actual: “it can open any time of file that ”
    Expected: “it can open any type of file that “