Watermark Images with Other Images and Text on the Fly

shabbir's Avatar author of Watermark Images with Other Images and Text on the Fly
This is an article on Watermark Images with Other Images and Text on the Fly in PHP.
Let us say you have some images and want to watermark those images with some other gif, jpeg, png images or with some plain text on the fly in PHP.

It actually looks tough but it is very simple. Let us take a real time example of profile picture option we have here at Go4Expert.com where if you visit the contact info tab of your profile you will see a code as follow.

HTML Code:
<A rel="nofollow" HREF="http://www.go4expert.com/member.php?u=1"><IMG SRC="http://www.go4expert.com/share/member1.jpg" WIDTH="120" HEIGHT="90" BORDER="0" ALT="shabbir's Profile at Go4Expert.com"></A>
And the output will be something like



But actually it is this image



Which converts into



Now let us see how.

Requirements



PHP 4+ and GD 2.0+.

Code



PHP Code:
$im imagecreatefromjpeg($baseimg); 
It loads the file into the PHP script using the GD library and gives us the opportunity to manipulate and/or output the image using our script.

We define variables for color and fonts which we will use to output the final text on the base image.
PHP Code:
$text_color[0] = imagecolorallocate($im2552550);
$text_color[1] = imagecolorallocate($im192192192);
$text_color[2] = imagecolorallocate($im255255255);
$text_color[3] = imagecolorallocate($im255255255);

$font[0] = DIR .'/images/user/fonts/arialbd.ttf';
$font[1] = DIR .'/images/user/fonts/arialbd.ttf';
$font[2] = DIR .'/images/user/fonts/arialbd.ttf';
$font[3] = DIR .'/images/user/fonts/arialbd.ttf'
If we already have an image for the user we should check for last updated time and if it is less than a day we just use the existing image and do not update the image with latest information. This is done to cache the image for a day and is updated every 24 hours.
PHP Code:
    $finalimg './advprofilepic/member'.$userid.'.jpg';

    if(
file_exists($finalimg))
    {
        
$cachetime TIMENOW 86400;
        if(
$cachetime filemtime($finalimg))
        {
            
header('Content-type: image/jpg');
            
readfile($finalimg);
            exit;
        }
    } 
Next we test for a user uploaded profile picture. If user has uploaded a profile picture we need to use the profile picture in our final image and depending on the uploaded image format we create the profile image from the file and then using imagecopyresampled we merge the two images at the desired locations.
PHP Code:
    // We have access to the linked image file
    
if (file_exists($profilepicurl))
    {
        list(
$width$height$image_type$attr) = getimagesize($profilepicurl);
        
$max_width 32;
        
$max_height 32;
        if(
$width $height)
        {
            
$width $height;
        }
        elseif(
$width $height)
        {
            
$height $width;
        }
        
$profileim imagecreatetruecolor($max_width,$max_height);
        
$bg_color imagecolorallocate ($profileim0,0,0); //background white
        
imagefilledrectangle ($profileim00$max_width$max_height$bg_color);
        switch (
$image_type)
        {
            case 
1$profileim imagecreatefromgif($userinfo['profilepicurl']); break;
            case 
2$profileim imagecreatefromjpeg($userinfo['profilepicurl']);  break;
            case 
3$profileim imagecreatefrompng($userinfo['profilepicurl']); break;
            default:  
trigger_error('Unsupported filetype!'E_USER_WARNING);  break;
        }
        
imagecopyresampled($im$profileim53500$max_width$max_height$width$height); // copy empty banner
        
imagedestroy($profileim);
    } 
Now we place few strings of user text at desired location.
PHP Code:
    $text "Posts at";
    if(
function_exists('imagettftext'))
    {
        
imagettftext($im120$left$top$text_color[0], $font[0], $username);
        
imagettftext($im80$left$top+$linespacing$text_color[1], $font[1], $usertitle);
        
imagettftext($im100$leftcounter$topcounter$text_color[2], $font[2], number_format($posts));
        
imagettftext($im100$leftcounter$topcounter $linespacing$text_color[3], $font[3], $text);
    } 
All done now out output the final image
PHP Code:
imagepng($im,$finalimg);
header('Cache-control: max-age=86400');
header('Expires: ' gmdate('D, d M Y H:i:s', (TIMENOW 86400)) . ' GMT');
header('Content-disposition: inline; filename=' $username '.png');
header('Content-transfer-encoding: binary');
header("Content-type: image/png");
imagepng($im);
imagedestroy($im); 

Complete Code



PHP Code:
<?php
$left 
4//Left text-margin
$top 15//text-margin from top
$leftcounter 44;
$topcounter 48;
$linespacing 12;
$baseimg './images/user/base.jpg';  //full path to empty input image
$finalimg './advprofilepic/member0.jpg';

$im imagecreatefromjpeg($baseimg); 

$text_color[0] = imagecolorallocate($im2552550);
$text_color[1] = imagecolorallocate($im192192192);
$text_color[2] = imagecolorallocate($im255255255);
$text_color[3] = imagecolorallocate($im255255255);

$font[0] = DIR .'/images/user/fonts/arialbd.ttf';
$font[1] = DIR .'/images/user/fonts/arialbd.ttf';
$font[2] = DIR .'/images/user/fonts/arialbd.ttf';
$font[3] = DIR .'/images/user/fonts/arialbd.ttf';

if(
$userid <> 0)
{
    
$finalimg './advprofilepic/member'.$userid.'.jpg';

    if(
file_exists($finalimg))
    {
        
$cachetime TIMENOW 86400;
        if(
$cachetime filemtime($finalimg))
        {
            
header('Content-type: image/jpg');
            
readfile($finalimg);
            exit;
        }
    }

    
// We have access to the linked image file
    
if (file_exists($profilepicurl))
    {
        list(
$width$height$image_type$attr) = getimagesize($profilepicurl);
        
$max_width 32;
        
$max_height 32;
        if(
$width $height)
        {
            
$width $height;
        }
        elseif(
$width $height)
        {
            
$height $width;
        }
        
$profileim imagecreatetruecolor($max_width,$max_height);
        
$bg_color imagecolorallocate ($profileim0,0,0); //background white
        
imagefilledrectangle ($profileim00$max_width$max_height$bg_color);
        switch (
$image_type)
        {
            case 
1$profileim imagecreatefromgif($userinfo['profilepicurl']); break;
            case 
2$profileim imagecreatefromjpeg($userinfo['profilepicurl']);  break;
            case 
3$profileim imagecreatefrompng($userinfo['profilepicurl']); break;
            default:  
trigger_error('Unsupported filetype!'E_USER_WARNING);  break;
        }
        
imagecopyresampled($im$profileim53500$max_width$max_height$width$height); // copy empty banner
        
imagedestroy($profileim);
    }

    
$text "Posts at";
    if(
function_exists('imagettftext'))
    {
        
imagettftext($im120$left$top$text_color[0], $font[0], $username);
        
imagettftext($im80$left$top+$linespacing$text_color[1], $font[1], $usertitle);
        
imagettftext($im100$leftcounter$topcounter$text_color[2], $font[2], number_format($posts));
        
imagettftext($im100$leftcounter$topcounter $linespacing$text_color[3], $font[3], $text);
    }
}
imagepng($im,$finalimg);
header('Cache-control: max-age=86400');
header('Expires: ' gmdate('D, d M Y H:i:s', (TIMENOW 86400)) . ' GMT');
header('Content-disposition: inline; filename=' $username '.png');
header('Content-transfer-encoding: binary');
header("Content-type: image/png");
imagepng($im);
imagedestroy($im);
?>
The above solution can also be used to watermark the images because standard watermarking procedure of editing the image in a photo-editing application is very time consuming and PHP offers better solution.

You can use the above method to loop through an entire directory to watermark all images in one go.

Possibilities are endless.
shabbir's Avatar, Join Date: Jul 2004
Go4Expert Founder
If you liked this article do nominate this article for Article of the month - May 2010
Darkness_inside like this
pkphp's Avatar, Join Date: Sep 2010
Light Poster
well. that's realllly what i need. thank you very much for your share.
Darkness_inside's Avatar, Join Date: Apr 2011
Newbie Member
Thanx 4 share
learner guy's Avatar, Join Date: Aug 2011
Light Poster
aoa sir,
this script is for the profile pic of go4expert.com
can i get a generalized code ....which i can use to create my water mark app.
plz tell me what modifications i have to do
waiting for reply ,
regards,
fasi khan
shabbir's Avatar, Join Date: Jul 2004
Go4Expert Founder
Quote:
Originally Posted by learner guy View Post
aoa sir,
this script is for the profile pic of go4expert.com
can i get a generalized code ....which i can use to create my water mark app.
plz tell me what modifications i have to do
waiting for reply ,
regards,
fasi khan
Fasi Khan, this is general script with example taken from is go4expert.com
jhon786's Avatar, Join Date: Oct 2011
Go4Expert Member
Thanks for shearing this useful information.