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.pngAnd 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:
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.pngPHP 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:
$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.pngPHP:
<?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:
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 FotoliaFrequently 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);
}
Martin E. Psinas is a self-taught web developer, published author, and is currently studying Japanese. For more information, visit his website.