Pasting anything other than simple text into the browser has historically been stupendously impossible. Until now… It’s a miracle, image data pasted into the browser can be retrieved with JavaScript (at least since Chrome 13.0.782.220)! Just use this jQuery plugin and start receiving paste events with images all their sweet gooey image data. This picks up paste events initiated with Ctrl+V
, it does not provide arbitrary clipboard access (which is probably sane from a security standpoint). What’s insane is that it used to be so hard to get pasted image data, but that is all behind us now.
Give it a try now, right click this wizard and choose “Copy Image”, then jam Ctrl+V
or Command+V
. Be amazed (unless you’re not using Chrome, and in that case, get off my lawn). It also works in the pixel editor on PixieEngine. Use the wizard there too, the editor currently only handles small images. Generally there is no size restriction, you can even paste image data from your favorite image editing programs, boot one up and try it out on this page.
# Created by STRd6 # MIT License # jquery.paste_image_reader.js.coffee (($) -> $.event.fix = ((originalFix) -> (event) -> event = originalFix.apply(this, arguments) if event.type.indexOf('copy') == 0 || event.type.indexOf('paste') == 0 event.clipboardData = event.originalEvent.clipboardData return event )($.event.fix) defaults = callback: $.noop matchType: /image.*/ $.fn.pasteImageReader = (options) -> if typeof options == "function" options = callback: options options = $.extend({}, defaults, options) this.each -> element = this $this = $(this) $this.bind 'paste', (event) -> found = false clipboardData = event.clipboardData Array::forEach.call clipboardData.types, (type, i) -> return if found if type.match(options.matchType) or clipboardData.items[i].type.match(options.matchType) file = clipboardData.items[i].getAsFile() reader = new FileReader() reader.onload = (evt) -> options.callback.call element, dataURL: evt.target.result event: evt file: file name: file.name reader.readAsDataURL(file) found = true )(jQuery)
Pretty simple plugin, eh? The first part is extending the copy and paste events in jQuery with the clipboardData object. Once the paste events have been extended with all the clipboard data that Chrome provides we can use that data to extract the image contents.
The meat of the plugin is binding a paste event to all the elements in the selector. When a paste event is triggered we loop through each MIME type until we hit one that claims to be an image. Once we find it we get the corresponding file data and load it as a dataURL. This can be used directly in CSS or passed on to the server and chopped up, base64 decoded, and stored as a regular png.
To use it you choose what element to listen to paste events on (html should get all of them). I haven’t messed around much with scoping it to other elements, but I don’t see why it wouldn’t work.
$("html").pasteImageReader (results) -> {filename, dataURL} = results $("body").css backgroundImage: "url(#{dataURL})"
Now when someone pastes a copied image to the page it sets the background to the pasted image. This is just scratching the surface, but the great thing is that you can now capture paste events containing images in pure JS/HTML.
What’s that? CoffeeScript is hot for you to handle? Well here’s the JS version:
// Created by STRd6 // MIT License // jquery.paste_image_reader.js (function($) { var defaults; $.event.fix = (function(originalFix) { return function(event) { event = originalFix.apply(this, arguments); if (event.type.indexOf('copy') === 0 || event.type.indexOf('paste') === 0) { event.clipboardData = event.originalEvent.clipboardData; } return event; }; })($.event.fix); defaults = { callback: $.noop, matchType: /image.*/ }; return $.fn.pasteImageReader = function(options) { if (typeof options === "function") { options = { callback: options }; } options = $.extend({}, defaults, options); return this.each(function() { var $this, element; element = this; $this = $(this); return $this.bind('paste', function(event) { var clipboardData, found; found = false; clipboardData = event.clipboardData; return Array.prototype.forEach.call(clipboardData.types, function(type, i) { var file, reader; if (found) { return; } if (type.match(options.matchType) || clipboardData.items[i].type.match(options.matchType)) { file = clipboardData.items[i].getAsFile(); reader = new FileReader(); reader.onload = function(evt) { return options.callback.call(element, { dataURL: evt.target.result, event: evt, file: file, name: file.name }); }; reader.readAsDataURL(file); return found = true; } }); }); }); }; })(jQuery);
// Created by STRd6
// MIT License
// jquery.paste_image_reader.js
(function() {
(function($) {
var defaults;
$.event.fix = (function(originalFix) {
return function(event) {
event = originalFix.apply(this, arguments);
if (event.type.indexOf(‘copy’) === 0 || event.type.indexOf(‘paste’) === 0) {
event.clipboardData = event.originalEvent.clipboardData;
}
return event;
};
})($.event.fix);
defaults = {
callback: $.noop,
matchType: /image.*/
};
return $.fn.pasteImageReader = function(options) {
if (typeof options === “function”) {
options = {
callback: options
};
}
options = $.extend({}, defaults, options);
return this.each(function() {
var $this, element;
element = this;
$this = $(this);
return $this.bind(‘paste’, function(event) {
var clipboardData, found;
found = false;
clipboardData = event.clipboardData;
return Array.prototype.forEach.call(clipboardData.types, function(type, i) {
var file, reader;
if (found) {
return;
}
if (type.match(options.matchType) || clipboardData.items[i].type.match(options.matchType)) {
file = clipboardData.items[i].getAsFile();
reader = new FileReader();
reader.onload = function(evt) {
return options.callback.call(element, {
dataURL: evt.target.result,
event: evt,
file: file,
name: file.name
});
};
reader.readAsDataURL(file);
return found = true;
}
});
});
});
};
})(jQuery);
}).call(this);
jQuery(“html”).pasteImageReader(function(results) {
var dataURL, filename;
filename = results.filename, dataURL = results.dataURL;
_gaq.push(“_trackEvent”, “Special”, “HTML5 Paste”, filename);
return jQuery(“#page”).css({
backgroundImage: “url(” + dataURL + “)”,
backgroundRepeat: “repeat”
});
});
You could use `Array.prototype.some` instead of `forEach`, then return true instead of setting `found = true`.
LikeLike
You’re right. I wasn’t familiar with
Array#some
, thanks for the tip.LikeLike
That’s awesome! I’ve been looking for something like that for ages, and your page is the only actual implementation I could find. How far is that from using the clipboard data to be passed as a regular file? I mean, I’d like to Ctrl-V the content of my clipboard on an html5 dnd area to do whatever it’d do on a regular file (attach it in gmail, upload it in a php method, etc.) without having to save the file from clipboard to disk. Is it straightforward or is there some work to do?
LikeLike
It’s almost exactly the same. The HTML5 file api handles pasted data just like dropped file data. You use a FileReader() to get the data in both instances.
LikeLike
Nice demo and page. Pretty smart trick!
Hey these guys got it working on Firefox: http://pasteboard.co/ in case you’re interested in stretching your plugin to work in more browsers
LikeLike
hi can you give me sample …. proper example with html code
….. i can understand how i use that code in Html
LikeLike
You can use any simple HTML page as long as you include jQuery and this JS code: https://gist.github.com/STRd6/5286415
On your page after the DOM has loaded do this:
LikeLike
Hi,
i want to ask a queation, i want to use this code for other browser is it possible or how can i do this ?
LikeLike
It should work for any browser that implements the File API: http://caniuse.com/#feat=fileapi
It may require some further testing and modifications for any cross browser differences.
LikeLike
Hi.. So how can you invoke the paste event by pressing a button on your page rather than pressing control-v?
Thanks
LikeLike
You aren’t able to get arbitrary acces to the clipboard without a plugin. HTML5 only gets access through paste events (Control + V, or right click and choose paste).
LikeLike
Thanks for your quick reply… Is there anyway I could invoke keyboard events such as using “event.initKeyEvent”? to replicate a control-v keypress when the user presses a button?
LikeLike
Not natively in HTML5, the paste event is controlled by the OS.
LikeLike
Daniel, thanks for sharing this. I have a question, some of our users are pasting screenshot snippets with a white background and black letters/graphs. These are screenshots from a Word document. It’s very strange, if the screenshot comes straight from the Word file, it just pastes a white image, but if the screenshot is from a “text box” in Word, it works just fine.
Any ideas on what the issue might be?
Thanks!
LikeLike
I would guess that depending on how the image is copied it could change how the image data is encoded. It’s really entirely up to the application that you copy data from on how to present the data that’s been copied. I assume that Word might be careless with the encoding depending on the context. I have also experienced something similar when transparent pixels where being copied as black, but was never really able to get to the bottom of it.
LikeLike
Hi, which version should I include jquery on the page, to run the paste-image-reader.
Thank you.
LikeLike
I haven’t tested with 2.0 yet, but 1.6.x-1.9.x should work fine. 2.0 may also work, but as I said I haven’t tested it.
LikeLike
Daniel, any idea why this doesn’t want to work with Safari 6? http://caniuse.com/#feat=fileapi shows that Safari fully supports fileapi.
LikeLike
Hi and thanks for the great article. Wondering how to determine size (width and height in pixels) of the pasted object. Right now have it working into a canvas of an arbitrary size but need to set the canvas to be the same size as the pasted image. Otherwise the image either gets clipped if too big or there is empty space surrounding the image.
LikeLike
Following up on question about getting size of pasted image
I’ve tried the following by modifying jquery.paste_image_reader.js
//added 5 lines
var img3 = new Image();
img3.onload = function(){
alert(“file info 3nwidth=” + img3.width + “nheight=” + img3.height);
};
img3.src = evt.target.result;
return options.callback.call(element, {
dataURL: evt.target.result,
event: evt,
file: file,
name: file.name,
//added 2 lines
width: img3.width,
height: img3.height
});
First time image is pasted the width and height are 0 … when same image is pasted again the correct dimensions show. I’m doing something out of order …
LikeLike
Is it possible to upload images from a mixed content with text and image? The use case is, user could copy rich content from some web page and paste into my rich editor. And the images embedded in the content will be uploaded to my server.
I can now obtain image objects, it will contain a remote url, I need image content from user’s browser/cache. Usually I can retrieve the image remotely by server-side scripts, but some website has this anti-leach technique that I can’t bypass. The user could always download the picture and uploaded to the server manually, I just want to my my site more user friendly.
LikeLike
Edward,
I believe that is possible, but it would require quite a bit more work than just uploading images. You can use this script as a starting point and experiment by seeing what types show up in `clipboardData.types`. Extracting the data would also require some additional work but in principle it should be doable.
LikeLike
Hi, this is awesome!
One question, the data url is always image/png type, no matter if we select a jpeg or gif image. Is this by design of HTML5 or is there any different explanation? We can convert the image server side, but I’m still curious.
Thanks!
LikeLike
Gorgi,
I believe it is the default type for the readAsDataURL method and I don’t see any option to modify it. https://developer.mozilla.org/en-US/docs/Web/API/FileReader#readAsDataURL()
LikeLike
Hi Daniel,
The script run smoothly in Chrome, but this doesn’t seem to be the case with Firefox. Can you verify that it indeed works on both Chrome and FF?
Thanks,
John
LikeLike
This works very well in Chrome, however it does not work in Firefox as FF doesn’t fully support clipboardData and doesn’t include any clipboardData.types. See: https://bugzilla.mozilla.org/show_bug.cgi?id=407983
LikeLike
The problem is that i am using this code
$( document ).ready(function() {
var dataURL=’dhruv’;
$(“html”).pasteImageReader(function(results) {
var filename;
alert(results.dataURL);
//$(“image11”).css({
// backgroundImage: “url(” + results.dataURL + “)”
//});
$(“#image11”).attr(“src”, results.dataURL);
return filename = results.filename, dataURL = results.dataURL, results;
});
here if i use “#textbox1” instead of “html” where “#textbox1” is ID of textbox set using getelement.setid(“”) function.
It does not work for this condition. any idea why it is not working?
LikeLike
I am using Container to use my app and my container uses chromium but It does not work for Chromium , Any idea why it doesnot ?
LikeLike
Hey, Can you let me know if we can do Copy & paste documents other than image such as .docx, .pdf. .xlsx and etc?
My requirement is to copy & paste document from a PC or email to a web form (not a Drag & Drop).
Thanks for your help!!
LikeLike
Hi there, I tested this page on Ubuntu 12.04 and Chrome 36.0.1985.125. When I copy image from my localfile system (ctrl + c) and pasted in page (ctrl + v) it simply wont work 😦
When I press print preview and press button copy to clipboard and pasted in this page it work.
What is difference in these two?
How I deal with ctrl + c Any idea?
LikeLike
Hi, it is only working on chrome. not other browser. Can you help me?
LikeLike
To get width and height you must modify this part:
reader.onload = function(evt) {
var img = new Image();
img.onload = function(){
return options.callback.call(element, {
dataURL: evt.target.result,
event: evt,
file: file,
name: file.name,
width: img.width,
height: img.height
});
};
img.src = evt.target.result;
};
LikeLike
Hi Daniel X Moore,
Thanks for sharing such an awesome way to do so. I’m sharing this http://jsfiddle.net/FhUwn/392/ link so it can help others with latest working example. I’ve tested in FF, Chrome and IE (with all latest versions).
Keep up the good work!
LikeLike
Hi Daniel,
i m able to capture image and copy paste it ,but i dont know how to save that image in sql server.
LikeLike
Hi, This is a great stuff to see in action.
I wonder if we are able to (Ctrl+C) a file in windows OS like from some folder and (Ctrl+V) that to web browser?
I saw same question by guru user above. Any one found luck doing this?
Thanks,
Abdul
LikeLike
This is the perfect solution for my purposes! Thanks so much for posting it.
LikeLike