Adding PNG Watermarks to JPEGs with PHP
This took up a good chunk of my afternoon. I have a client who wants to upload JPEG images to his website and have them automatically resized and watermarked with copyright information to discourage image theft. Resizing is a piece of cake — I’ve done that before — but getting the alpha transparency of a 24-bit PNG to overlay correctly was maddening.
It turns out that the solution is actually really simple. The code is below:
$photo = imagecreatefromjpeg("original.jpg");
$watermark = imagecreatefrompng("watermark.png");
// This is the key. Without ImageAlphaBlending on, the PNG won't render correctly.
imagealphablending($photo, true);
// Copy the watermark onto the master, $offset px from the bottom right corner.
$offset = 10;
imagecopy($photo, $watermark, imagesx($photo) - imagesx($watermark) - $offset, imagesy($photo) - imagesy($watermark) - $offset, 0, 0, imagesx($watermark), imagesy($watermark));
// Output to the browser - please note you should save the image once and serve that instead on a production website.
header("Content-Type: image/jpeg");
imagejpeg($photo);
Note: It’s a bad idea to do this on the fly for each visitor. I strongly recommend watermarking an image once and then using that image for your website.


Hi, i have found your code after hours of searching. I have tried to put it on my site because it’s just what i needed. I don’t know much about php image processing, so i have a question. How do i use the resulted photo in an img tag? Btw very stylish website. Thx
Comment by Sebastian — December 29, 2008 @ 1:35 pm
Sebastian, I’m glad that you found it useful. You’ll save your PHP code in a separate .php file and then use the <img> tag as follows:
<img src=”filename.php”>
where filename.php is the .php file that you create. Note that you’ll have to use imagejpeg and appropriate headers to output an image from your PHP script.
I hope that helps!
Comment by holmenb — December 31, 2008 @ 10:00 pm
Thank you for sharing this. I was being driven mad as well by the lack of 24bit support. Everywhere else I looked suggested using imagecopyresampled(…), which, from my testing, doesn’t support 24bit png transparencies (the ironic 32bit 24bit png) even when used in conjunction with the imagealphablending(…) function.
Anyway, thanks again!
Comment by Tiernan — January 31, 2009 @ 3:52 pm
Thank you for your extremely helpful script. This is exactly what I needed!
Comment by John Weatherford — November 7, 2009 @ 8:38 pm
Cheers Ben. This problem gets me every time. I was going wrong by using imagecopymerge instead of imagecopy.
Comment by Harvey Kane — November 18, 2009 @ 8:11 am
Thank’s dude, imagealphablending($photo, true); really saved my life
Comment by Dumitru — December 18, 2009 @ 5:44 pm
es kann hier der Fehler?
Comment by predbeto — January 5, 2010 @ 5:12 am
thanks alot! your code was really helpfull xD
Comment by Alireza Pazirandeh — April 16, 2010 @ 12:42 am
Thanks! It works! I read many articles but there was no word about the problem of handling 24bit png files.
Comment by solaris — June 29, 2010 @ 1:47 am
Thanks for this little snippet – very handy!
Sleek website too
Comment by James Waples — October 2, 2010 @ 2:56 pm
Thank u Ben. Your code has solved my problem with png’s transparency.
Comment by Wimpi — October 14, 2010 @ 12:26 am
thank you
Comment by Maziar — November 17, 2010 @ 7:16 am
It was helpful, lots of thanks
Comment by Yuriy — December 6, 2010 @ 9:05 am
Very helpful! Thanks for sharing, however, I’m using this method with a lightbox for different galleries, so the watermarked image is used in an anchor instead of being displayed straight away like…
The link displays the image perfectly fine when I open it in a new tab with the watermark and all, however, when I try and open the image in the lightbox simply by clicking, it fails
Any ideas?
Comment by Dave — December 14, 2010 @ 5:27 pm
Thanks for your help. That one line of code (imagealphablending) was just what I needed!
Comment by Jonathan Elder — December 31, 2010 @ 4:21 pm
Thank you so much, Ben! This is exactly what I was looking for.
Comment by Adam — March 15, 2011 @ 2:02 pm
Thanks!
Comment by Rauni — May 4, 2011 @ 4:39 am
Your the man. Haven’t had a chance to test it yet but thanks a bunch for sharing this
Comment by Jos — July 23, 2011 @ 1:12 am
Thanks Ben!
Exactly what I needed, and worked perfectly.
Comment by Rick Westhorpe — September 7, 2011 @ 2:55 am
don’t forget to
imagedestroy($photo); imagedestroy($watermark);
to avoid server cache to blow up. cheers.
Comment by ranma — September 14, 2011 @ 11:06 am