The following code sample demonstrates the use of GD library to watermark images on the fly. The method demonstrated here to watermark an uploaded image is to overlay the original image with another image, preferably a transparent PNG image.
PHP provides a rich set of functions to create and alter images on the fly. These functions require the GD library, which is bundled with PHP since version 4.3.
The Complete Example
The working code sample requires the following items:
- HTML form that posts an image to the PHP script
- The PHP Script
- The Watermark Image
HTML Form
The HTML form needs a file upload element: <input type="file">
. You must also specify the correct encoding type: enctype="multipart/form-data"
for the form.
<form action="watermark-image.php" method="post" enctype="multipart/form-data"> Select a file to upload for processing<br> <input type="file" name="File1"><br> <input type="submit" value="Submit File"> </form>
The PHP Script
The following code handles the file upload and performs the image processing.
<?php /* * PHP function to image-watermark an image * http://salman-w.blogspot.com/2008/11/watermark-your-images-with-another.html * * Writes the given watermark image on the specified image * and saves the result as another image */ define('WATERMARK_OVERLAY_IMAGE', 'watermark.png'); define('WATERMARK_OVERLAY_OPACITY', 50); define('WATERMARK_OUTPUT_QUALITY', 90); function create_watermark($source_file_path, $output_file_path) { list($source_width, $source_height, $source_type) = getimagesize($source_file_path); if ($source_type === NULL) { return false; } switch ($source_type) { case IMAGETYPE_GIF: $source_gd_image = imagecreatefromgif($source_file_path); break; case IMAGETYPE_JPEG: $source_gd_image = imagecreatefromjpeg($source_file_path); break; case IMAGETYPE_PNG: $source_gd_image = imagecreatefrompng($source_file_path); break; default: return false; } $overlay_gd_image = imagecreatefrompng(WATERMARK_OVERLAY_IMAGE); $overlay_width = imagesx($overlay_gd_image); $overlay_height = imagesy($overlay_gd_image); imagecopymerge( $source_gd_image, $overlay_gd_image, $source_width - $overlay_width, $source_height - $overlay_height, 0, 0, $overlay_width, $overlay_height, WATERMARK_OVERLAY_OPACITY ); imagejpeg($source_gd_image, $output_file_path, WATERMARK_OUTPUT_QUALITY); imagedestroy($source_gd_image); imagedestroy($overlay_gd_image); } /* * Uploaded file processing function */ define('UPLOADED_IMAGE_DESTINATION', 'originals/'); define('PROCESSED_IMAGE_DESTINATION', 'images/'); function process_image_upload($Field) { $temp_file_path = $_FILES[$Field]['tmp_name']; $temp_file_name = $_FILES[$Field]['name']; list(, , $temp_type) = getimagesize($temp_file_path); if ($temp_type === NULL) { return false; } switch ($temp_type) { case IMAGETYPE_GIF: break; case IMAGETYPE_JPEG: break; case IMAGETYPE_PNG: break; default: return false; } $uploaded_file_path = UPLOADED_IMAGE_DESTINATION . $temp_file_name; $processed_file_path = PROCESSED_IMAGE_DESTINATION . preg_replace('/\\.[^\\.]+$/', '.jpg', $temp_file_name); move_uploaded_file($temp_file_path, $uploaded_file_path); $result = create_watermark($uploaded_file_path, $processed_file_path); if ($result === false) { return false; } else { return array($uploaded_file_path, $processed_file_path); } } /* * Here is how to call the function(s) */ $result = process_image_upload('File1'); if ($result === false) { echo '<br>An error occurred during file processing.'; } else { echo '<br>Original image saved as <a href="' . $result[0] . '" target="_blank">' . $result[0] . '</a>'; echo '<br>Watermarked image saved as <a href="' . $result[1] . '" target="_blank">' . $result[1] . '</a>'; } ?>
The Watermark Image
The watermark image should be in one of the following recommended formats:
- PNG-8 (recommended)
Colors: 256 or less
Transparency: On/Off - GIF
Colors: 256 or less
Transparency: On/Off - JPEG
Colors: True color
Transparency: n/a
The imagecopymerge function does not properly handle the PNG-24 images; it is therefore not recommend.
If you are using Adobe Photoshop to create watermark images, it is recommended that you use "Save for Web" command with the following settings:
- File Format: PNG-8, non-interlaced
- Color Reduction: Selective, 256 colors
- Dithering: Diffusion, 88%
- Transparency: On, Matte: None
- Transparency Dither: Diffusion Transparency Dither, 100%
How it Works
The function relies on the imagecopymerge function available in GD library. This function copies a rectangular region from one image onto the other. The important thing is that this function allows you to specify the opacity of the image that is rendered on the destination image.
Visit the following URLs to see documentation of the functions used in this example:
- imagecreatefromgif
- imagecreatefromjpeg
- imagecreatefrompng
- imagecopymerge -- most important one in this example
- imagejpeg
- imagedestroy
Example Output
Example 1: Original Image
Example 1: Watermarked image showing four different combinations of alignment and opacity
Example 2: Original Image
Example 2: Watermarked image showing four different combinations of alignment and opacity
Variations of the Function
The example above will place the watermark image on the lower-right corner of the original image with 50% opacity. To experiment with other alignment options, you can modify the line containing imagecopymerge
as follows:
<?php /* * ALIGN TOP, LEFT */ imagecopymerge( $source_gd_image, $overlay_gd_image, 0, 0, 0, 0, $overlay_width, $overlay_height, WATERMARK_OVERLAY_OPACITY ); /* * ALIGN TOP, RIGHT */ imagecopymerge( $source_gd_image, $overlay_gd_image, $source_width - $overlay_width, 0, 0, 0, $overlay_width, $overlay_height, WATERMARK_OVERLAY_OPACITY ); /* * ALIGN BOTTOM, RIGHT */ imagecopymerge( $source_gd_image, $overlay_gd_image, $source_width - $overlay_width, $source_height - $overlay_height, 0, 0, $overlay_width, $overlay_height, WATERMARK_OVERLAY_OPACITY ); /* * ALIGN BOTTOM, LEFT */ imagecopymerge( $source_gd_image, $overlay_gd_image, 0, $source_height - $overlay_height, 0, 0, $overlay_width, $overlay_height, WATERMARK_OVERLAY_OPACITY ); ?>
Limitations of the Script
- The example currently supports GIF, JPEG and PNG file handling. Additional image type support can be added rather easily.
- The example does not generate unique file names and therefore overwrites existing uploaded or thumbnail images.
- The example does not show any error messages. All
"return false"
need to be replaced by appropriate error handling. - 256 color watermark images with transparency often have visible artifacts around the edges after rendering.
- 24-bit PNG watermark images are not rendered properly.
- Additional watermark alignment options are not discussed. I am leaving that as an exercise. Hint: it is as simple as dividing a few numbers by 2.