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.
Copy and paste me in this webpage!
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); |
You could use `Array.prototype.some` instead of `forEach`, then return true instead of setting `found = true`.
You’re right. I wasn’t familiar with
Array#some, thanks for the tip.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?
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.
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
hi can you give me sample …. proper example with html code
….. i can understand how i use that code in Html
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:
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 ?
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.
Hi.. So how can you invoke the paste event by pressing a button on your page rather than pressing control-v?
Thanks
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).
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?