Posts Tagged ‘watermark’

Watermarks with PHP and IMagick

Saturday, August 30th, 2008

There are a lot of web sites, online communities and social networks that apply a watermark over photos uploaded from users. This watermark, usually a logo or a text with the service name, should be applied in a region of the image where there are no important things, because no one likes to see a text over his face.

This simple feature requires an algorithm to automatically select the best corner where apply the watermark.

The algorithm

The watermark should be placed in the corner with the lowest number of graphic details, in order to be as less invasive as possible. To select the best corner, the proposed algorithm counts the number of different colours inside each corner and applies the watermark to the corner with the lowest number of different colours.

This algorithm is very simple but effective, and can be described with the following steps:

  1. For each candidate image region (corners) calculate the number of different colours
  2. Select the image region with the lowest number of different colours
  3. Apply the watermark to the selected region

The code

Here is the code the PHP code of a function that selects the best corner of an image and then apply the watermark.

/**
 * Draw a watermark over an image (the watermark position is
 * selected automatically) and returns true. If the watermark
 * is bigger than the image, this method returns false.
 *
 * @param IMagick $image
 * @param IMagick $watermark
 * @param int $padding
 * @return bool
 */
private function drawWatermark($image, $watermark, $padding = 0)
{
	// Check if the watermark is bigger than the image
	$image_width 		= $image->getImageWidth();
	$image_height 		= $image->getImageHeight();
	$watermark_width 	= $watermark->getImageWidth();
	$watermark_height 	= $watermark->getImageHeight();

	if ($image_width < $watermark_width + $padding || $image_height < $watermark_height + $padding) {
		return false;
	}

	// Calculate each position
	$positions = array();
	$positions[] = array(0 + $padding, 0 + $padding);
	$positions[] = array($image_width - $watermark_width - $padding, 0 + $padding);
	$positions[] = array($image_width - $watermark_width - $padding, $image_height - $watermark_height - $padding);
	$positions[] = array(0 + $padding, $image_height - $watermark_height - $padding);

	// Initialization
	$min 		= null;
	$min_colors = 0;

	// Calculate the number of colors inside each region
	// and retrieve the minimum
	foreach($positions as $position)
	{
		$colors = $image->getImageRegion(
			$watermark_width,
			$watermark_height,
			$position[0],
			$position[1])->getImageColors();

		if ($min === null || $colors <= $min_colors)
		{
			$min 		= $position;
			$min_colors = $colors;
		}
	}

	// Draw the watermark
	$image->compositeImage(
		$watermark,
		Imagick::COMPOSITE_OVER,
		$min[0],
		$min[1]);

	return true;
}

(more…)