EDIT:
FOUND MY MISTAKE:
line 3 in this example, the $(this) selector isn't valid in this case. So the command is skipped, the download attribute isn't set and instead of downloading, the browser tries to navigate to the dataUrl, which is prohibited. Cue errors.
I have a PWA that stores images as base64 pngs. I want to give users the option to download them to their device.
Previously I used this really simple code where myAnchor is an anchor-tag in my HTML and pic contains the base64 png:
function imgDownload(pic) {
$('#myAnchor').attr('href', pic);
$(this).attr('download', 'image.png');
$('#myAnchor')[0].click();}
So: simply set href to the image, set download attribute and filename, then trigger the download by clicking the link. But either Chrome 60 or 61 broke that - apparently for security reasons -, it now results in this error:
Not allowed to navigate top frame to data URL: [my b64 png]
Is there a (preferrably not too complex) client-side alternative to achieve the same functionality? It only has to work in Chrome, more browser compatibility is nice of course, but not neccessary.
Related
I want to embed base64 encoded string of pdf into an html template.
<iframe src="data:application/pdf;base64, encodeURI(pdfstring)"></iframe>
This works fine in chrome and edge but showing blank page in IE 11.I do not want to download it.Is there a fix for IE11
It doesn't work because IE doesn't support iframe with data url as src attribute. You could check it in caniuse. It shows that the support is limited to images and linked resources like CSS or JS in IE. Please also check this documentation:
Data URIs are supported only for the following elements and/or
attributes.
object (images only)
img
input type=image
link
CSS declarations that accept a URL, such as background, backgroundImage, and so on.
You can only do what like the accepted answer says:
The only workaround for this is to return your PDF content from a HTTP/HTTPS or FTP URI and use that as the source of the IFRAME.
I am generating a GIF in the browser, and so the only link to it I can use is an inline data URL. (Like data:image/gif;base64,...)
I want to allow the user to download the GIF they created. To make it as easy as clicking on a link, I am using an a[download] like so:
<a download="GIF" href="data:image/gif;base64,...">Download</a>
With small files, this opens my MacOS "save as" dialog. With this GIF, it does not. Nothing happens when I click on the link, except that the Chrome icon changes to look like this:
When I right-click on the GIF and select "save image as", I can save it just fine. This allows me to see that the GIF is a whopping 3MB.
I have checked with a large file linked to in the usual fashion, and the a[download] link works just fine. This seems to only be a problem with inline, data-URL files.
Is there a file size limit?
Bonus questions:
Why is there a file size limit?
Is there a workaround?
TL;DR: The data-url size limit is 2 MiB. See this demo.
--
This means that the file size is a little smaller than that, as a base64-encoded image is about 37% larger than the original.
Note also that it's a 2 Mebibyte limit, hence the "2 MiB" with the little "i". As explained here, this means the limit is 2 * 2^20 = 2,097,152 bytes, or 2.097 of the familiar base-ten megabytes, MB.
As shown in the demo, this translates to a 1.568 MB file downloading just fine, but Chrome failing to download a 1.581 MB file.
Why does Chrome do this? Not sure. Seems like it might be a bug.
Workarounds: Not sure. You could try to use URL.createObjectUrl as #roland-starke suggests, or perhaps open the data URL in a new tab
I get the image data from canvas as follows:
var img = mycanvas.toDataURL("image/png;base64;");
then i pass de image data to the href attribute of anchor
$("#imagenMapa2").prop("src",img);
The problem is that when i try to download the image chrome crash,
I tried with other smaller canvas and that work, buth with the size of
width="2600" height="3400"
doesn't work
appreciate any help
The problem is that browsers may or may not apply length limits to data-URIs. There is no way around that unfortunately, but to hope they increase this limit. The data itself is not a problem for modern computers.
Workaround #1
Canvas is essential a bitmap just like an Image, the only difference being that it can be edited using JavaScript.
So instead of converting the canvas to an image, just insert the canvas element into the DOM. It will behave just like an image from the user's point of view.
If you need user to download the image you are limit to make the user right-click and "save as" the image (supported in most browsers by now).
Workaround #2
Another option is to use a Blob. Virtually all browsers supports Blobs, but almost none support canvas.toBlob() however (only Firefox does, IE 10+ with prefix), so you will run into limitations here as well.
This example is from MDN's page:
canvas.toBlob(function(blob) {
var newImg = document.createElement("img"),
url = URL.createObjectURL(blob);
newImg.onload = function() {
// no longer need to read the blob so it's revoked
URL.revokeObjectURL(url);
};
newImg.src = url;
document.body.appendChild(newImg);
});
Workaround #3
Or, as stated in the other answer, use lossy compression JPEG with high compression ratio. You will loose the alpha channel too.
This may, however, be the "only" option left if you require as much compatibility as possible cross-browser:
var dataURI = canvas.toDataURL("image/jpeg", 0.2); // type, enc. option <0.0, 1.0]
Workaround #4
You can also send the raw bitmap to server as ArrayBuffer in a post, then encode the raw data on server-side and send the image back to user for download.
This is obviously a high traffic-load option and not very user friendly as you would be sending ~44mb (with the size from the question) upstream from user end to the server (considering that most ADSL users in particular has limited upstream rate this could take ages trialing the user's patience, which is never a good idea...).
If this is special use however, ie. intranet or similar, it is doable, but generally not recommendable.
Workaround #5 (in principle)
The last option is to basically encode the raw bitmap data to PNG using JavaScript using low-level ArrayBuffer. I am not aware of any libraries that do encoding yet though so this option is currently left to long nights...
I got an AJAX function that loads a png from a canvas graph element and does (per user choice) open the image in a new browser window or force a download.
While the first works without a problem, I got a problem with adding the file extension to the download. Currently I simply get none, using the following HttpHeaders: image/octet-stream, application/download(force-download, x-download)
Gladly some SO user put a JsFiddle together. 1)
Question: How could I go and append a file extension (.png/.jpeg) to the forced download as seen in the JsFiddle example?
1) Sry, but I donĀ“t know the User name anymore.
Unfortunately, with data uris, it is not possible to supply filenames. You should probably look at the HTML5 BlobBuilder API - http://blogs.msdn.com/b/ie/archive/2012/01/27/creating-files-through-blobbuilder.aspx
Even with BlobBuilder, I've found that only Chrome acknowledges the filenames you supply, not Firefox.
Suppose in Javascript that you assign the SRC to an IMG tag. It is a large SRC and you want to cancel it before it has finished loading. Assigning the SRC to another image will not stop the data from loading.
That is, in the middle of the load you can assign the SRC to another smaller image and the smaller image will be loaded and appear in your browser. However, the original SRC still continues downloading.
Similarly, deleting the IMG node will not prevent the SRC from continuing to download. No guesses please, look at the repro steps.
REPRO
Load this URL in Chrome in Windows: http://68.178.240.17/imgLoadTest/imgLoadTest.htm
Open up the developer panel by pressing CTRL-SHIFT-J
On the top row of icons in the Chrome developer panel click the Network icon to watch network activity.
On the web page loaded in Step 1 click the Load Image button and watch the developer panel as a large (32meg) image starts loading.
On the web page click the Try To Cancel button to load a different image.
A small image loads, but watch the network in the developer panel and notice that the large image continues to download.
Quick answer
Setting the src attribute of the img tag to the empty string will interrupt the current download, even on Chrome.
Details
Nowadays most of browsers implemented that out-of-standard mechanism thought in the old answer to programmatically abort the connection. This is not achieved through a protocol request, but with a client-side in-memory operation. Keep in mind that is not a standard behaviour, but most of vendors courtesy. That is, it could not work on every browser.
I've prepared a jsfiddle showing this mechanism in action (keep an eye at the network panel of the inspector).
Old answer (2011)
Your browser asks for that image with a specific HTTP GET request, as specified in HTTP protocol. Once it asks for it, the http server starts the transfer.
So, it is between the browser (as http client) and the http server.
Since http protocol does not takes into account the option to abort a transfer, the browser should implement a out-of-standard mechanism to programmatically abort the connection. But since this is not specified in any standard, i think you won't find any way to do that with javascript or any client side code.
Cancel with transparent base64 encoded GIF to avoid additional requests and double page load on android:
var img = new Image();
img.src = 'http://google.com/favicon.ico';
img.src = 'data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEAAAAALAAAAAABAAEAAAI=;'
Although I can't find the bug report now, I believe this is a long-standing logged WebKit bug. Firefox (and IE I think) have more sane behavior. I'm going back a bit in my brain, but if I recall on those browsers, resetting the img.src will in fact cancel outstanding downloads. I am positive that Firefox does this when a download is "waiting in line" for a chance at an open HTTP connection, and I seem to recall that it will actually force close connections sometimes.
I've never found a way to coax WebKit based browsers into cancelling an img download in progress, whether it is just queued or already actively downloading.
This really sucks if you're making something like a mapping client and need more fine grained control over images.
Setting the .src property to an empty string should cancel the load:
//load image from url
var img = new Image();
img.src = 'http://somedomain.com/image.jpg';
......
//cancel load
img.src = '';
Yes, page is downloaded twice on Android when an img tag has an src="" attribute.
This still occurs on recent Android versions.
I have not found any other browser that does that.
But I found a solution: use an img tag without src attribute.
The ultimative answer is web workers.
Load the image inside an webworker and stopping the web worker will stop the image loading.
You can get the idea from this code:
https://github.com/NathanWalker/ng2-image-lazy-load
this work for me:
imageVarName.src = '';
imageVarName.onload = null;
imageVarName.onerror = null;
the src property must be a valid non-empty URL
So null or empty string are not legal (even though they sometimes work).
Use:
img.src='http://xxxx';
img.onerror=null;
(see here)
Sadly, setting src to an empty string does not work in WebKit-based browsers like Safari. Here is the link to the bug report which Stella mentioned.
https://bugs.webkit.org/show_bug.cgi?id=6656