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.
Related
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.
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 need to capture the event triggered by dragging and dropping a bookmark onto the window, preferably in all browsers. What I actually need is the target url of the bookmark. onbeforeunload does get triggered, but the event has no information about the target URL and I can't stop the page from loading it either. mouseup also does not work.
The FileReader API seems viable, but I'm not sure whether it's appropriate. Ideally this would also work in at least IE9 (which does not support FileReader).
I have a solution to part one of this problem, but I myself would like some help with the second part of it, so if this serves as a bump for your question it'd be much appreciated.
NOTE: Most of this is based off of my personal experience, so I'll make notes about compatibility before we get too far in.
The drop event is supported on Microsoft Edge 12+, and has a field, dataTransfer, that contains information about the element being dragged/dropped. This field was added to IE in is always null, and for that reason I won't be talking about a solution I found for it. From the timing of your post, it seems like you're using the latest Microsoft browser, which means that the features I talk about below will be supported.
The first event you'll want to take a look at is drop. This event, fairly logically, is an event that is fired when you drop an element onto a page, be it a file, another element, or in our case, a bookmark.
The second event, rather confusingly, is dragover. For some unknown reason, suppressing default behavior of the drop event on its own does not seem to completely negate the effect of going to a new webpage, instead redirecting me (using Chrome 94) to about:blank#blocked in a new tab, which might interfere with UX.
The files attribute of dataTransfer for the drop event usually contains the information about the data that is being transferred, and as I have experimented with, I've gotten this data from it:
{
items: DataTransferItemList {0: DataTransferItem {'kind': 'string', 'type': 'text/plain'}, 1: DataTransferItem {'kind': 'string', 'type': 'text/uri-list'}, length: 2},
types: ['text/plain', 'text/uri-list'],
files: FileList {length: 0}
}
I'm rather frustrated by the fact that files contains no data, and it's currently got me stuck to a point where I can't get any further. I'll see if I remember to post back here when/if it gets fixed, but until then, there's another thing I'd like to point out.
On Windows computers, internet shortcuts are actually small files with the .url extension. So, it's possible to obtain both a name for a site and its address if the user simply drags in a shortcut from their homepage. My code for getting the data is below.
element.addEventListener('drag', function(event)) {
event.preventDefault();
// in case you haven't put this in already; having multiple has
// the same effect as one
let shortcutFile = event.dataTransfer.files[0];
// This assumes the user is only dragging a single file, but it can be
// expanded to others by simply detecting the extension of the file.
let fileName = shortcutFile.name;
let fileLines = fileContent.split('\n');
// the last line of the file has a pattern that looks like this:
// URL=<url to site>
// this is what i'm going to be using to get the address.
//
// the better solution to the first index below would be to use
// Array.prototype.at(-1), however doing so would require a polyfill
// on all versions of Opera, IE, and Safari, not to mention that even somewhat
// recent browsers don't have this method implemented.
let siteUrl = fileLines[fileLines.length - 1].match(/(?<=URL=)/)[0];
// going to use one of my favorite JS features here: object destructuring!
// it's not supported in some older browsers, or in IE at all, but it's a VERY
// cool feature nonetheless, so I use it when i really shouldn't a lot of the time
//
// i know stuff is supposed to be cross-compatible but what's the point
// in browsers getting new APIs/interfaces like this if you don't use
// them?
return {fileName, siteUrl};
// oh yeah explanation of how it works
// it's basically the same thing as saying {fileName: fileName, siteUrl: siteUrl}
// looks very nice right?
}
Hope this information and workaround helps, and that the exact issue we both have gets resolved!
I found the solution! You have to use this method to get the actual URL: DataTransfer.getData(). Try putting
console.log(e.dataTransfer.getData("text/plain"));
into your "drop" event - it shows the URL for both Firefox and Chrome.
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.
This question already has answers here:
How does the paste image from clipboard functionality work in Gmail and Google Chrome 12+?
(3 answers)
Closed 3 years ago.
How do we paste an image from clipboard into a custom rich text editor using javascript? (ctrl+c and ctrl+v or a snapshot).
Has anyone used Ajax's rich text editor? Does pasting an image from clipboard to Ajax RTE work?
Because this question still often shows up in Google's search results, I want to point out this is possible today, at least in Google Chrome (2011) in all modern browsers (2018). They implemented it to use in GMail, but it is available for all websites.
How does the paste image from clipboard functionality work in Gmail and Google Chrome 12+?
To help others, I'll leave the link here with the answer made by Nick Rattalack
// window.addEventListener('paste', ... or
document.onpaste = function(event){
var items = (event.clipboardData || event.originalEvent.clipboardData).items;
console.log(JSON.stringify(items)); // will give you the mime types
for (index in items) {
var item = items[index];
if (item.kind === 'file') {
var blob = item.getAsFile();
var reader = new FileReader();
reader.onload = function(event){
console.log(event.target.result)}; // data url!
reader.readAsDataURL(blob);
}
}
}
How does the paste image from clipboard functionality work in Gmail and Google Chrome 12+?
This is definitely possible now in Chrome and Firefox. I'm not so sure about IE/Safari.
Look at imgur.com, onpaste, and pasteboard.co as examples, and see the code for pasteboard on github as well as Joel's excellent write up on his blog
For the record, you need the user to press Ctrl+V on your element, and then you can capture the data in the paste event handler by reading from event.clipboardData but to make it work down-level, you need to be sure focus is on an empty contenteditable element, and pull the results from there, which doesn't work well in Firefox 22. See here
New browsers, like Firefox 4, support pasting of image data from clipboard into a RTE as Data URI with encoded PNG Data. However, most web applications incorrectly parse these Data URIs and discard it. Yahoo mail properly handles. However Gmail and Hotmail discard it. I have notified Google and Microsoft about this.
For now i found the clipboardData Object .
But it retrieve only text format or URL from clipboard.
clipboardData is IE only, it works with character string and return null if we paste an image.
a test example
<form>
<input type="text" id="context" onClick="paste();">
</form>
<script type="text/javascript">
function paste() {
var sRetrieveData = clipboardData.getData("Text");
document.getElementById('context').value = sRetrieveData;
}
</script>
By default clipboard access is not enabled on firefox, explanation here.
On the other way, execCommand() only process text values and is not Firefox compliant.
Like the others said, the fact that code works on IE is a security risk, any site can access your clipboard text.
The easiest way to copy images relative URL is to use a java applet, windows activeX plugin, .net code or drag and drop it.
Unfortunately, It's not possible to paste an image from your clipboard to the RTE.
If you copy a blob from a desktop app like Microsoft Word that contains an image and some text, the image will turn up as a broken reference (though the proportions will be correct) and the text will be pasted correctly (formatting will be lost).
The only thing that is possible is to copy an image within the RTE and paste back within the RTE.