Home

Code Snippet — Accessing Clipboard Images with Javascript

The system clipboard is a feature that most of us heavy computer users probably couldn’t survive a day without. While it’s mostly used for copying and pasting text, images can also be stored in the clipboard, by for example using the print screen key. Today I want to share with you how you can access these images with a bit of Javascript code. This works in modern versions of Chrome and Firefox, but the technique differs a bit between them.

Here’s the code:

// We start by checking if the browser supports the
// Clipboard object. If not, we need to create a
// contenteditable element that catches all pasted data
if (!window.Clipboard) {
  var pasteCatcher = document.createElement('div');

  // Firefox allows images to be pasted into contenteditable elements
  pasteCatcher.setAttribute('contenteditable', '');

  // We can hide the element and append it to the body,
  pasteCatcher.style.opacity = 0;
  document.body.appendChild(pasteCatcher);

  // as long as we make sure it is always in focus
  pasteCatcher.focus();
  document.addEventListener('click', function() {
    pasteCatcher.focus();
  });
}
// Add the paste event listener
window.addEventListener('paste', pasteHandler);

/* Handle paste events */
function pasteHandler(e) {
  // We need to check if event.clipboardData is supported (Chrome)
  if (e.clipboardData) {
    // Get the items from the clipboard
    var items = e.clipboardData.items;
    if (items) {
      // Loop through all items, looking for any kind of image
      for (var i = 0; i < items.length; i++) {
        if (items[i].type.indexOf('image') !== -1) {
          // We need to represent the image as a file,
          var blob = items[i].getAsFile();
          // and use a URL or webkitURL (whichever is available to the browser)
          // to create a temporary URL to the object
          var URLObj = window.URL || window.webkitURL;
          var source = URLObj.createObjectURL(blob);

          // The URL can then be used as the source of an image
          createImage(source);
        }
      }
    }
    // If we can't handle clipboard data directly (Firefox),
    // we need to read what was pasted from the contenteditable element
  } else {
    // This is a cheap trick to make sure we read the data
    // AFTER it has been inserted.
    setTimeout(checkInput, 1);
  }
}

/* Parse the input in the paste catcher element */
function checkInput() {
  // Store the pasted content in a variable
  var child = pasteCatcher.childNodes[0];

  // Clear the inner html to make sure we're always
  // getting the latest inserted content
  pasteCatcher.innerHTML = '';

  if (child) {
    // If the user pastes an image, the src attribute
    // will represent the image as a base64 encoded string.
    if (child.tagName === 'IMG') {
      createImage(child.src);
    }
  }
}

/* Creates a new image from a given source */
function createImage(source) {
  var pastedImage = new Image();
  pastedImage.onload = function() {
    // You now have the image!
  };
  pastedImage.src = source;
}

With Chrome we can access the image in the clipboard through the clipboardData object, but this can only be done inside a paste event handler. Inside the event handler, we loop through all items and search for an image. If we find one, we create a Blob of the image, and use the URL of it as the image source.

Firefox on the other hand does not have the clipboardData object, but we can work around this. In Firefox, it’s possible to paste images into elements with the contenteditable attribute set. By creating an invisible contenteditable element which always is focused, we can catch everything that the user pastes. So, everytime the user pastes something, we read through the content in the catcher element and check if it was an image. If it is, we simply take the source of that image and clear the element.

That nasty bit of code you see on line 48, setTimeout(checkInput, 1);, is a way to work around the fact that contenteditable elements don’t trigger oninput events in Firefox. Since the paste event triggers before anything is inserted into the element, we set a 1 ms timeout before we read the element’s content. This is enough time for the pasted content to be inserted.

Once we have the image, we can do anything we want with it, e.g append it to the page, draw it onto a canvas, upload it to a server, etc.



Last Updated on

Next Post: GraphProtocol: TS2322 null assignment in Subgraph →

Comments