Adding watermarks to images with PHP

After the brief introduction to creating images with GD and PHP done on Text to Image with PHP we will be creating a function that given two attributes will return the first image with the second one as a watermark. For those of you who don’t know what a watermark is, it’s a mark on an image that either states the author of it, or prevents a sample image from being used instead of purchasing it etc. Usually is some text repeated all across the main image, it can also be another image instead of text.

On this introduction post we will create a function called watermarkIt that will take one argument, in this case the source image and return the same image. This may sound stupid but it’s going to be quite interesting since we will be checking multiple things like integrity of the, file type and valid file name:

1
2
3
4
5
6
7
8
<?php
    function watermarkIt($str_src_img){
        $img_source = @ImageCreateFromString(file_get_contents($str_src_img));
        if($img_source !== false){
            echo "Broken or invalid image";
        }
    }
?>

The first thing we’ve done is try accessing the image at the route specified at $str_source_img, and if there is no image or it’s corrupt/invalid we will return an error message. By using ImageCreateFromString and file_get_contents combined to get the source image we don’t have to worry about the file type as long as it’s valid. Since we will be using this function to return an image on the fly, we don’t want text error messages so let’s deal with it:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<?php
    function watermarkIt($str_src_img){
    header('Content-Type: image/jpg');

    $str_error_message = "The image is corrupt";

        $img_source = @ImageCreateFromString(file_get_contents($str_src_img));
        if($img_source == false){
            $img_error = imagecreatetruecolor(200,30);
            $color_black = imagecolorallocate($img_error, 255, 255, 255);
            imagestring($img_error, 5, 10, 7, $str_error_message, $color_black);
        imagejpeg($img_error);
        imagedestroy($img_error);
        }
    }
?>

Well, that’s a step forward isn’t it? Right now, we check if the file we wanted to use as a source image is valid and if not, we create a 200px by 30px image containing the value of the $str_error_message variable. That way if we call the function to an invalid image, it will still return an image. This of course can be changed to anything you want, a blank image or a pre-set error image. In the meantime I want to explain some lines of the code. I will assume you have some basic php knowledge so I’ll avoid the most obvious ones.

1
 header('Content-Type: image/jpg');

This sets the content type of the script file to a jpg image. Meaning that we can call it like we did in the introduction to images with php like this <img src='http://yoursite.com/route_to_script.php' /> and it will show the image generated by it.

1
$img_source = @ImageCreateFromString(file_get_contents($str_src_img));

There’s a lot going on in this line! We are creating an image object called $img_source that will contain the image specified when we called the function. The @ will hide errors. The ImageCreateFromString function will create and image identifier from the image stream created, forgive the repetition, by the file_get_contents.

1
2
3
$img_error   = imagecreatetruecolor(200,30);
$color_black = imagecolorallocate($img_error, 255, 255, 255);
imagestring($img_error, 5, 10, 7, $str_error_message, $color_black);

Those three lines are only used if the image we provided is invalid, so we need to create a new one, and we called it $img_error. The imagecreatetruecolor function will create an image identifier just like the ImageCreateFromString function did before. The moment we create it, it has no colours associated to it, and has a size of 200px by 30px since those are the values we declared when we called it. The next line allocates a black colour to the $img_error image, meaning that it will be available for use. The attributes it takes are, image identifier, red, blue and green. imagestring($img_error, 5, 10, 7, $str_error_message, $color_black); The imagestring funtion will add a string of text to the image specified at the first attribute, with a font specified at the second attribute, located at 10 pixels from the left side and 7 pixels from the top. More information on this function here.

The last two lines create and destroy the image, meaning we will output the image on the first one and once the output is completed, we will destroy it.
Why would be destroy it? Because creating and modifying images with PHP takes memory of course and this function frees any memory associated with it.

We wanted this function to return the same image if everything else was correct so lets do it!:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<?php
    function watermarkIt($str_src_img){
    header('Content-Type: image/jpg');

    $str_error_message = "The image is corrupt";

        $img_source = @ImageCreateFromString(file_get_contents($str_src_img));
        if($img_source == false){
            $img_error = imagecreatetruecolor(200,30);
            $color_black = imagecolorallocate($img_error, 255, 255, 255);
       
            imagestring($img_error, 5, 10, 7, $str_error_message, $color_black);
        imagejpeg($img_error);
        imagedestroy($img_error);
        }else{
            $arr_src_img_data = getimagesize($str_source_img);
            $int_img_type_start = strpos($arr_src_img_data['mime'],"/")+1;
            $str_src_img_type = str_replace("image/","",$arr_src_img_data['mime']);
            $img_output = call_user_func("imagecreatefrom$str_src_img_type", $str_src_img);
       
       imagejpeg($img_output);
       imagedestroy($img_output);
        }
    }
?>

$arr_source_img_data is an array created by the getimagesize function that contains the file type, the image size, and some other interesting values. For us, we’ll be using the ‘mime’ element of that array which contains the file type. Unfortunately, the format of the string contains both the file type and the extension. Since we just want the extension for now we use the str_replace function to remove the unnecessary parts.

$img_output = call_user_func("imagecreatefrom$str_src_img_type", $str_src_img); This line prevents us from having to use conditionals for creating the image object depending on the file extension. Instead, we use the [cci lang='php']call_user_func[/php] function to dynamically call the appropriate function to create the image. We do this because it’s not the same to create an image from a jpg a gif or a png, they use different functions.

On the next part, we will start getting into the actual watermarking. I apologize for anyone who was disappointed by this, but we need to set a strong base for our code to be bulletproof.

About Juan

Hola! Me llamo Juan y soy un programador de 23 años de Madrid. Este es mi blog personal dedicado a la programación en general aunque con cierta predilección hacia PHP y Java.