19

I want to know if there is any way to make a script using Javascript/jQuery to download (open a download dialog) a image so the browser won't just show it.

Salman A
  • 262,204
  • 82
  • 430
  • 521
Nathan Campos
  • 28,769
  • 59
  • 194
  • 300
  • I asked this a few weeks ago, see the answer here: http://stackoverflow.com/questions/6473832/pull-in-html-resource-in-the-background-in-jquery – Kevin Burke Jul 22 '11 at 23:01
  • @Nathan: what server are you using? Apache, IIS? – Salman A Jul 23 '11 at 08:43
  • 1
    Kevin Burke - the question you linked doesn't seem to have any overlap with this. Preloading images vs. forcing a download? http://stackoverflow.com/questions/6473832/pull-in-html-resource-in-the-background-in-jquery – Ernest May 11 '13 at 21:23

4 Answers4

37

You need to use server-side scripting for this. Search on stackoverflow.

Alternately, your server might allow you to alter headers dynamically via configuration.

Apache solution with mod_headers

Place your downloadable images in a directory. Inside this directory, create a .htaccess file with the following contents:

SetEnvIf Request_URI "([^/]+\.jpg)$" REQUESTED_IMAGE_BASENAME=$1
SetEnvIf Request_URI "([^/]+\.png)$" REQUESTED_IMAGE_BASENAME=$1
Header set Content-Disposition "attachment; filename=\"%{REQUESTED_IMAGE_BASENAME}e\"" env=REQUESTED_IMAGE_BASENAME

Test Request:

HEAD /test/Water%20lilies.jpg HTTP/1.1
Host: localhost

Test Response:

HTTP/1.1 200 OK
Date: Sat, 23 Jul 2011 09:03:52 GMT
Server: Apache/2.2.17 (Win32)
Last-Modified: Thu, 23 Aug 2001 14:00:00 GMT
ETag: "26000000017df3-14752-38c32e813d800"
Accept-Ranges: bytes
Content-Length: 83794
Content-Disposition: attachment; filename="Water lilies.jpg"
Content-Type: image/jpeg

HTML5 Solution

You can use the HTML5 download attribute on anchors:

<p>Example 1<br>
   <a href="http://dummyimage.com/600x400/000/fff.png" download>Download this image</a></p>

<p>Example 2<br>
   <a href="http://dummyimage.com/600x400/000/fff.png" download="alternate-filename.png"><img
       src="http://dummyimage.com/150x100/000/fff.png"></a></p>
Community
  • 1
  • 1
Salman A
  • 262,204
  • 82
  • 430
  • 521
15

I have come up with pure JavaScript way to force download of image, with the following restrictions:

  1. Using HTML5 so not working at all in IE browsers before IE9.
  2. In IE (even 9) limited to very small images, due to URL length limit.
  3. The image name (when saved to machine) can't be determined in the code, in Chrome it will be just "download" without extension and in Firefox it will be what looks like jibberish string with ".part" extension - either way, user will have to rename the file to make it usable.
  4. Can only download images in the same domain - same origin policy.

The above restrictions (especially the third) more or less renders this useless but still, the "core" idea is working and hopefully at some point in the future it will be possible to determine file name then it will become much more useful.

Here is the code:

function DownloadImage(imageURL) {
    var oImage = document.getElementById(imageURL);
    var canvas = document.createElement("canvas");
    document.body.appendChild(canvas);
    if (typeof canvas.getContext == "undefined" || !canvas.getContext) {
        alert("browser does not support this action, sorry");
        return false;
    }

    try {
        var context = canvas.getContext("2d");
        var width = oImage.width;
        var height = oImage.height;
        canvas.width = width;
        canvas.height = height;
        canvas.style.width = width + "px";
        canvas.style.height = height + "px";
        context.drawImage(oImage, 0, 0, width, height);
        var rawImageData = canvas.toDataURL("image/png;base64");
        rawImageData = rawImageData.replace("image/png", "image/octet-stream");
        document.location.href = rawImageData;
        document.body.removeChild(canvas);
    }
    catch (err) {
        document.body.removeChild(canvas);
        alert("Sorry, can't download");
    }

    return true;
}

As you can see, the trick is drawing the image into canvas object, get the raw binary data of the image then force download by using image/octet-stream mime type and changing the browser location.

Usage sample follows as well.

HTML:

<image id="myimage" src="Penguins.jpg" />
<button type="btnDownload" rel="myimage">Download</button>

JavaScript:

window.onload = function() {
    var arrButtons = document.getElementsByTagName("button");
    for (var i = 0; i < arrButtons.length; i++) {
        var oButton = arrButtons[i];
        var sRelatedImage = oButton.getAttribute("rel");
        if (sRelatedImage && sRelatedImage.length > 0) {
            oButton.onclick = function() {
                HandleRelatedImage(this, sRelatedImage);
            }
        }
    }
};

function HandleRelatedImage(oButton, sRelatedImage) {
    var oImage = document.getElementById(sRelatedImage);
    if (!oImage) {
        alert("related image '" + sRelatedImage + "' does not exist");
        return false;
    }

    return DownloadImage(sRelatedImage);
}

This allows to "attach" download button to every existing image by assigning the rel attribute of the button to the image ID - the code will do the rest and attach the actual click events.

Due to the same origin policy can't post live example at jsFiddle - they're using "sandbox" domain to execute the scripts.

Shadow The GPT Wizard
  • 66,030
  • 26
  • 140
  • 208
5

Here's a simple solution that uses the HTML5 'download' attribute:

document.getElementById('download').click();
<a id="download" href="https://docs.google.com/uc?id=0B0jH18Lft7ypSmRjdWg1c082Y2M" download hidden></a>
If it can find the picture it will download a cat picture.
Triforcey
  • 453
  • 5
  • 10
  • 2
    I tested it with Firefix Developer Edition v43, Firefox v39, Microsost Edge, Internet Explorer v11 the image is displayed in the page, and no download dialog appear – Mohamed Badr Oct 06 '15 at 18:26
  • 3
    check this http://caniuse.com/#feat=download, please note that altough it's said that it should work with FF 39 but I tested this with image and it's displayed in the browser – Mohamed Badr Oct 06 '15 at 18:33
  • 2
    One simple solution for all your download issues! Programmers hate him! – a20 May 11 '16 at 07:12
  • 1
    download attribut is not supported by safari – Pranav Labhe Jul 04 '16 at 11:43
-1

This is totally possible. Just encode the image as Base64 then do a window.open with a data:image/jpg,Base64,...-style url.

buley
  • 28,032
  • 17
  • 85
  • 106