Image Watermarks with Imagick

    Timothy Boronczyk
    Share

    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.