169

I noticed a blog post from Google that mentions the ability to paste images directly from the clipboard into a Gmail message if you're using the latest version of Chrome. I tried this with my version of Chrome (12.0.742.91 beta-m) and it works great using control keys or the context menu.

From that behavior I need to assume that the latest version of webkit used in Chrome is able to deal with images in the Javascript paste event, but I have been unable to locate any references to such an enhancement. I believe ZeroClipboard binds to keypress events to trigger its flash functionality and as such wouldn't work through the context menu (also, ZeroClipboard is cross-browser and the post says this works only with Chrome).

So, how does this work and where the enhancement was made to Webkit (or Chrome) that enables the functionality?

Josh Lee
  • 171,072
  • 38
  • 269
  • 275
Emil Lerch
  • 4,416
  • 5
  • 33
  • 43
  • 3
    It seems that it works randomly with Firefox as well. Anybody knows if this is supposed to be supported with Firefox ? – Sébastien Sep 30 '13 at 13:36

4 Answers4

278

I spent some time experimenting with this. It seems to sort of follow the new Clipboard API spec. You can define a "paste" event handler and look at event.clipboardData.items, and call getAsFile() on them to get a Blob. Once you have a Blob, you can use FileReader on it to see what's in it. This is how you can get a data url for the stuff you just pasted in Chrome:

document.onpaste = function (event) {
    var items = (event.clipboardData || event.originalEvent.clipboardData).items;
    console.log(JSON.stringify(items)); // might give you mime types
    for (var 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);
        }
    }
};

Once you have a data url you can display the image on the page. If you want to upload it instead, you could use readAsBinaryString, or you could put it into an XHR using FormData.

Edit: Note that the item is of type DataTransferItem. JSON.stringify might not work on the items list, but you should be able to get mime type when you loop over items.

Nux
  • 9,276
  • 5
  • 59
  • 72
Nick Retallack
  • 18,986
  • 17
  • 92
  • 114
  • 7
    Clutching at straws here, but any ideas why event.clipboardData.items seems to be 'undefined' in Safari 5.1? Or even how to get the clipboard contents for a file/blob in Safari? Works great in Chrome. You'd think webkit would be webkit :( – Gavin Gilmour Aug 13 '11 at 00:03
  • 9
    @SenicaGonzalez that is because the data only exists for the duration of the event. After the event, it is gone, so when you try to flip open the object in the inspector you will see nothing. – Nick Retallack Jun 12 '12 at 08:38
  • 3
    Would you mind making an example how to submit a XMLHttpRequest with that image data? That would be real nice :D – poitroae Aug 04 '13 at 22:30
  • 2
    Here's how you can submit that using XMLHttpRequest, I wrote it up in a blog after I implemented it: http://blog.securevideo.com/2013/11/27/paste-screenshot-from-chrome-to-mvc/ – J.T. Taylor Nov 27 '13 at 16:11
  • @jitbit I believe `event.clipboardData` has been replaced with `event.dataTransfer` – PixnBits Jan 20 '14 at 21:14
  • 1
    Now that the first item in the list isn't always the file you pasted, I've updated it to loop through the items to find any pasted files. – Nick Retallack Sep 07 '15 at 20:28
  • 1
    in iOS' WebKit, `clipboardData` seems to be an instance of [DataTransfer](https://developer.mozilla.org/en-US/docs/Web/API/DataTransfer) – adib Mar 05 '16 at 13:15
  • readAsBinaryString is non-standard and deprecated. Can use readAsArrayBuffer instead. Source: https://developer.mozilla.org/en-US/docs/Web/API/FileReader/readAsBinaryString – Champ Jul 28 '16 at 15:23
  • But this function does not return anything to work with, nor so it affect any global variable, in other words, this function does nothing and there are no indication of where my file will be especally if I want to use readAsBinaryString – Doomer Apr 01 '20 at 19:43
  • 1
    Size of the file increases tremendously after this operation. am i missing something? – Max Aug 12 '20 at 11:53
  • @NickRetallack, my testing would agree that in Firefox, the data is gone once the `paste` event finishes, but the form can be submitted DURING the `paste` event to upload a file. However, in Chromium, the data seems to stay after the `paste` event. Do you know if "the data only exists for the duration of the event" is documented anywhere? – Reed Dec 22 '22 at 20:43
74

The answer by Nick seems to need small changes to still work :)

// window.addEventListener('paste', ... or
document.onpaste = function (event) {
  // use event.originalEvent.clipboard for newer chrome versions
  var items = (event.clipboardData  || event.originalEvent.clipboardData).items;
  console.log(JSON.stringify(items)); // will give you the mime types
  // find pasted image among pasted items
  var blob = null;
  for (var i = 0; i < items.length; i++) {
    if (items[i].type.indexOf("image") === 0) {
      blob = items[i].getAsFile();
    }
  }
  // load image if there is a pasted image
  if (blob !== null) {
    var reader = new FileReader();
    reader.onload = function(event) {
      console.log(event.target.result); // data url!
    };
    reader.readAsDataURL(blob);
  }
}

Example running code: http://jsfiddle.net/bt7BU/225/

So the changes to nicks answer were:

var items = event.clipboardData.items;

to

var items = (event.clipboardData  || event.originalEvent.clipboardData).items;

Also I had to take the second element from the pasted items (first one seems to be text/html if you copy an image from another web page into the buffer). So I changed

  var blob = items[0].getAsFile();

to a loop finding the item containing the image (see above)

I didn't know how to answer directly to Nick's answer, hope it is fine here :$ :)

robintibor
  • 991
  • 8
  • 13
  • 1
    How should we submit the image data as XMLHttpRequest? – poitroae Aug 04 '13 at 22:31
  • To others reading this, answer to this question may be included there now: http://stackoverflow.com/questions/18055422/how-to-receive-php-image-data-over-copy-n-paste-javascript-with-xmlhttprequest :) – robintibor Aug 13 '13 at 12:49
  • 5
    I don't understand. When I paste files in browser, the `clipboardData.items` is always empty in google chrome (Firefox works). The chrome now needs almost as much optimization as IE used to. – Tomáš Zato Oct 22 '14 at 22:54
  • 1
    Small edit: if (blob != null) { (or set blob = null in initialization) – Pancakeo Nov 27 '14 at 05:15
  • As @TomášZato said It only works in FF (but with error "TypeError: items is undefined") and not working in Chrome, Safari, IE. Is there any updates? – immayankmodi Sep 04 '15 at 17:38
  • @MayankModi this works for me in Chrome but not FF :) In FF I get TypeError items is undefined – Matthew Moisen Oct 03 '16 at 01:02
  • @MatthewMoisen Instead of the `items` property check the `files` property. https://developer.mozilla.org/en-US/docs/Web/API/ClipboardEvent – 1.21 gigawatts May 26 '17 at 23:16
  • [http://jsfiddle.net/bt7BU/225/](http://jsfiddle.net/bt7BU/225/) demo doesn't work with newest Chrome 59.0.3071.115 on Win10. Can anybody help? – qba Jul 03 '17 at 18:06
  • 1
    `event.clipboardData.items` worked fine for me on the latest Chrome, not sure when `event.originalEvent...` is useful? – Ruben Martinez Jr. Jul 03 '17 at 21:08
  • I believe that the "originalEvent" is needed only if your object is a jQuery object. In other words, if your event is vanilla Javascript then it's not needed; if it's a jQuery object then you need the originalEvent to get to the underlying items. – Peter Bowers Apr 02 '19 at 10:42
1

As far as I know -

With HTML 5 features(File Api and the related) - accessing clipboard image data is now possible with plain javascript.

This however fails to work on IE (anything less than IE 10). Don't know much about IE10 support also.

For IE the optiens that I believe are the 'fallback' options are either using Adobe's AIR api or using a signed applet

saurshaz
  • 489
  • 5
  • 17
0
<html><body>
<p> Right click on any image in chrome and press copy image.<br>
Press Ctrl + V to pase your image. Works on chrome </p>

<div id='MyDiv1'></div>

<script>
document.onpaste = function (event) {
  var items = (event.clipboardData || event.originalEvent.clipboardData).items;
  var blob = items[items.length - 1].getAsFile();
  var reader = new FileReader();
  reader.readAsDataURL(blob);
  reader.onload = function (event) {
    const img1 = document.createElement("img");
    img1.src = event.target.result; // Appending image data to img tag
    document.getElementById('MyDiv1').appendChild(img1);
  } 
}

</script>
</body></html>

Paste this and save as .html and you are good to go

  • Your answer could be improved with the help of supporting information such as tutorials and links to documentation – Harrison Jul 08 '23 at 07:47