'protect images from being copied

Im looking for reliable solutions to protect images from being copied.. My customer (photographer) would like to avoid customers copying her pictures without buying them.

I was thinking about mixing these techniques:


PHP self-made expiration

images are loaded from a php script reading from the image file, in the request I bundle the request timestamp and filename. if the timestamp is very close to the actual timestamp (both timestamps are generated on the same server, so no time config issues) the request is created on page generation. For example: in the generated html, I have some img tag like:

So when the users wants to copy the image source from source code, the image.php script won't answer as there is a delay between page generation and image request...

No caching

If I send a No cache header, I suppose the browser doesn't caches/stores the file on the client computer?


Now that's the basic idea.. Users don't have the original file name so can't acces them directly.. With this solution, I can even watermark them on the fly or resize them

Users could still print screen them, there are 2 types of printscreens, those that put them in the clipboard, and those that save a file.

Would there be a solution, I was thinking about some sort of javascript side onkeydown and detecting the printscreen touch, or shift+alt+cmd+[1-4] on mac cobination and blank out imagesbefore any action is taken.. is this possible, more or less reliable and how?

Another partial idea I had was to clear clipboard on an interval or some action, but this is annoyinng for people, doesn't work for desktop saved screen captures and maybe doesn't works on all browsers.

any other idea?

So where to go from here? This is a practical question, I know people could take a picture of their screen after all or use a hdmi cable to capturing device.. but seriously, this is overkill, no one will do this for such pictures, we're not talking about top secret classified documents...



Solution 1:[1]

So this is my implementation:

First when calling an image during a page generation in php:

$reqinfo['id'] = $data[id];
$reqinfo['maxsize'] = 320;
$reqinfo['timestamp'] = time();
$reqinfo['base'] = false;

$encoded = base64_encode(openssl_encrypt(serialize($reqinfo), 'AES-128-CBC', 'martine',0,'fgrgfvcfghtfdrfg'));

echo'<div class="imagecontainer"><img src="photo.php?info='.$encoded.'" /></div>'; 

This already implement some restrictions in css and javascript on the imagecontainer class. I send the image ID (or name) the maximum width or height and the request timestamp, all this encrypted in a request string sent to photo.php base is ment to be true if image may bypass everything and be called like a plain image.

photo.php

<?
//request info
$reqinfo = unserialize(openssl_decrypt(base64_decode($_GET[info]), 'AES-128-CBC', 'martine',0,'fgrgfvcfghtfdrfg'));

//image expired
if(time() - $reqinfo[timestamp] > 10){ exit(); }

//public image
if($reqinfo[base] == true){ readfile('img/'.$reqinfo[id].'.jpg'); exit(); }

//header cache
header("Cache-Control: no-cache, must-revalidate"); // HTTP/1.1
header("Expires: Sat, 26 Jul 1997 05:00:00 GMT"); // Date in the past
header('Content-type: image/jpeg');

//check cache existance and send out
if(file_exists( 'img/'.$reqinfo[id].'_'.$reqinfo[maxsize].'.jpg')) { readfile('img/'.$reqinfo[id].'_'.$reqinfo[maxsize].'.jpg'); exit(); }

//source Image
$image_path = 'img/'.$reqinfo[id].'.jpg';
list($original_width, $original_height)= getimagesize($image_path); 
$srcImage = imagecreatefromjpeg( $image_path );
$ratio = $original_height/$original_width;


//create destination image holder
$destination_width = $reqinfo['maxsize'];
if($destination_width < 1) $destination_width = 1;
if($destination_width > $original_width)$destination_width = $original_width;
$destination_height = round($destination_width*$ratio);
if ($destination_height > $reqinfo['maxsize'])
{
    $destination_height = $reqinfo['maxsize'];
    $destination_width = round($destination_height/$ratio);
}
$targetImage = imagecreatetruecolor( $destination_width, $destination_height );
imagealphablending($targetImage,true);

//resample copy logo
imagecopyresampled( $targetImage, $srcImage, 
0, 0, 
0, 0, 
$destination_width, $destination_height, 
$original_width, $original_height );


// watermark
$watermark = imagecreatefrompng('watermark.png');
imagesettile($targetImage, $watermark);
imagefilledrectangle($targetImage, 0, 0, $destination_width, $destination_height, IMG_COLOR_TILED);




//output
imagejpeg(  $targetImage, 'img/'.$reqinfo[id].'_'.$reqinfo[maxsize].'.jpg' );
imagejpeg(  $targetImage );
imagedestroy( $targetImage );


?>

'martine' is a simple passphrase img is obviously an non public path

Hope this is more or less clear, basically this (in order):

  • Decrypt the $reqinfo array
  • check if imagerequest is fresh, if a user copies the urls and loads in another frame, no image will be loaded.
  • Checks if the image can bypass resize and watermark and be sent to the browser
  • Checks if a cached version exists to speed up process
  • Recreates a resized version
  • Add a watermark
  • Saves a server cached version
  • sends out the 'disposable' image

Hope this can helps someone...

Solution 2:[2]

Anything displayed can be captured. All solutions are from server side : adding a watermark, or using small low-resolution images for display.

Solution 3:[3]

The general rule of thumb is: If it can be accessed with a browser, the user already has full access to it and can take it if they wish to do so. Example options:

Option 1:

Prevent right clicking via JavaScript.

Won't work when user:

  • Disables JavaScript and refreshes the page.
  • Uses a screenshot tool.
  • Manually inspects your HTML and finds the img src.

Option 2:

Put image as the background image of a div.

Won't work when user:

  • Uses a screenshot tool.
  • Manually inspects your HTML/CSS and finds the img src.

Option 3:

Use a watermark and/or a low res image.

Probably the best approach here. If your client is a photographer that wants to protect his/her work, displaying a low-res image and providing an option/link to purchase the hi-res version may be the best course of action. Adding a watermark may also dissuade visitors from taking the image free-of-charge as nobody wants to frame a picture that has a photographer's logo across the middle.

Solution 4:[4]

  1. photographer mostly doing high quality pictures, so why not show on the web site low quality images and write on them "Demo" or something.
  2. use flash to prevent from the users copy them.
  3. encode your images into base64 and show them with canvas or svg.

Solution 5:[5]

There is no 100% protection..

The client always can make for example a Screenshot from the image. Or can get the Link to the image with the browser's code-inspector.

Add a watermark is the best solution.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Vincent Duprez
Solution 2 Alain Beauvois
Solution 3 Community
Solution 4 Igor Goldny
Solution 5 q0re