How export img data with javascript - javascript

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...

Related

Download png from JavaScript/jQuery

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.

How to set Image to clipboardData in oncopy event

I want to implement ctrl+c event in canvas (like in painters) from selected region to OS buffer. Based on this answer I can add copy listener and change clipboard data there - which works perfectly with text. But I can't find how to put Image/ImageData object there there. Here's MDN copy documentation and setData. Seems like there is nothing about image/* format. Well Specification doesn't say anything as well. But I smell if first param named as format in setData there should be a way to put file there.
Here's where I come so far:
document.addEventListener('copy', function(e) {
var data = ctx.getImageData(params.left, params.top, params.width, params.height);
var file = new File(data.data, "file.png", {type: "image/png"});
e.clipboardData.items.add(file, 'image/png'); // This doesn't work, But it create the structure like on the image below(with items and types, but without FileList)
e.clipboardData.setDragImage(tool.img, 10, 10); // doesn't work
e.clipboardData.setData("image/png", tool.file); // doesn't work
e.preventDefault();
})
I also found setDragImage method, I implemented it but after putting Image it doesn't appear in buffer.
NOTE:
When I paste image FROM clipboard my 'paste' event shows event structure like on the image bellow, so I guess I need create something similar.
Any Ideas?
p.s. I also know about document.execCommand('copy');, but it doesn't work in chrome (at least in my case) so I don't wanna use it.
Speaking only from my observations and investigation:
Chrome does not support the "image/png" type, and this is not a format that is required by the Clipboard API spec. (Chrome bug.)
Firefox will at least attempt to put a DataTransferItem with the "image/png" type on the clipboard, but I haven't yet figured out what data format to use. (A base64 PNG, with or without the data:image/png;base64, prefix, does not work to paste into PowerPoint, nor does atob(<the base64 PNG without prefix>), as far as I've experimented.)
"text/html" is required however. When a copy event is triggered in Google Docs, it appears to upload an image, then puts an HTML fragment on the clipboard that looks like this:
<meta charset="utf-8">
<b style="font-weight:normal;" id="docs-internal-guid-abcdefg-abcd-abcd">
<img src="https://lh4.googleusercontent.com/a-very-long-identifier" width="659px;" height="312px;" />
</b>
using evt.clipboardData.setData("text/html", fragment). Then, e.g. Microsoft Office apps will download that image and embed it in the document. I don't know if it does the same thing on MacOS or Linux. Data URIs do not work as the img src, by the way.

Download progress in HTML5

If I have 5 javascript files and each of different size and same with CSS, is it possible to show "real time" progress bar when scripts/css get downloaded?
I know this can't be possible in HTML4 and would require Flash/Silverlight. But can I achieve this in HTML5? If yes, how would I do it?
I want to show a text like "Downloading" and as each script/css get downloaded real time, each letter of Downloading should start filling up. I am not asking for any code. Just want a high level concept of how that is possible.
Thanks.
Here's what I've been able to come up with; In HTML5 there is a <progress> element that you may be able to use. The bad news is that support for this element isn't as good as it could be. See the support chart here: http://caniuse.com/#search=progress There's no support in Safari 5 and below or IE9 and below. Partial support is in IE10 and any relevant versions of FireFox. If you need more support try a polyfil like this one: http://lea.verou.me/polyfills/progress/
If you choose to use the <progress> element here's a link about how to style it: http://www.useragentman.com/blog/2012/01/03/cross-browser-html5-progress-bars-in-depth/
Now the trick about making this work, you'll need to know the file size of the file(s) you'll be downloading and the number of bytes downloaded. As the files are being downloaded you'll have to get the header info that tells you how many bytes are transferred. You can see a sample of how to do that with jQuery here: http://markmail.org/message/kmrpk7w3h56tidxs#query:jquery%20ajax%20download%20progress+page:1+mid:kmrpk7w3h56tidxs+state:results
Note that this method will not work with IE. IE does not expose the header data of the XHR object.
At this point set the max attribute of the <progress> element to the total file size and using the setTimeout sample, update the value attribute of the <progress> element.
Knowing all this, maybe finding some kind of package solution with a built-in Flash fallback might be much easier to implement, and have better support. Anyone else have any ideas?
Good luck.

How to cancel an image from loading

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

Read size of current document from Javascript

I'm starting to play around with Boomerang for measuring performance. It's very promising. While it allows me to measure latency, bandwidth and page load times, I'm also interested in trying to get the time it took to render the initial HTML page server-side. Wile it seems straightforward to log the time at which the browser started parsing the javascript (which is close to when it initally arrived) in order to get an estimate of the server time, I need to work out how much network time to deduct. So to do that, I need to know how large the html document is.
How can I tell this from Javascript?
The document object does not appear to have an innerHtml property
I tried
totsize=document.HEAD.innerHTML.length + document.BODY.innerHTML.length;
The HEAD and BODY entities appear in the DOM browser within Firefox - but when I try the code above I get an undefined error - also tried with 'head' - to no avail.
Any ideas?
(note that javascript is in a seperate file and will be cached in most cases - so that's not a big problem).
I did try google - but I just get lots of pages describing the on-screen size of html elements and the window dimensions :(
TIA
How about document.documentElement.innerHTML.length ?
document.documentElement.innerHTML.length as per #meder is probably good enough. It won't be exact because it returns a serialisation of the current page DOM and not the original HTML source.
For static pages that won't matter as it'll just be the case of an extra close tag here, different attribute quoting there... but if there's lots of page content created on the fly from script, that content will count in innerHTML despite not being present in the original source, which could throw your calculation out.
If you need to find out the actual resource length, you'd need to fetch the page again, which you could do using an XMLHttpRequest on the current URL:
var xhr= new XMLHttpRequest();
xhr.onreadystatechange= function() {
if (this.readyState!==4) return;
alert(this.responseText.length);
};
xhr.open('GET', location.href, true);
xhr.send();
(This can't be done if the page is the result of a POST request though.)
This will give you a size in characters. If you are using an single-byte encoding like ISO-8859-1, the network-load byte size will be the same. If you're using UTF-8, then you can find out the byte size by converting the string to UTF-8-bytes-as-code-units, for which there's a quick idiomatic hack:
var bytes= unescape(encodeURIComponent(this.responseText));
alert(bytes.length);
If you are unfortunate enough to be using a non-UTF-8 multibyte encoding you can't really do much here; you'd have to include full mapping tables for the encoding, which for East Asian encodings would be insanely large.
How about this?:
/*
* This script determines the size of the current page in bytes.
* But why does the 2nd length differ from the first?
*/
var len=document.getElementsByTagName("html")[0].innerHTML.length;
var len2=document.getElementsByTagName("head")[0].innerHTML.length + document.getElementsByTagName("body")[0].innerHTML.length;
//document.body.innerHTML.length
alert('Page Size: '+len +' bytes');
alert('Page Size2: '+len2+' bytes');
It seems to work ok, BUT NOT great. As it gives two different lengths. But why?
Ugh! This formatting is killing me.
EDIT: Can somebody please fix this formatting? My browser isn't working right, apparently. Firefox 15.x
EDIT: fixed formatting

Categories

Resources