How to Force an Image Download in the Browser

How can I force an Image download in the browser?

There's two ways to do this - one with JS, one with PHP.

In JS from this site:

<a href="javascript:void(0);"
onclick="document.execCommand('SaveAs',true,'file.html');"
>Save this page</a>

In PHP create a script named download.php that is similar to the following code:

<?php
// Force download of image file specified in URL query string and which
// is in the same directory as the download.php script.

if(empty($_GET['img'])) {
header("HTTP/1.0 404 Not Found");
return;
}

$basename = basename($_GET['img']);
$filename = __DIR__ . '/' . $basename; // don't accept other directories

$mime = ($mime = getimagesize($filename)) ? $mime['mime'] : $mime;
$size = filesize($filename);
$fp = fopen($filename, "rb");
if (!($mime && $size && $fp)) {
// Error.
return;
}

header("Content-type: " . $mime);
header("Content-Length: " . $size);
// NOTE: Possible header injection via $basename
header("Content-Disposition: attachment; filename=" . $basename);
header('Content-Transfer-Encoding: binary');
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
fpassthru($fp);

Then set the image link to point to this file like this:

<img src="/images/download.php?img=imagename.jpg" alt="test">

How to force a browser to download and cache an image which is not currently being displayed on the page

Just load them all as hidden images.

CSS:

.hidden {
display:none;
}

HTML:

<img src="/hugeImage.jpg" class="hidden" />
<img src="/hugeImage2.jpg" class="hidden" />
<img src="/hugeImage3.jpg" class="hidden" />
<img src="/hugeImage4.jpg" class="hidden" />

You can easily simulate this with JavaScript, adding each of the images to the DOM after the DOMContentLoaded event - the same logic applies.

var img = document.createElement('img');
img.setAttribute('src', '/hugeImage.jpg');
img.setAttribute('class','hidden');
document.body.appendChild(img);

Browser/HTML Force download of image from src=data:image/jpeg;base64...


Simply replace image/jpeg with application/octet-stream. The client would not recognise the URL as an inline-able resource, and prompt a download dialog.

A simple JavaScript solution would be:

//var img = reference to image
var url = img.src.replace(/^data:image\/[^;]+/, 'data:application/octet-stream');
window.open(url);
// Or perhaps: location.href = url;
// Or even setting the location of an <iframe> element,

Another method is to use a blob: URI:

var img = document.images[0];
img.onclick = function() {
    // atob to base64_decode the data-URI
    var image_data = atob(img.src.split(',')[1]);
// Use typed arrays to convert the binary data to a Blob
    var arraybuffer = new ArrayBuffer(image_data.length);
    var view = new Uint8Array(arraybuffer);
    for (var i=0; i<image_data.length; i++) {
        view[i] = image_data.charCodeAt(i) & 0xff;
    }
try {
// This is the recommended method:
var blob = new Blob([arraybuffer], {type: 'application/octet-stream'});
} catch (e) {
// The BlobBuilder API has been deprecated in favour of Blob, but older
// browsers don't know about the Blob constructor
// IE10 also supports BlobBuilder, but since the `Blob` constructor
// also works, there's no need to add `MSBlobBuilder`.
var bb = new (window.WebKitBlobBuilder || window.MozBlobBuilder);
     bb.append(arraybuffer);
     var blob = bb.getBlob('application/octet-stream'); // <-- Here's the Blob
}

// Use the URL object to create a temporary URL
    var url = (window.webkitURL || window.URL).createObjectURL(blob);
    location.href = url; // <-- Download!
};

Relevant documentation

  • atob
  • Typed arrays
  • URL.createObjectURL
  • Blob and BlobBuilder

Force download remotely hosted images to browser

The very first example on the readfile() manual page is titled 'Forcing a download using readfile()', with a .gif file:

$file = 'monkey.gif';

if (file_exists($file)) {
header('Content-Description: File Transfer');
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename='.basename($file));
header('Expires: 0');
header('Cache-Control: must-revalidate');
header('Pragma: public');
header('Content-Length: ' . filesize($file));
readfile($file);
exit;
}

Under the Notes section is the following tip:

A URL can be used as a filename with this function if the fopen wrappers have been enabled. See fopen() for more details on how to specify the filename. See the Supported Protocols and Wrappers for links to information about what abilities the various wrappers have, notes on their usage, and information on any predefined variables they may provide.

So if you simply substitute $file = 'https://www.google.ae/images/srpr/logo11w.png'; for $file = 'monkey.gif'; the above script should force the image download.

Of course, the big drawback with this approach is that the image is transferred to your server first, and then downloaded to the client. But, as @charlietfl wrote 'you can't control how another server handles requests.' so you can't link directly to the original source and expect the file to download.

Force Browser to download Image with Javascript window.open?

Use application/octet-stream instead of image/jpg:

If [the Content-Disposition] header is used in a response with the application/octet-stream content-type, the implied suggestion is that the user agent should not display the response, but directly enter a `save response as...' dialog.

— RFC 2616 – 19.5.1 Content-Disposition

href image link download on click

<a download="custom-filename.jpg" href="/path/to/image" title="ImageName">
<img alt="ImageName" src="/path/to/image">
</a>

It's not yet fully supported caniuse, but you can use with modernizr (under Non-core detects) to check the support of the browser.



Related Topics



Leave a reply



Submit