24

I've created an image from my canvas object by using canvas.toDataURL("image/png", 0.7). It works fine to save the image from the context menu but it doesn't work to copy the image to the clipboard and paste it into a mail or a word document for example. Is it possible to get "copy to clipboard" to behave the same way it does for a "normal" image?

I'm thinking of creating a small server component that can take the base64 representation of the image and return a "normal" png image that I will be able to copy to clipboard. Could this work as a workaround?

Edit: To clearify: I'm using canvas.toDataURL("image/png", 0.7) to create an image from the canvas and I then set the src attribute of an img tag to the result. I can then select "copy image" from the context menu when right clicking on the image. The problem is then that I can't paste the image into Word and emails (Outlook at least). Pasting into Wordpad and mspaint works fine.

gusjap
  • 2,397
  • 5
  • 24
  • 38
  • 1
    BTW, Chrome (and I think FF also) will already let you right-click-copy-to-clipboard the canvas content. The clipboard will contain a .png image created from the canvas content. – markE Jan 09 '15 at 18:43
  • @df1 answer's works well for me (BUT…). The only draw back of it is that it copies HTML formatted image not binary image. Some applications that support image pasting don't understand HTML formatted images, however all should support binary ones which I've looked for a lot and can't reach any Javascript code that generates them till now. – Omar Mar 20 '19 at 13:41

6 Answers6

20

Clipboard API for images are now available on chrome

https://github.com/web-platform-tests/wpt/tree/master/clipboard-apis

const item = new ClipboardItem({ "image/png": blob });
navigator.clipboard.write([item]); 

Example

const canvas = document.createElement("canvas");
canvas.width = 100;
canvas.height = 100;
document.body.appendChild(canvas);
const ctx = canvas.getContext("2d");
ctx.fillRect(0, 0, canvas.width, canvas.height);
ctx.fillStyle = "#eee";
ctx.fillRect(10, 10, 50, 50);

//tested on chrome 76
canvas.toBlob(function(blob) { 
    const item = new ClipboardItem({ "image/png": blob });
    navigator.clipboard.write([item]); 
});
  • 1
    Note that, as of October 2020, this is experimental and not supported in Firefox or Safari: https://caniuse.com/mdn-api_clipboarditem – Josh Kelley Oct 06 '20 at 18:31
  • You can see a full working example in the [article](https://web.dev/async-clipboard/#write()). Currently, the API supports `image/png` and `image/svg+xml`. More support is [coming](https://chromestatus.com/features#async%20clipboard), included plans for full raw clipboard access. – DenverCoder9 Dec 16 '20 at 13:49
7

You can convert the canvas to img, put in inside a <div contenteditable>, select it and copy it.

var img = document.createElement('img');
img.src = canvas.toDataURL()

var div = document.createElement('div');
div.contentEditable = true;
div.appendChild(img);
document.body.appendChild(div);

// do copy
SelectText(div);
document.execCommand('Copy');
document.body.removeChild(div);

The SelectText function is from https://stackoverflow.com/a/40547470/1118626

function SelectText(element) {
    var doc = document;
    if (doc.body.createTextRange) {
        var range = document.body.createTextRange();
        range.moveToElementText(element);
        range.select();
    } else if (window.getSelection) {
        var selection = window.getSelection();
        var range = document.createRange();
        range.selectNodeContents(element);
        selection.removeAllRanges();
        selection.addRange(range);
    }
}
df1
  • 434
  • 4
  • 11
4

Much easier 1 liner:
Assuming u have a canvas.
The following code will copy the canvas (as blob --> PNG image) to your clipboard.

canvas.toBlob(blob => navigator.clipboard.write([new ClipboardItem({'image/png': blob})]))
Carson
  • 6,105
  • 2
  • 37
  • 45
Konstantinos
  • 943
  • 1
  • 9
  • 20
0

To add to the div.appendChild( img ) answer, this method of selecting works on most browsers:

window.getSelection().selectAllChildren( div );

As of 2022, the "right" way using ClipboardAPI does not work well on Safari or Firefox.

Complete code:

const canvas = document.getElementById("share");

let img = document.createElement('img'); 
img.src = canvas.toDataURL();

let div = document.createElement('div');
div.contentEditable = true;
div.appendChild( img );
document.body.appendChild( div );
div.focus();
window.getSelection().selectAllChildren( div );
document.execCommand('Copy');  // technically deprecated
document.body.removeChild( div );

`

dwhitnee
  • 1
  • 1
0

Clipboard feature is available only in secure contexts (HTTPS), in some or all supporting browsers. You need change protocol to https (SSL)

if (location.protocol !== 'https:') {
    location.replace(`https:${location.href.substring(location.protocol.length)}`);
}
Hoàng Vũ Tgtt
  • 1,863
  • 24
  • 8
-1

Today 4 years later, it's the most starred issue in Google Chrome. To copy images using JavaScript. And now it's possible!

Chrome 76 Beta supports it: https://blog.chromium.org/2019/06/chrome-76-beta-dark-mode-payments-new.html

You can read the full draft here: https://www.chromestatus.com/feature/5074658793619456

and here: https://w3c.github.io/clipboard-apis/#async-clipboard-api

Example:

var data = new Blob(["iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+P+/HgAFhAJ/wlseKgAAAABJRU5ErkJggg=="], {type : "image/png"});

  const clipboardItemInput = new ClipboardItem({'image/png' : blobInput});
  await navigator.clipboard.write([clipboardItemInput]);

You can test it here: http://w3c-test.org/clipboard-apis/async-write-image-read-image-manual.https.html

(Now it support only Chrome 76 beta)

More info: The draft document [contain examples]: https://docs.google.com/document/d/1lpi3-9vBP_1b7hZc2xBs0s_HaACJ6UigZZqHlJSNeJg/edit#heading=h.do75bvtsde7a

Aminadav Glickshtein
  • 23,232
  • 12
  • 77
  • 117
  • Are you sure about your example code? `new Blob(["...` will convert your DOMString to an UTF8 sequence, i.e it's just a text file with this string, it won't decode the base64 to actual binary data. – Kaiido Jun 19 '19 at 02:32
  • does not work in firefox – serge Aug 09 '22 at 13:25