When bloggers post their images online, sometimes they want them watermarked - usually by adding a small, unobtrusive logo (or copyright info) to the image in one of the corners.

While one may use one of the graphic tools to do that prior to uploading, it's much more effective to do it programmatically, after upload.

WordPress requires the PHP GD library in order to process images, but there is a better alternative: ImageMagick (IM, for short). As this SitePoint article suggests, both have their pros and cons, but I prefer IM because it's not only much more powerful, it's also easier to write.

Before we proceed, make sure you have ImageMagick installed, along with it's PHP module for example on Debian/Ubuntu-based servers, run the following command:

$ sudo apt-get install imagemagick php5-imagick

Step 1: Register necessary image size

Before you can manipulate an image attachment, you need to register the image size you want to watermark:

function register_watermarked_size() {
  add_image_size( 'watermarked', 550, 550, true ); 
}

add_action( 'init', 'register_watermarked_size' ); 

In our case I've set the image to be 550x500 pixels wide and high and cropped (which is what the true argument does), but feel free to choose another size.

Step 2: Hook into metadata generation

WordPress comes with a filter called wp_generate_attachment_metadata which allows us to modify attachment metadata (the data about the attachment), which gets saved to the database. Here's the function we use to do that:

function generate_watermarked_image( $meta ) {

  $time = substr( $meta['file'], 0, 7); // Extract the date in form "2015/04"
  $upload_dir = wp_upload_dir( $time );

  $filename = $meta['sizes']['watermarked']['file'];
  $meta['sizes']['watermarked']['file'] = watermark_image( $filename, $upload_dir );

  return $meta;

}

add_filter( 'wp_generate_attachment_metadata', 'generate_watermarked_image' );

In this function, we define the $upload_dir variable, which is important for one reason (as opposed to just using wp_upload_dir() everywhere): Without the $time, WordPress might get confused on occasions where we upload attachments to articles that are from a previous month, resulting in images being saved in multiple different folders.

Following our upload dir definition, we store the original filename, then generate a new one, by calling the watermark_image function, which we're about to write. It's completely optional to generate a new one, but I like to add a string to the image name which let's me know the image has been manipulated in some way.

Step 3: Watermark image with ImageMagick

Now's the time for the meat of this tutorial, manipulating the image:

function watermark_image( $filename, $upload_dir ) {

  $original_image_path = trailingslashit( $upload_dir['path'] ) . $filename;

  $image_resource = new Imagick( $original_image_path );
  $image_resource->blurImage( 20, 10 );

  $watermark_resource = new Imagick( get_stylesheet_directory() . '/images/logo.png' );
  $image_resource->compositeImage( $watermark_resource, Imagick::COMPOSITE_DEFAULT, 100, 250 );

  return save_watermarked_image( $image_resource, $original_image_path );

}

First we get the image path of our unmodified image, and create a new Imagick object. As an example, I decided to both blur the image and then add the logo on top of it, approximately at the center. You might want to position it differently, according to your needs. As you might have noticed, the logo is also an Imagick object instance, and combining them is that easy!

Watermark WordPress image example
Left: Picard unmodified, right: Picard blurred and watermarked by ImageMagick

At this point, the image isn't saved yet, it dwells in our server's memory, waiting for us to release it! :)

Step 4: Save the new image

Now that our image is modified, let's save it:

function save_watermarked_image( $image_resource, $original_image_path ) {

  $image_data = pathinfo( $original_image_path );

  $new_filename = $image_data['filename'] . '-watermarked.' . $image_data['extension'];

  $watermarked_image_path = str_replace($image_data['basename'], $new_filename, $original_image_path);

  if ( ! $image_resource->writeImage( $watermarked_image_path ) )
    return $image_data['basename'];

  unlink( $original_image_path );

  return $new_filename;

}

The first three lines in this function are used to get the name of the originally uploaded image (of the defined size) then we just add the -watermarked to its name. As I mentioned above, it's not necessary but it's much easier to understand that image has been manipulated just by looking at it's name.

We wrap the saving part (writeImage) into an if statement to make sure it was written to disk properly - or return the original image name if not.

Lastly, we delete the original image (via unlink) as it won't be stored in the database, which means it would just occupy disk space for no purpose.

Conslusion

As you can see, ImageMagick makes it easy for us to watermark WordPress images or modify them in any way you can imagine, blurring and combining being just a starting point.

To save you some time, I uploaded the code from above into this gist - both the procedural and the more classy version. Feel free to use them however you like, just don't forget to tell around where you got them :)Quality: The Codeable Differene

  • plaidtractor

    Thanks so much for this. Will this work with the Imagemagick-engine plugin?

  • Shaun Bakic

    Doesn’t seem to work. I have imagick 3.4.3RC4 module installed and enabled.
    When I upload an image, it says HTTP error.