Imagine you have a set of images and you need to add watermark to all of them. You can do the work with an image editor (Gimp or Photoshop for example). It’s easy work but if your image library is big, the easy work become into hard. But imagine again you need to add a dynamic watermark, let’s say the current timestamp. To solve this problem we can use PHP’s GD image function set.
The idea is simple. Instead of opening directly the image, we are going to open a PHP script. This PHP script will open the original image file with imagecreatefromjpeg, add the footer and flush the new image to the browser with the properly headers.
But I don’t want to rewrite all the anchor’s hrefs within my HTML files. Because of that I’m going to use the same trick I used in my one of my posts. With a simple .htaccess in our jpg’s folder, our apache’s mod_rewrite will do work for us:
RewriteEngine on RewriteRule !\.(php)$ watermark.php
And now our PHP script called watermark.php
<?php $uri = $_SERVER['REQUEST_URI']; $documentRoot = $_SERVER['DOCUMENT_ROOT']; $filename = $documentRoot . $uri; if (realpath(__FILE__) == realpath($filename)) { exit(); } $stringSize = 3; $footerSize = ($stringSize==1) ? 12 : 15; $footer = date('d/m/Y H:i:s'); list($width, $height, $image_type) = getimagesize($filename); $im = imagecreatefromjpeg($filename); imagefilledrectangle ( $im, 0, $height, $width, $height - $footerSize, imagecolorallocate($im, 49, 49, 156)); imagestring($im, $stringSize, $width-(imagefontwidth($stringSize)*strlen($footer)) - 2, $height-$footerSize, $footer, imagecolorallocate($im, 255, 255, 255)); header( 'Content-Type: image/jpeg' ); imagejpeg($im);
Simple, isn’t it? You can change my blue footer with a your logo. Easy with PHP’s gd functions. Of course you need to have your PHP compiled with GD support.
Been there, done that. Huge resources drain if you really need to watermark not so big ammounts of images.
Gonzalo, have you tried this technique with other kind of resources that would economize the requests to the server? Let’s say a reverse proxy, for example, implementing a cache that would catch the watermarked images for later requests on the same object.
It’d be great to have one of your superb comparison &benchmarking charts on this topic as my experience on this was so bad that I had to disable it.
I normally use this technique only when I need to use a dynamic watermarks (depending on current state, timestamps or something like that). If you are using static watermarks (such as logos) it’s better to generate off-line the images with the watermark. BTW, when you said you had performance problems what’re you speaking about? (memory usage, probably). I admit that I normally don’t use high resolution images, but I’ve never felt any performance problems. In fact I have a reverse proxy (squid) but I disable it (with PHP headers) with those kind of images. I will check the memory usage of the script but I think it will be close to the image size.
You are doing imagepng while having output the header-type as jpeg.
Updated. Thanks for the bug hunt.
I was wondering if your method or if you know of a plugin that would allow me to watermark all my photos with the username of the person logged into my site looking at the image at that given time? Seems to me that is the best possible way to not only stop someone from downloading them and sharing the pics but also catching who did it when the pics show up and then cancel their membership. Is such a thing possible?? If a timestamp can be pulled why not the username of the person calling the image??
To create the watermark online within the request (as I explain in the blog post) is a hard operation to the server. If you dynamically add watermarks to all the photos depending on the logged user your server load will be increased a lot. Maybe you should create a background process to create those watermarks offline, but if you’ve got a big amount of users this process will be crazy. Another solution is to add the watermark with CSS. That’s means that the “real” image won’t have the watermark, but the user will see the watermark in the browser (but downloaded image will be without it). I’m not a CSS expert. I only know that it’s possible.