smoothly upload a file, add a watermark and save a good quality version

hi all

I'm trying to upload a image file (only images) and then add a watermark to them before loading them into my MySQL database. I'm currently doing it by grabbing the file, saving it on the FileSystem, loading it again then adding the watermark, saving it again before finally liading it into the database and deleting the image.

Seems somewhat messy (although it works) and it degrades on quality the 2nd time around.

Can one of you guru's amend my code to work in 1 neat movement please?

I would obviously like to browse for the file, have it grabbed, the watermark added then saved for me to upload using send_long_data to MySQL (which works fine already so I haven't included that bit)


<?php // upload directory
    define('UPLOAD_DIR', 'uploads/');
	// watermark stamp
	$stamp = imagecreatefrompng('../../images/site/stamp.png');
	// grab the image
    $img = $_POST['image'];
    $img = str_replace('data:image/jpeg;base64,', '', $img);
    $img = str_replace(' ', '+', $img);	
    $data = base64_decode($img);
	// give the file a new name
    $file = UPLOAD_DIR . MD5(microtime()) . '.jpg';	
	// save the file
    $success = file_put_contents($file, $data);
    //print $success ? $file : 'Unable to save the file.';	
	// reload to add the watermark
	$preWMImage = imagecreatefromjpeg($file);

	// Set the margins for the stamp and get the height/width of the stamp image
	$marge_right = 10;
	$marge_bottom = 10;
	$sx = imagesx($stamp);
	$sy = imagesy($stamp);
	// add the watermark
		(imagesx($preWMImage) - $sx - $marge_right),
		(imagesy($preWMImage) - $sy - $marge_bottom),
	// resave
	imagejpeg($preWMImage, $file); ?>

Open in new window

Neil ThompsonSenior Systems DeveloperAsked:
Who is Participating?

[Product update] Infrastructure Analysis Tool is now available with Business Accounts.Learn More

I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

JPEG is a lossy format. Every single save operation will degrade the quality - there is absolutely no way to avoid that. If you need to preserve the highest quality of the image, then you should be using 24-bit PNGs. They will be much larger in size than JPEGs, but are lossless, so you can save them as many times as you want without any quality loss.

If you want to stick with JEPGs, then you can minimize the quality loss by specifying a higher quality parameter to your final imagejpeg() call, like this:

imagejpeg($preWMImage, $file, 90);

You can specify anything up to 100, but the higher the quality, the more larger the image file will be. If you store it at 100, your resulting file will actually be larger than the original (in almost every case) but will look ALMOST identical (you'd probably need software to tell the difference).

You mentioned "the 2nd time around" - I'm not sure if you're talking about doing another round of saves beyond what you already have here, but like I said, every JPEG save will result in a quality loss of some kind.

Personally, I would STRONGLY NOT recommend saving images in the database at all. Databases are not file systems, and it adds a large amount of overhead to the image access. If an image is saved directly on disk, then you're getting the best I/O performance possible. Not only can the web server read the file directly with very minimal overhead, but it can make use of all the caching features that your operating system, file system, and physical disk offer (which don't require any management or extra thought from you). However, when you get into images being stored in a database:

1. Every image needs to be extracted from the database to be viewed, which means load on the database, overhead in the database connection, and extra memory in the database client side (PHP) to store the image in memory before outputting it.

2. You miss out on all the native caching benefits from the filesystem.

3. Database backups become larger and harder to manage.

4. You get into situations where scripts that use SELECT * might accidentally end up pulling down the image data when it's not needed.

5. It doesn't scale as well in the long-term and is much less flexible. Usually in order to maintain good performance on both database and files when usage becomes high, you move the files onto a separate device/system (e.g. a local NAS or Amazon S3 or something), which can be done without a huge database impact. Plus, not having lots of image files in the DB makes it easier to move to high-availability clustering databases later on if you need.

If it were up to me, I'd suggest storing both the original and the watermarked image on the filesystem. Store any access-protected files outside the document root so they can't be accessed directly, and then when access to a non-watermarked file is verified, use PHP's readfile() function to stream the file directly from the disk (which will still take advantage of several performance features).

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
Neil ThompsonSenior Systems DeveloperAuthor Commented:
Many thanks for your detailed thoughts. I've done some working out and it would have used the 1GB of space I had really quickly so thanks for that.

I've also amended my scripts to use PNG and as you said it's perfect. It's also allowed me to cull 1/2 my scrips and implement both client side resizing and compression.

Thanks for taking the time :)

It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today

From novice to tech pro — start learning today.