Adding Text Watermarks with Imagick

    Martin Psinas
    Martin Psinas
    Share

    In a previous article, Timothy Boronczyk wrote about how to create watermarks with Imagick using an overlay image. In this article, I’ll show you how to achieve a similar effect using plain text. At the time of this writing, virtually no documentation exists on PHP’s Imagick API documentation, although there are plenty of command-line examples to be found on the ImageMagick website, so that is where we shall begin. Converting the command-line code from the examples into PHP is simply a tedious matter of finding the appropriate methods that perform the same functionality. For my examples I’ll be using the following image of some completely random handsome looking gentleman.

    Drawing Text on the Image

    The easiest type of textual watermark to create is a string overlay on top of the image. The command line example is:
    convert image.png  -font Arial -pointsize 20 
        -draw "gravity south
            fill black  text 0,12 'Copyright'
            fill white  text 1,11 'Copyright'" 
        result.png
    And the PHP equivalent is:
    <?php
    // Create objects
    $image = new Imagick('image.png');
    
    // Watermark text
    $text = 'Copyright';
    
    // Create a new drawing palette
    $draw = new ImagickDraw();
    
    // Set font properties
    $draw->setFont('Arial');
    $draw->setFontSize(20);
    $draw->setFillColor('black');
    
    // Position text at the bottom-right of the image
    $draw->setGravity(Imagick::GRAVITY_SOUTHEAST);
    
    // Draw text on the image
    $image->annotateImage($draw, 10, 12, 0, $text);
    
    // Draw text again slightly offset with a different color
    $draw->setFillColor('white');
    $image->annotateImage($draw, 11, 11, 0, $text);
    
    // Set output image format
    $image->setImageFormat('png');
    
    // Output the new image
    header('Content-type: image/png');
    echo $image;
    The result is:

    This example is pretty straight-forward and the code’s comments make it so you shouldn’t need much extra explanation. But while this works, the text stands out too drastically from the image and the effect should probably be more subtle.

    Transparent Text Using a Font Mask

    For a smoother effect on the watermark text, you can make the text string transparent using a font mask. Command line example:
    convert -size 300x50 xc:grey30 -font Arial -pointsize 20 
        -gravity center -draw "fill grey70  text 0,0  'Copyright'" 
        fgnd.png
    convert -size 300x50 xc:black -font Arial -pointsize 20 -gravity center 
        -draw "fill white  text  1,1  'Copyright'
            text  0,0  'Copyright'
            fill black  text -1,-1 'Copyright'" 
        +matte mask.png
    composite -compose CopyOpacity  mask.png  fgnd.png  stamp.png 
        mogrify -trim +repage stamp.png
    composite -gravity south -geometry +0+10 stamp.png  image.png 
        result.png
    PHP equivalent:
    <?php
    // Create objects
    $image = new Imagick('image.png');
    $watermark = new Imagick();
    $mask = new Imagick();
    $draw = new ImagickDraw();
    
    // Define dimensions
    $width = $image->getImageWidth();
    $height = $image->getImageHeight();
    
    // Create some palettes
    $watermark->newImage($width, $height, new ImagickPixel('grey30'));
    $mask->newImage($width, $height, new ImagickPixel('black'));
    
    // Watermark text
    $text = 'Copyright';
    
    // Set font properties
    $draw->setFont('Arial');
    $draw->setFontSize(20);
    $draw->setFillColor('grey70');
    
    // Position text at the bottom right of the image
    $draw->setGravity(Imagick::GRAVITY_SOUTHEAST);
    
    // Draw text on the watermark palette
    $watermark->annotateImage($draw, 10, 12, 0, $text);
    
    // Draw text on the mask palette
    $draw->setFillColor('white');
    $mask->annotateImage($draw, 11, 13, 0, $text);
    $mask->annotateImage($draw, 10, 12, 0, $text);
    $draw->setFillColor('black');
    $mask->annotateImage($draw, 9, 11, 0, $text);
    
    // This is needed for the mask to work
    $mask->setImageMatte(false);
    
    // Apply mask to watermark
    $watermark->compositeImage($mask, Imagick::COMPOSITE_COPYOPACITY, 0, 0);
    
    // Overlay watermark on image
    $image->compositeImage($watermark, Imagick::COMPOSITE_DISSOLVE, 0, 0);
    
    // Set output image format
    $image->setImageFormat('png');
    
    // Output the new image
    header('Content-type: image/png');
    echo $image;
    The result is:

    Several images are created in this example. The first image $watermark
    is grey-scale, and the second image $mask uses pure black for the parts I want to be transparent and white for the parts I want to keep. When I apply the mask by combining the images, any grey shades found in $mask as a result of anti-aliasing will be semi-transparent and result in smoother edges. In the command-line version of the code, the outside edges of the transparent image are clipped before the watermark is overlayed, but there appears to be a bug that prevents the compositeImage() method from preserving the position defined by setGravity()
    . This basically means that if I were to clip the edges then my watermark would lose its place at the bottom right and be re-positioned in the top-left corner. To get around this foolish behavior, I’ve created my palettes with the same dimensions as the source image so no clipping takes place.

    Tiled Text

    This final example tiles text over the entire image which makes it far more difficult to remove. Command line:
    convert -size 140x80 xc:none -fill grey 
        -gravity NorthWest -draw "text 10,10 'Copyright'" 
        -gravity SouthEast -draw "text 5,15 'Copyright'" 
        miff:- | 
    composite -tile - image.png  result.png
    PHP:
    <?php
    // Create objects
    $image = new Imagick('image.png');
    $watermark = new Imagick();
    
    // Watermark text
    $text = 'Copyright';
    
    // Create a new drawing palette
    $draw = new ImagickDraw();
    $watermark->newImage(140, 80, new ImagickPixel('none'));
    
    // Set font properties
    $draw->setFont('Arial');
    $draw->setFillColor('grey');
    $draw->setFillOpacity(.5);
    
    // Position text at the top left of the watermark
    $draw->setGravity(Imagick::GRAVITY_NORTHWEST);
    
    // Draw text on the watermark
    $watermark->annotateImage($draw, 10, 10, 0, $text);
    
    // Position text at the bottom right of the watermark
    $draw->setGravity(Imagick::GRAVITY_SOUTHEAST);
    
    // Draw text on the watermark
    $watermark->annotateImage($draw, 5, 15, 0, $text);
    
    // Repeatedly overlay watermark on image
    for ($w = 0; $w < $image->getImageWidth(); $w += 140) {
        for ($h = 0; $h < $image->getImageHeight(); $h += 80) {
            $image->compositeImage($watermark, Imagick::COMPOSITE_OVER, $w, $h);
        }
    }
    
    // Set output image format
    $image->setImageFormat('png');
    
    // Output the new image
    header('Content-type: image/png');
    echo $image;
    Result:

    Notice that I’ve set the transparency with setFillOpacity()
    rather than using an image mask.

    Summary

    For me, image manipulation in PHP has become one of the most enjoyable aspects of the language, and I can only hope that Imagick will become bundled in future versions. If you’re looking for a way to contribute, I encourage you to convert other command line examples to PHP and then post your results on the official PHP manual so others can learn and enjoy. Image via Fotolia

    Frequently Asked Questions (FAQs) on Adding Text Watermarks with Imagick

    How can I add a text watermark to an image using Imagick in PHP?

    To add a text watermark to an image using Imagick in PHP, you first need to create an instance of the Imagick class and read the image into it. Then, create an ImagickDraw instance and set the font properties. After that, you can add the text to the image using the annotateImage() method. Finally, write the image to the file system using the writeImage() method. Here is a basic example:

    $imagick = new \Imagick(realpath('image.png'));
    $draw = new \ImagickDraw();
    $draw->setFillColor('white');
    $draw->setFont('Arial');
    $draw->setFontSize(50);
    $imagick->annotateImage($draw, 10, 45, 0, 'Watermark Text');
    $imagick->writeImage('watermarked_image.png');

    How can I change the font color of the watermark text in Imagick?

    You can change the font color of the watermark text in Imagick by using the setFillColor() method of the ImagickDraw class. This method accepts a string representing the color. For example, to set the font color to red, you would do:

    $draw->setFillColor('red');

    How can I change the font size of the watermark text in Imagick?

    The font size of the watermark text in Imagick can be changed using the setFontSize() method of the ImagickDraw class. This method accepts an integer representing the font size. For example, to set the font size to 30, you would do:

    $draw->setFontSize(30);

    How can I change the font of the watermark text in Imagick?

    The font of the watermark text in Imagick can be changed using the setFont() method of the ImagickDraw class. This method accepts a string representing the font name. For example, to set the font to ‘Arial’, you would do:

    $draw->setFont('Arial');

    How can I position the watermark text in Imagick?

    The position of the watermark text in Imagick can be set using the annotateImage() method of the Imagick class. This method accepts four parameters: the ImagickDraw instance, the x and y coordinates of the text, the rotation angle of the text, and the text string. For example, to position the text at coordinates (10, 45), you would do:

    $imagick->annotateImage($draw, 10, 45, 0, 'Watermark Text');

    How can I rotate the watermark text in Imagick?

    The rotation of the watermark text in Imagick can be set using the annotateImage() method of the Imagick class. The fourth parameter of this method is the rotation angle of the text. For example, to rotate the text 45 degrees, you would do:

    $imagick->annotateImage($draw, 10, 45, 45, 'Watermark Text');

    How can I save the watermarked image in Imagick?

    The watermarked image can be saved using the writeImage() method of the Imagick class. This method accepts a string representing the file path. For example, to save the image as ‘watermarked_image.png’, you would do:

    $imagick->writeImage('watermarked_image.png');

    How can I add a transparent watermark text in Imagick?

    To add a transparent watermark text in Imagick, you can use the setFillOpacity() method of the ImagickDraw class. This method accepts a float representing the opacity level. For example, to set the opacity to 0.5, you would do:

    $draw->setFillOpacity(0.5);

    How can I add a shadow to the watermark text in Imagick?

    Adding a shadow to the watermark text in Imagick can be achieved by drawing the text twice: once for the shadow and once for the text itself. The shadow can be created by setting the fill color to black and offsetting the text position. For example:

    $draw->setFillColor('black');
    $imagick->annotateImage($draw, 12, 47, 0, 'Watermark Text');
    $draw->setFillColor('white');
    $imagick->annotateImage($draw, 10, 45, 0, 'Watermark Text');

    How can I add a watermark text to multiple images in Imagick?

    To add a watermark text to multiple images in Imagick, you can loop over the images and apply the watermark to each one. Here is a basic example:

    $images = ['image1.png', 'image2.png', 'image3.png'];
    foreach ($images as $image) {
    $imagick = new \Imagick(realpath($image));
    $draw = new \ImagickDraw();
    $draw->setFillColor('white');
    $draw->setFont('Arial');
    $draw->setFontSize(50);
    $imagick->annotateImage($draw, 10, 45, 0, 'Watermark Text');
    $imagick->writeImage('watermarked_' . $image);
    }