I’m trying to put image in clipboard when user copies canvas selection:
So I thought the right way would be to convert canvas tu dataURL, dataURL to blob and blob to binary string.
Theoretically it should be possible to skip the blob, but I don’t know why.
So this is what I did:
function copy(event) { console.log("copy"); console.log(event); //Get DataTransfer object var items = (event.clipboardData || event.originalEvent.clipboardData); //Canvas to blob var blob = Blob.fromDataURL(_this.editor.selection.getSelectedImage().toDataURL("image/png")); //File reader to convert blob to binary string var reader = new FileReader(); //File reader is for some reason asynchronous reader.onloadend = function () { items.setData(reader.result, "image/png"); } //This starts the conversion reader.readAsBinaryString(blob); //Prevent default copy operation event.preventDefault(); event.cancelBubble = true; return false; } div.addEventListener('copy', copy);
But when the DataTransfer
object is used out of the paste
event thread the setData
has no longer any chance to take effect.
How can I do the conversion in the same function thread?
Advertisement
Answer
Here is a hacky-way to get you synchronously from a blob to its bytes. I’m not sure how well this works for any binary data.
function blobToUint8Array(b) { var uri = URL.createObjectURL(b), xhr = new XMLHttpRequest(), i, ui8; xhr.open('GET', uri, false); xhr.send(); URL.revokeObjectURL(uri); ui8 = new Uint8Array(xhr.response.length); for (i = 0; i < xhr.response.length; ++i) { ui8[i] = xhr.response.charCodeAt(i); } return ui8; } var b = new Blob(['abc'], {type: 'application/octet-stream'}); blobToUint8Array(b); // [97, 98, 99]
You should consider keeping it async but making it two-stage, though, as you may end up locking up the browser.
Additionally, you can skip Blobs entirely by including a binary-safe Base64 decoder, and you probably don’t need to go via Base64 AND Blob, just one of them.