Share/Bookmark

Featured Posts

Video Game Website Gives all it's profit to Charity Sometimes you read an article that just makes you smile, this is such one: http://www.ps3attitude.com/new/2010/02/no-fuss-reviews-4000-charity/ A video game review website that has given all of it's...

Read more

SQL AD Group membership Hi all, I have been working on a way to return Active directory group membership from a linked AD server in SQL. Its quite hard as you can`t return it from the group - you have to return it from...

Read more

Face Detection with PHP A very useful piece of PHP code that will highlight any pictures where a face has been detected. Heres the first piece of PHP code you will need, it would be best to make this an include: [sourcecode...

Read more

Basic Guide to Database Normalisation: First Normal... Before I start talking about the normal forms, I thought it would be best to explain what I am planning to write about, and what normalisation is. I am going to cover what normalisation is for beginners...

Read more

Sony: Synonymous with Innovation Sony have always been on the leading edge of innovation. From creating the WalkMan back in the 80's to popularising the CD, DVD and Blu-Ray with their PlayStation products. In this article we're discussing...

Read more

Add a Watermark to Images on the Fly

Posted by matthew | Posted in Tutorial | Posted on 27-11-2009

Tags: ,

2

Adding a watermark to an image is quite easy with PHP and has many applications, such as branding or copy protection. So after the jump see just how easy it is, and let us know your thoughts.

First of make a page called “watermark.php” and paste the following code into it:

<?php
class watermark{
# given two images, return a blended watermarked image
function create_watermark( $main_img_obj, $watermark_img_obj, $alpha_level = 100 ) {
$alpha_level = 100; # convert 0-100 (%) alpha to decimal
# calculate our images dimensions
$main_img_obj_w = imagesx( $main_img_obj );
$main_img_obj_h = imagesy( $main_img_obj );
$watermark_img_obj_w = imagesx( $watermark_img_obj );
$watermark_img_obj_h = imagesy( $watermark_img_obj );
# determine center position coordinates
$main_img_obj_min_x = floor( ( $main_img_obj_w / 2 ) - ( $watermark_img_obj_w / 2 ) );
$main_img_obj_max_x = ceil( ( $main_img_obj_w / 2 ) + ( $watermark_img_obj_w / 2 ) );
$main_img_obj_min_y = floor( ( $main_img_obj_h / 2 ) - ( $watermark_img_obj_h / 2 ) );
$main_img_obj_max_y = ceil( ( $main_img_obj_h / 2 ) + ( $watermark_img_obj_h / 2 ) );
# create new image to hold merged changes
$return_img = imagecreatetruecolor( $main_img_obj_w, $main_img_obj_h );
# walk through main image
for( $y = 0; $y < $main_img_obj_h; $y++ ) {
for( $x = 0; $x < $main_img_obj_w; $x++ ) {
$return_color = NULL;
# determine the correct pixel location within our watermark
$watermark_x = $x - $main_img_obj_min_x;
$watermark_y = $y - $main_img_obj_min_y;
# fetch color information for both of our images
$main_rgb = imagecolorsforindex( $main_img_obj, imagecolorat( $main_img_obj, $x, $y ) );
# if our watermark has a non-transparent value at this pixel intersection
# and we're still within the bounds of the watermark image
if ($watermark_x >= 0 && $watermark_x < $watermark_img_obj_w &&
$watermark_y >= 0 && $watermark_y < $watermark_img_obj_h ) {
$watermark_rbg = imagecolorsforindex( $watermark_img_obj, imagecolorat( $watermark_img_obj, $watermark_x, $watermark_y ) );
# using image alpha, and user specified alpha, calculate average
$watermark_alpha = round( ( ( 127 - $watermark_rbg['alpha'] ) / 127 ), 2 );
$watermark_alpha = $watermark_alpha * $alpha_level;
# calculate the color 'average' between the two - taking into account the specified alpha level
$avg_red = $this->_get_ave_color( $main_rgb['red'],$watermark_rbg['red'],$watermark_alpha );
$avg_green = $this->_get_ave_color( $main_rgb['green'],$watermark_rbg['green'],$watermark_alpha );
$avg_blue = $this->_get_ave_color( $main_rgb['blue'],$watermark_rbg['blue'],$watermark_alpha );

# calculate a color index value using the average RGB values we've determined
$return_color = $this->_get_image_color( $return_img, $avg_red, $avg_green, $avg_blue );
# if we're not dealing with an average color here, then let's just copy over the main color
} else {
$return_color = imagecolorat( $main_img_obj, $x, $y );
} # END if watermark
# draw the appropriate color onto the return image
imagesetpixel( $return_img, $x, $y, $return_color );
} # END for each X pixel
} # END for each Y pixel
# return the resulting, watermarked image for display
return $return_img;
} # END create_watermark()
# average two colors given an alpha
function _get_ave_color( $color_a, $color_b, $alpha_level ) {
return round( ( ( $color_a * ( 1 - $alpha_level ) ) + ( $color_b * $alpha_level ) ) );
} # END _get_ave_color()
# return closest pallette-color match for RGB values
function _get_image_color($im, $r, $g, $b) {
$c=imagecolorexact($im, $r, $g, $b);
if ($c!=-1) return $c;
$c=imagecolorallocate($im, $r, $g, $b);
if ($c!=-1) return $c;
return imagecolorclosest($im, $r, $g, $b);
} # EBD _get_image_color()
} # END watermark API
?>
<?php

class watermark{

# given two images, return a blended watermarked image

function create_watermark( $main_img_obj, $watermark_img_obj, $alpha_level = 100 ) {

$alpha_level /= 100; # convert 0-100 (%) alpha to decimal

# calculate our images dimensions

$main_img_obj_w = imagesx( $main_img_obj );

$main_img_obj_h = imagesy( $main_img_obj );

$watermark_img_obj_w = imagesx( $watermark_img_obj );

$watermark_img_obj_h = imagesy( $watermark_img_obj );

# determine center position coordinates

$main_img_obj_min_x = floor( ( $main_img_obj_w / 2 ) - ( $watermark_img_obj_w / 2 ) );

$main_img_obj_max_x = ceil( ( $main_img_obj_w / 2 ) + ( $watermark_img_obj_w / 2 ) );

$main_img_obj_min_y = floor( ( $main_img_obj_h / 2 ) - ( $watermark_img_obj_h / 2 ) );

$main_img_obj_max_y = ceil( ( $main_img_obj_h / 2 ) + ( $watermark_img_obj_h / 2 ) );

# create new image to hold merged changes

$return_img = imagecreatetruecolor( $main_img_obj_w, $main_img_obj_h );

# walk through main image

for( $y = 0; $y < $main_img_obj_h; $y++ ) {

for( $x = 0; $x < $main_img_obj_w; $x++ ) {

$return_color = NULL;

# determine the correct pixel location within our watermark

$watermark_x = $x - $main_img_obj_min_x;

$watermark_y = $y - $main_img_obj_min_y;

# fetch color information for both of our images

$main_rgb = imagecolorsforindex( $main_img_obj, imagecolorat( $main_img_obj, $x, $y ) );

# if our watermark has a non-transparent value at this pixel intersection

# and we're still within the bounds of the watermark image

if ($watermark_x >= 0 && $watermark_x < $watermark_img_obj_w &&

$watermark_y >= 0 && $watermark_y < $watermark_img_obj_h ) {

$watermark_rbg = imagecolorsforindex( $watermark_img_obj, imagecolorat( $watermark_img_obj, $watermark_x, $watermark_y ) );

# using image alpha, and user specified alpha, calculate average

$watermark_alpha = round( ( ( 127 - $watermark_rbg['alpha'] ) / 127 ), 2 );

$watermark_alpha = $watermark_alpha * $alpha_level;

# calculate the color 'average' between the two - taking into account the specified alpha level

$avg_red = $this->_get_ave_color( $main_rgb['red'],$watermark_rbg['red'], $watermark_alpha );

$avg_green = $this->_get_ave_color( $main_rgb['green'],$watermark_rbg['green'],$watermark_alpha );

$avg_blue = $this->_get_ave_color( $main_rgb['blue'],$watermark_rbg['blue'],$watermark_alpha );

# calculate a color index value using the average RGB values we've determined

$return_color = $this->_get_image_color( $return_img, $avg_red, $avg_green, $avg_blue );

# if we're not dealing with an average color here, then let's just copy over the main color

} else {

$return_color = imagecolorat( $main_img_obj, $x, $y );

} # END if watermark

# draw the appropriate color onto the return image

imagesetpixel( $return_img, $x, $y, $return_color );

} # END for each X pixel

} # END for each Y pixel

# return the resulting, watermarked image for display

return $return_img;

} # END create_watermark()

# average two colors given an alpha

function _get_ave_color( $color_a, $color_b, $alpha_level ) {

return round( ( ( $color_a * ( 1 - $alpha_level ) ) + ( $color_b * $alpha_level ) ) );

} # END _get_ave_color()

# return closest pallette-color match for RGB values

function _get_image_color($im, $r, $g, $b) {

$c=imagecolorexact($im, $r, $g, $b);

if ($c!=-1) return $c;

$c=imagecolorallocate($im, $r, $g, $b);

if ($c!=-1) return $c;

return imagecolorclosest($im, $r, $g, $b);

} # EBD _get_image_color()

} # END watermark API

?>

This is the watermark function, however you don’t need to include it on your page, so hold your horses dear cardboard coder, next create a file called “image.php” and paste this code in:

<?php

# include our watermarking class

include 'watermark.php';

$watermark = new watermark();

# create image objects using our user-specified images

# NOTE: we're just going to assume we're dealing with a JPG and a PNG here - for example purposes

$main_img_obj = imagecreatefromjpeg('images/menus/'.$_GET['main']);

$watermark_img_obj = imagecreatefrompng('watermark.png');

# create our watermarked image - set 66% alpha transparency for our watermark

$return_img_obj = $watermark->create_watermark( $main_img_obj, $watermark_img_obj, 20 );

# display our watermarked image - first telling the browser that it's a JPEG,

# and that it should be displayed inline

header( 'Content-Type: image/jpeg' );

header( 'Content-Disposition: inline; filename=' . $_GET['src'] );

imagejpeg( $_GET['main'], '', 100 );

?>

Next upload the image you want to use as a watermark, it must be a PNG file and it must be 72 DPI. To add a watermark to any image just include images in your HTML like so:

<img src="/image.php?main=images/items/00000001.jpg&watermark=watermark.png">

Replace the main variable with the actual location of your image and the watermark variable with the location of your watermark, and that’s it!

This is also useful as when users right click and choose save as on an image, all they will get is a PHP file.

Please remember however doing this is CPU intensive so you need a decent server, so you may want to build a function that creates the images once and stores them somewhere ;-)

Comments (2)

Awesome job with the code formatting.

Thanks, we like everything to be colour coded makes it easier to read.

Write a comment