Is there any way to specify a suggested filename when using data: URI?
Asked Answered
A

17

281

If for example you follow the link:

data:application/octet-stream;base64,SGVsbG8=

The browser will prompt you to download a file consisting of the data held as base64 in the hyperlink itself. Is there any way of suggesting a default name in the markup? If not, is there a JavaScript solution?

Autoroute answered 12/11, 2008 at 13:42 Comment(6)
maybe unrelated to this issue but I suggest using blob's & URL.createObjectURL if this isn't an server or old browser obstacleMassif
Some browsers support the mediatype's optional parameter "name": data:application/pdf;name=document.pdf;base64,BASE64_DATA_ENCODEDUnbolted
I had the issue with Firefox pdf.js which tends to hang in some cases if it cannot extract a filename from the data uri. see #45586421Vaunt
@Unbolted Which browsers support the "name" parameter? Can you point me to some reference documentation? (my google-fu has failed me).Udine
@DimuDesigns At least Firefox at that time. It look like it's not anymore the case. It's related to MIME Content-Type (!= Content-Disposition) "name" parameter (not in RFC?)Unbolted
Is it works for blob uri?. How to set the download file extension for blob dataSummer
A
219

Use the download attribute:

<a download='FileName' href='your_url'>

The download attribute works on Chrome, Firefox, Edge, Opera, desktop Safari 10+, iOS Safari 13+, and not IE11.

Anadem answered 4/8, 2011 at 14:44 Comment(9)
This answer is the only complete one. No you can't do it with data: URI. Yes you can provide a file name to a download link with pure Javascript. Thanks!Amphidiploid
@BioDesign: It works even with data:URI's in chrome. See: jsfiddle.net/pYpqWBastian
but you can’t do it with window.location.replace. if you e.g. want to create a data:uri or one generated by window.URL.createObjectURL, and download that as file, you’ll have to create an <a> and click it: jsfiddle.net/flyingsheep/wpQtH (no, $(...).click() doesn’t work)Patch
It's a WHATWG feature that Google implements, but since it's an (unofficial) standard it could get popular. whatwg.org/specs/web-apps/current-work/multipage/…Arizona
@flyingsheep $('<a href="data:text/plain,Test" download="test.txt">')[0].click() seems to work fine here (Chrome 23) (note: I used the native click method, not jQuery's one). Demo: jsfiddle.net/2zsRWSidestroke
but in firefox, only jsfiddle.net/2zsRW/1 works. maybe some sort of same-origin-policy or bug? (an aside: since the download attribute is not yet implemented, it just replaces the frame there instead of downloading)Patch
@flyingsheep it seems they are enforcing a same-origin policy in Firefox "In Firefox 20 this attribute is only honored for links to resources with the same-origin." developer.mozilla.org/en-US/docs/Web/HTML/Element/a In my testing, Chrome doesn't have this limitation.Cw
The problem with this solution is that the file will be downloaded if the user clicks on the link. What if you just want to specify the filename if the user does right-click + Save Link As...?Gladdy
I try to use the download for the blob data. But it not works. How to set the download file extension for blob dataSummer
I
71

Chrome makes this very simple these days:

function saveContent(fileContents, fileName)
{
    var link = document.createElement('a');
    link.download = fileName;
    link.href = 'data:,' + fileContents;
    link.click();
}
Incogitant answered 13/5, 2013 at 13:23 Comment(4)
Refer to http://caniuse.com/#feat=download for a complete list of browser compatibility.Osteal
@tixastronauta: Despite the info in that page, not working in my firefox 44. Working nicely in Chrome. 48Declaim
there is a bit better way, cuz via this you can't save divided into paragraphs text file. my variant is: var file = new File(rows, "file.csv", {type: 'text/csv'}); var link = document.createElement('a'); link.href = URL.createObjectURL(file); link.download = file.name; link.click(); i've found the answer hereEvocation
Unfortunately this is the same 2 MB limit in Chrome when used with a data URL: https://mcmap.net/q/42104/-data-protocol-url-size-limitationsBently
A
62

HTML only: use the download attribute:

<a download="logo.gif" href="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7">Download transparent png</a>

Javascript only: you can save any data URI with this code:

function saveAs(uri, filename) {
  var link = document.createElement('a');
  if (typeof link.download === 'string') {
    link.href = uri;
    link.download = filename;

    //Firefox requires the link to be in the body
    document.body.appendChild(link);
    
    //simulate click
    link.click();

    //remove the link when done
    document.body.removeChild(link);
  } else {
    window.open(uri);
  }
}

var file = 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7'
saveAs(file, 'logo.gif');

Chrome, Firefox, and Edge 13+ will use the specified filename.

IE11, Edge 12, and Safari 9 (which don't support the download attribute) will download the file with their default name or they will simply display it in a new tab, if it's of a supported file type: images, videos, audio files, …

Aetna answered 8/9, 2014 at 0:22 Comment(4)
For a more complete solution, I suggest using downloadjs on npmAetna
It works for me but the browser page refreshes after that. Wonder how to prevent that?Rouleau
Doesn't work in chrome for file size > 2MB due restriction by chrome #695651Luftwaffe
The limit belongs to the data: URI, which is what the question mentions. This answer also works with Blobs and whatever else has a URIAetna
S
42

According to RFC 2397, no, there isn't.

Nor does there appear to be any attribute of the <a> element that you can use either.

However HTML5 has subsequently introduced the download attribute on the <a> element, although at the time of writing support is not universal (no MSIE support, for example)

Seismology answered 12/11, 2008 at 13:52 Comment(2)
If the file is so long the download failsAloeswood
If anyone is wondering about support, here's the caniuse page for this featureInebriant
P
21

I've looked a bit in firefox sources in netwerk/protocol/data/nsDataHandler.cpp

data handler only parses content/type and charset, and looks if there is ";base64" in the string

the rfc specifices no filename and at least firefox handles no filename for it, the code generates a random name plus ".part"

I've also checked firefox log

[b2e140]: DOCSHELL 6e5ae00 InternalLoad data:application/octet-stream;base64,SGVsbG8=
[b2e140]: Found extension '' (filename is '', handling attachment: 0)
[b2e140]: HelperAppService::DoContent: mime 'application/octet-stream', extension ''
[b2e140]: Getting mimeinfo from type 'application/octet-stream' ext ''
[b2e140]: Extension lookup on '' found: 0x0
[b2e140]: Ext. lookup for '' found 0x0
[b2e140]: OS gave back 0x43609a0 - found: 0
[b2e140]: Searched extras (by type), rv 0x80004005
[b2e140]: MIME Info Summary: Type 'application/octet-stream', Primary Ext ''
[b2e140]: Type/Ext lookup found 0x43609a0

interesting files if you want to look at mozilla sources:

data uri handler: netwerk/protocol/data/nsDataHandler.cpp
where mozilla decides the filename: uriloader/exthandler/nsExternalHelperAppService.cpp
InternalLoad string in the log: docshell/base/nsDocShell.cpp

I think you can stop searching a solution for now, because I suspect there is none :)

as noticed in this thread html5 has download attribute, it works also on firefox 20 http://www.whatwg.org/specs/web-apps/current-work/multipage/links.html#attr-hyperlink-download

Panay answered 5/6, 2011 at 1:49 Comment(0)
F
16

The following Javascript snippet works in Chrome by using the new 'download' attribute of links and simulating a click.

function downloadWithName(uri, name) {
  var link = document.createElement("a");
  link.download = name;
  link.href = uri;
  link.click();
}

And the following example shows it's use:

downloadWithName("data:,Hello%2C%20World!", "helloWorld.txt")
Frontogenesis answered 5/4, 2013 at 11:19 Comment(1)
This doesn't work in Firefox, I added an extended answer below with Fx compatibility.Aetna
W
12

No.

The entire purpose is that it's a datastream, not a file. The data source should not have any knowledge of the user agent handling it as a file... and it doesn't.

Writ answered 30/5, 2011 at 0:3 Comment(8)
The purpose of data: is to fudge a block of internal data into URL format without having to read it from a protocol-based source. The link in @silex's answer shows that the ability to suggest a preferred name to write it to is considered useful, even if it's not implemented yet.Seismology
@Alnitak: Useful? Absolutely. Technically appropriate? Still not convinced. :)Writ
@Tomalak consider the difference between loading the data and saving it - just because a blob is encoded inline in a data: URL doesn't mean that it shouldn't have a preferred name for saving it to.Seismology
@Alnitak: The data itself should have no knowledge of how you load or save it. It's data.Writ
But your line about it's "entire purpose" is wrong. data: was specifically invented to allow (small) inline content to appear in a fudged-together URL format so that it could be used by things like image tags without a separate HTTP request. HTML says the content of a img src attribute must be a URL, so that's what RFC 2397 created. There is no "data source".Seismology
@Alnitak: Exactly. There's no data source. There's no context. The URI is the data.Writ
@LightnessRacesinOrbit Saving an empty file with the URI as the filename would make more sense right? Btw, We have URL.createObjectURL to make things even worse.Scholasticism
@LoïcFaure-Lacroix: If you need a filename, yeah. Otherwise best to save the HTTP request.Writ
N
11

you can add a download attribute to the anchor element.

sample:

<a download="abcd.cer"
    href="data:application/stream;base64,MIIDhTC......">down</a>
Newport answered 13/9, 2012 at 14:57 Comment(0)
P
9

Using service workers, this is finally possible in the truest sense.

  1. Create a fake URL. For example /saveAs/myPrettyName.jpg
  2. Use URL in <a href, <img src, window.open( url ), absolutely anything that can be done with a "real" URL.
  3. Inside the worker, catch the fetch event, and respond with the correct data.

The browser will now suggest myPrettyName.jpg even if the user opens the file in a new tab, and tries to save it there. It will be exactly as if the file had come from the server.

// In the service worker
self.addEventListener( 'fetch', function(e)
{
    if( e.request.url.startsWith( '/blobUri/' ) )
    {
        // Logic to select correct dataUri, and return it as a Response
        e.respondWith( dataURLAsRequest );
    }
});
Palatal answered 24/1, 2015 at 10:56 Comment(1)
Interesting! Support seems to be quite shallow for now, though: caniuse.com/#feat=serviceworkersOpportina
E
5

Look at this link: http://lists.w3.org/Archives/Public/uri/2010Feb/0069.html

Quote:

It even works (as in, doesn't cause a problem) with ;base64 at the end
like this (in Opera at least):

data:text/plain;charset=utf-8;headers=Content-Disposition%3A%20attachment%3B%20filename%3D%22with%20spaces.txt%22%0D%0AContent-Language%3A%20en;base64,4oiaDQo%3D

Also there is some info in the rest messages of the discussion.

Enchorial answered 30/5, 2011 at 0:24 Comment(2)
unfortunately this does not download.Loiret
this discussion was for a proposed extension to the data URI format - it hasn't been implemented.Seismology
M
4

There is a tiny workaround script on Google Code that worked for me:

http://code.google.com/p/download-data-uri/

It adds a form with the data in it, submits it and then removes the form again. Hacky, but it did the job for me. Requires jQuery.

This thread showed up in Google before the Google Code page and I thought it might be helpful to have the link in here, too.

Moffit answered 11/1, 2012 at 22:32 Comment(3)
Interesting script but it does require the server to get the response ans send it back right? jsfiddle.net/hZySfLoiret
I'm not sure where the file is being generated from.. is that file being stored in the base64 encode? (I'm not too familiar with base64)Except
@streetlight: The "file" (i.e. data) is generated by Javascript. The context of that project (and probably most here) assume that you have some way of getting your desired data into a JS variable. The difference is that instead of presenting it to the user via a data:... URI, that script creates a form to POST it to the server. And the server then presumably echoes it straight back as an HTTP "download" response (i.e. with an appropriate Content-Disposition header specifying the filename).Jeffry
H
4

Here is a jQuery version based off of Holf's version and works with Chrome and Firefox whereas his version seems to only work with Chrome. It's a little strange to add something to the body to do this but if someone has a better option I'm all for it.

var exportFileName = "export-" + filename;
$('<a></a>', {
    "download": exportFileName,
    "href": "data:," + JSON.stringify(exportData, null,5),
    "id": "exportDataID"
}).appendTo("body")[0].click().remove();
Hassett answered 20/2, 2014 at 17:25 Comment(3)
With jQuery 1.11 I get an exception because of the .remove(). I got around this by assigning $().appendTo() to a variable then calling variable.click(); variable.remove()Dorran
@Dorran you should get that exception with any jQuery, because getting the [0] from any "jQuery element" should return the first DOM element it represents, which essentially "takes you out of" jQuery.Low
You actually shouldn't need to append/remove the element at all -- see comments at https://mcmap.net/q/57263/-download-image-with-javascriptLow
F
2

This one works with Firefox 43.0 (older not tested):

dl.js:

function download() {
  var msg="Hello world!";
  var blob = new File([msg], "hello.bin", {"type": "application/octet-stream"});

  var a = document.createElement("a");
  a.href = URL.createObjectURL(blob);

  window.location.href=a;
}

dl.html

<html lang="en" xmlns="http://www.w3.org/1999/xhtml">

<head>
    <meta charset="utf-8"/>
    <title>Test</title>
    <script type="text/javascript" src="dl.js"></script>
</head>

<body>
<button id="create" type="button" onclick="download();">Download</button>
</body>
</html>

If button is clicked it offered a file named hello.bin for download. Trick is to use File instead of Blob.

reference: https://developer.mozilla.org/de/docs/Web/API/File

Flaherty answered 2/1, 2016 at 18:51 Comment(0)
P
1

(This answer has been made deprecated by newer technology, but will be kept here for historical interest.)

It's kind of hackish, but I've been in the same situation before. I was dynamically generating a text file in javascript and wanted to provide it for download by encoding it with the data-URI.

This is possible with minormajor user intervention. Generate a link <a href="data:...">right-click me and select "Save Link As..." and save as "example.txt"</a>. As I said, this is inelegant, but it works if you do not need a professional solution.

This could be made less painful by using flash to copy the name into the clipboard first. Of course if you let yourself use Flash or Java (now with less and less browser support I think?), you could probably find a another way to do this.

Pinguid answered 30/5, 2011 at 0:18 Comment(4)
This is not a solution and does not meet what was asked for. Sorry.Inextirpable
Lol @ "minor user intervention". Getting the user to do the whole thing for you is not "minor user intervention".Writ
Combine this with #17312145 to trigger the generated link and you don't need user intervention. You can specify the HTML5 download attribute to suggest a name as mentioned by many other answers.Low
This is a great workaround for Safari. Use Modernizr to detect when the download attribute is not supported and update the link text!Knoll
S
0

<a href=.. download=.. > works for left-click and right-click -> save link as..,

but <img src=.. download=.. > doesn't work for right-click -> save image as.. , "Download.jped" is suggested.

If you combine both:<a href=.. download=..><img src=..></a>

it works for left-click, right-click -> save link as.., right-click -> save image as..

You have to write the data-uri twice (href and src), so for large image files it is better to copy the uri with javascript.

tested with Chrome/Edge 88

Spindlelegs answered 11/2, 2021 at 15:26 Comment(0)
F
-1
var isIE = /*@cc_on!@*/false || !!document.documentMode; // At least IE6
var sessionId ='\n';
var token = '\n';
var caseId = CaseIDNumber + '\n';
var url = casewebUrl+'\n';
var uri = sessionId + token + caseId + url;//data in file
var fileName = "file.i4cvf";// any file name with any extension
if (isIE)
    {
            var fileData = ['\ufeff' + uri];
            var blobObject = new Blob(fileData);
            window.navigator.msSaveOrOpenBlob(blobObject, fileName);
    }
    else //chrome
    {
        window.requestFileSystem = window.requestFileSystem || window.webkitRequestFileSystem;
         window.requestFileSystem(window.TEMPORARY, 1024 * 1024, function (fs) {
            fs.root.getFile(fileName, { create: true }, function (fileEntry) { 
                fileEntry.createWriter(function (fileWriter) {
                    var fileData = ['\ufeff' + uri];
                    var blob = new Blob(fileData);
                    fileWriter.addEventListener("writeend", function () {
                        var fileUrl = fileEntry.toURL();
                        var link = document.createElement('a');
                        link.href = fileUrl;
                        link.download = fileName;
                        document.body.appendChild(link);
                        link.click();
                        document.body.removeChild(link);
                    }, false);
                    fileWriter.write(blob);
                }, function () { });
            }, function () { });
         }, function () { });
    }
Fifteenth answered 25/11, 2015 at 13:8 Comment(2)
pls add a more detailed explanation to your answer - stackoverflow.com/help/how-to-answerJaborandi
this answer is garbageMikkanen
S
-2

You actually can achieve this, in Chrome and FireFox.

Try the following url, it will download the code that was used.

data:text/html;base64,PGEgaHJlZj0iZGF0YTp0ZXh0L2h0bWw7YmFzZTY0LFBHRWdhSEpsWmowaVVGVlVYMFJCVkVGZlZWSkpYMGhGVWtVaUlHUnZkMjVzYjJGa1BTSjBaWE4wTG1oMGJXd2lQZ284YzJOeWFYQjBQZ3BrYjJOMWJXVnVkQzV4ZFdWeWVWTmxiR1ZqZEc5eUtDZGhKeWt1WTJ4cFkyc29LVHNLUEM5elkzSnBjSFErIiBkb3dubG9hZD0idGVzdC5odG1sIj4KPHNjcmlwdD4KZG9jdW1lbnQucXVlcnlTZWxlY3RvcignYScpLmNsaWNrKCk7Cjwvc2NyaXB0Pg==
Sympathy answered 26/11, 2016 at 15:33 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.