Helpful Information
 
 
Category: Post a PHP snippet
GD - Overlay Watermark

This code overlays a watermark (transparent or not) on to an image using the GD image library. This code would be useful for websites that commonly have pictures uploaded to them and wish to overlay a watermark over them, as this code can be called in a url, thus from img tags. Such as image.php?image=uploaded-343223.jpg. The position of the watermark starts from the bottom right corner, and the offset can easily be configured with the $w_offset and $h_offset variables below.


<?php
// Velox Letum (2005)
// [email protected]

$image = $HTTP_GET_VARS['image']; // Useful if using in an img tag to call images
$image = str_replace(array("/", ".."), "", $image); // Prevent abuse
$overlay = 'overlay.png';
$dir = '../hresources/';

// A default image for the demo...remove if you wish.
if ($image == NULL) {
$image = 'donutland.jpg';
}

// Find if image exists
if (!file_exists($dir . $image)) {
die("Image does not exist.");
}

// Set offset from bottom-right corner
$w_offset = 0;
$h_offset = 0;

$extension = strtolower(substr($image, strrpos($image, ".") + 1));

// Load image from file
switch ($extension)
{
case 'jpg':
$background = imagecreatefromjpeg($dir . $image);
break;
case 'jpeg':
$background = imagecreatefromjpeg($dir . $image);
break;
case 'png':
$background = imagecreatefrompng($dir . $image);
break;
case 'gif':
$background = imagecreatefromgif($dir . $image);
break;
default:
die("Image is of unsupported type.");
}

// Find base image size
$swidth = imagesx($background);
$sheight = imagesy($background);

// Turn on alpha blending
imagealphablending($background, true);

// Create overlay image
$overlay = imagecreatefrompng($dir . $overlay);

// Get the size of overlay
$owidth = imagesx($overlay);
$oheight = imagesy($overlay);

// Overlay watermark
imagecopy($background, $overlay, $swidth - $owidth - $w_offset, $sheight - $oheight - $h_offset, 0, 0, $owidth, $oheight);

// Output header and final image
header("Content-type: image/jpeg");
header("Content-Disposition: filename=" . $image);
imagejpeg($background);

// Destroy the images
imagedestroy($background);
imagedestroy($overlay);

?>

A short description of what this code does and in what setting would really help. :)

My apologies, I will be sure to include a description and possible use for scripts in which they are not readily apparent.

OMG, thank you so much, you have no idea how long I've been search for a tutorial / script that i can use on my site. This has helped me so much! I really appreciate the snippet you have provided.:thumbsup:

Just so you know..

$image = imagecreatefromstring(file_get_contents('path/to/image.jpg'));
..removes the need for nasty switch statements.

Just so you know..

$image = imagecreatefromstring(file_get_contents('path/to/image.jpg'));
..removes the need for nasty switch statements.

But also slows down the script (possibly a fair bit based on the image), so I would reccomend going with the switch statement. :)

OMG, thank you so much, you have no idea how long I've been search for a tutorial / script that i can use on my site. This has helped me so much! I really appreciate the snippet you have provided.:thumbsup:

Glad to help. And that's why I used the switch statements, because imagecreatefromstring() really slowed it all down, especiallly when testing with 2048x1538 pixel images.

Hi all

I know this was posted a long time ago by Velox Letum but i am after something very similar to this as i require a watermarked image that will overlay the whole page.

Having read the post i do not fully understand what is required to be able to use it and where i would put the folders.

Any advice would be great and of huge benifit to me.

Thanks


Richard

Pretty much just PHP, and GD2. You'll probably want to use imagecopyresampled instead of imagecopy. That original script looks like he was keeping the images out of publicly accessible areas and watermarking them on-the-fly as they load in his webpages. That could put a large amount of stress on your server if you have more than a couple of images.

Instead of using a extention, cant you use getimagesize? eg.


$params = getimagesize($image) or die("File not found or supported");
switch($params[2]){
//1- gif
//2-jpeg
//3-Png
}

This would also mean that imagesx and imagesy would not have to be invoked as $params[0] and $params[1] would be their equivalents. Also the first check (!file_exists) is also redundant as getimagesize returns false if the selected file isnt a valid image or not found.

Im not sure if Im making any sense? Send me back to the loony bin someone.

Yes, you could use getimagesize() instead. :)

Thanks for the tips on this page guys. This version does (should do) the following:

1. Load the image and scale it to a given maximum dimension.
2. Load the watermark file
3. Work out the width of the image and the watermark and apply the watermark centrally
4. Create a thumbnail without a watermark but scaled to a given maximum dimension.
5. Save out both thumbnail and watermarked images to file.
6. Delete the orginal file.

I did it for me and my needs but it should be pretty easy to tweak.
Might help anyone putting up an image library ...



<?php

function waterMarkImage($catalogueRef, $imageName = '') {

$watermarkSrc = dirname(__FILE__) . '/spc_watermark.png';
$sourceDir = dirname(__FILE__) . '/tmp/';
$thumbnailDir = dirname(__FILE__) . '/../images/thumbs/';
$outputDir = dirname(__FILE__) . '/../images/large/';
$maximumDimension = 500; // max image dimension
$maximumThumbnail = 200; // max thumbnail dimension
if ($imageName == '') {
$imageName = $catalogueRef . ".jpg";
}
$rawImage = imagecreatefromjpeg($sourceDir . $imageName);

// ======================================================================== Find base image size & scale down to a max of 500px

$rawWidth = imagesx($rawImage);
$rawHeight = imagesy($rawImage);

$imageScaleTo = 1;


if ($rawWidth >= $rawHeight) { // if a landsscape or square image

if ($rawWidth > $maximumDimension) {
$imageScaleTo = $maximumDimension/$rawWidth;
}

// scale thumbnail
$thumbNailScale = $maximumThumbnail/$rawWidth;
$thumbNailWidth = $maximumThumbnail;
$thumbNailHeight = floor($rawHeight * $thumbNailScale);
$thumbNailImage = imagecreatetruecolor($thumbNailWidth, $thumbNailHeight);
imagecopyresampled($thumbNailImage, $rawImage, 0, 0, 0, 0, $thumbNailWidth, $thumbNailHeight, $rawWidth, $rawHeight);

} else { // if a portrait image

if ($rawHeight > $maximumDimension) {
$imageScaleTo = $maximumDimension/$rawHeight;
}

// scale thumbnail
$thumbNailScale = $maximumThumbnail/$rawHeight;
$thumbNailWidth = floor($rawWidth * $thumbNailScale);
$thumbNailHeight = $maximumThumbnail;
$thumbNailImage = imagecreatetruecolor($thumbNailWidth, $thumbNailHeight);
imagecopyresampled($thumbNailImage, $rawImage, 0, 0, 0, 0, $thumbNailWidth, $thumbNailHeight, $rawWidth, $rawHeight);

}

// ======================================================================== Create Output Image

$outputWidth = floor($rawWidth * $imageScaleTo);
$outputHeight = floor($rawHeight * $imageScaleTo);

$outputImage = Imagecreatetruecolor($outputWidth, $outputHeight);
imagecopyresampled($outputImage, $rawImage, 0, 0, 0, 0, $outputWidth, $outputHeight, $rawWidth, $rawHeight);

// Turn on alpha blending
imagealphablending($outputImage, true);

// Create overlay image
$watermark = imagecreatefrompng($watermarkSrc);

// Get the offset centring for the overlay
$offsetWidth = floor(($outputWidth - imagesx($watermark))/2);
$offsetHeight = floor(($outputHeight - imagesy($watermark))/2);

// Overlay watermark
imagecopy($outputImage, $watermark, $offsetWidth, $offsetHeight, 0, 0, imagesx($watermark), imagesy($watermark));

// Output header and final images to file
imagejpeg($outputImage, $outputDir . $catalogueRef . ".jpg");
imagejpeg($thumbNailImage, $thumbnailDir . $catalogueRef . ".jpg");

// Destroy the images
imagedestroy($outputImage);
imagedestroy($thumbNailImage);
imagedestroy($rawImage);
imagedestroy($watermark);

// clean up temp

unlink($sourceDir . $imageName);

}

?>

Glad to help. And that's why I used the switch statements, because imagecreatefromstring() really slowed it all down, especiallly when testing with 2048x1538 pixel images.

Any particular reason why you set up separate code for jpg and jpeg rather than placing both labels in front of the same code block.


case 'jpg':
case 'jpeg':
$background = imagecreatefromjpeg($dir . $image);
break;

Any particular reason why you set up separate code for jpg and jpeg rather than placing both labels in front of the same code block.


case 'jpg':
case 'jpeg':
$background = imagecreatefromjpeg($dir . $image);
break;

I couldn't say. It was so long ago I can hardly remember why I'd done a few things the way I did. :o

For anyone who may want it, here's a way to tile watermark the whole image:

Replace:

// Overlay watermark
imagecopy($background, $overlay, $swidth - $owidth - $w_offset, $sheight - $oheight - $h_offset, 0, 0, $owidth, $oheight);
With:

// Overlay watermark
$x = 0;
$y = 0;
$opacity = 100; // overlay's opacity (in percent)
while ($sheight > $y)
{
imagecopymerge($background, $overlay, $x, $y, 0, 0, $owidth, $oheight, $opacity);

if ($x < $swidth) {
$x = $x + $owidth;
}
else if ($x >= $swidth) {
$x = 0;
$y = $y + $oheight;
}
}

I like imagecopymerge better because you can control the opacity of the overlay. If you still wanna use imagecopy though, just change it, and take out the opacity parameter. If the opacity is 100%, it's identical to imagecopy anyway.










privacy (GDPR)