Html 如何让用户使用纯 Javascript 将剪贴板中的图像数据粘贴到 Firefox 中的画布元素中?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/18377891/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-29 12:27:55  来源:igfitidea点击:

How can I let user paste image data from the clipboard into a canvas element in Firefox in pure Javascript?

javascripthtmlfirefoxcanvas

提问by DG.

I have done my best to find a simple, relevant, and up-to-date example that works for the latest version of Firefox and I'm really struggling.

我已尽力找到一个适用于最新版本 Firefox 的简单、相关且最新的示例,但我真的很挣扎。

Titles says it all really. I want the user to able to copy part of an image from an editor such as Windows Paint or use the Print Screen button and then paste that into a canvas element. Bonus points if the canvas resizes to fit exactly the pasted image (literally).

标题说明了一切。我希望用户能够从 Windows Paint 等编辑器复制部分图像,或使用 Print Screen 按钮,然后将其粘贴到画布元素中。如果画布调整大小以完全适合粘贴的图像(字面意思),则加分。

Want to avoid Flash or Java based solutions if reasonable.

如果合理,希望避免基于 Flash 或 Java 的解决方案。

I'm half-decent at Javascript but relatively inexperienced with the latest HTML5 features and totally new to the Canvas element. Please help!

我在 Javascript 方面还算不错,但对最新的 HTML5 功能相对缺乏经验,并且对 Canvas 元素完全陌生。请帮忙!

回答by ViliusL

Version 2.0: Smaller, cleaner code works on Chrome, Firefox, Edge, Opera. No more hacks. But if you need support IE and Safari, check v1 version.

2.0 版:更小、更干净的代码适用于 Chrome、Firefox、Edge、Opera。没有更多的黑客。但如果您需要支持 IE 和 Safari,请查看 v1 版本。

http://jsfiddle.net/viliusl/xq2aLj4b/5/

http://jsfiddle.net/viliusl/xq2aLj4b/5/



Version 1.0Chrome implementation is simple. Firefox (and IE) has restrictions that user must give command to do paste like keyboard event and editable input must be focused, so we do tricks here - on ctrl down we focusthat input field, on release unfocus.

1.0 版Chrome 实现很简单。Firefox(和 IE)有一些限制,用户必须像键盘事件一样发出命令来进行粘贴,并且可编辑的输入必须聚焦,所以我们在这里做了一些技巧 - 在 ctrl 上我们聚焦那个输入字段,在释放时不聚焦。

Browser support(image data):

浏览器支持(图像数据):

  • Firefox
  • Chrome
  • Edge
  • IE-11
  • Opera
  • 火狐
  • 铬合金
  • 边缘
  • IE-11
  • 歌剧

var CLIPBOARD = new CLIPBOARD_CLASS("my_canvas", true);

/**
 * image pasting into canvas
 * 
 * @param {string} canvas_id - canvas id
 * @param {boolean} autoresize - if canvas will be resized
 */
function CLIPBOARD_CLASS(canvas_id, autoresize) {
 var _self = this;
 var canvas = document.getElementById(canvas_id);
 var ctx = document.getElementById(canvas_id).getContext("2d");
 var ctrl_pressed = false;
 var command_pressed = false;
 var paste_event_support;
 var pasteCatcher;

 //handlers
 document.addEventListener('keydown', function (e) {
  _self.on_keyboard_action(e);
 }, false); //firefox fix
 document.addEventListener('keyup', function (e) {
  _self.on_keyboardup_action(e);
 }, false); //firefox fix
 document.addEventListener('paste', function (e) {
  _self.paste_auto(e);
 }, false); //official paste handler

 //constructor - we ignore security checks here
 this.init = function () {
  pasteCatcher = document.createElement("div");
  pasteCatcher.setAttribute("id", "paste_ff");
  pasteCatcher.setAttribute("contenteditable", "");
  pasteCatcher.style.cssText = 'opacity:0;position:fixed;top:0px;left:0px;width:10px;margin-left:-20px;';
  document.body.appendChild(pasteCatcher);

  // create an observer instance
  var observer = new MutationObserver(function(mutations) {
   mutations.forEach(function(mutation) {
    if (paste_event_support === true || ctrl_pressed == false || mutation.type != 'childList'){
     //we already got data in paste_auto()
     return true;
    }

    //if paste handle failed - capture pasted object manually
    if(mutation.addedNodes.length == 1) {
     if (mutation.addedNodes[0].src != undefined) {
      //image
      _self.paste_createImage(mutation.addedNodes[0].src);
     }
     //register cleanup after some time.
     setTimeout(function () {
      pasteCatcher.innerHTML = '';
     }, 20);
    }
   });
  });
  var target = document.getElementById('paste_ff');
  var config = { attributes: true, childList: true, characterData: true };
  observer.observe(target, config);
 }();
 //default paste action
 this.paste_auto = function (e) {
  paste_event_support = false;
  if(pasteCatcher != undefined){
   pasteCatcher.innerHTML = '';
  }
  if (e.clipboardData) {
   var items = e.clipboardData.items;
   if (items) {
    paste_event_support = true;
    //access data directly
    for (var i = 0; i < items.length; i++) {
     if (items[i].type.indexOf("image") !== -1) {
      //image
      var blob = items[i].getAsFile();
      var URLObj = window.URL || window.webkitURL;
      var source = URLObj.createObjectURL(blob);
      this.paste_createImage(source);
     }
    }
    e.preventDefault();
   }
   else {
    //wait for DOMSubtreeModified event
    //https://bugzilla.mozilla.org/show_bug.cgi?id=891247
   }
  }
 };
 //on keyboard press
 this.on_keyboard_action = function (event) {
  k = event.keyCode;
  //ctrl
  if (k == 17 || event.metaKey || event.ctrlKey) {
   if (ctrl_pressed == false)
    ctrl_pressed = true;
  }
  //v
  if (k == 86) {
   if (document.activeElement != undefined && document.activeElement.type == 'text') {
    //let user paste into some input
    return false;
   }

   if (ctrl_pressed == true && pasteCatcher != undefined){
    pasteCatcher.focus();
   }
  }
 };
 //on kaybord release
 this.on_keyboardup_action = function (event) {
  //ctrl
  if (event.ctrlKey == false && ctrl_pressed == true) {
   ctrl_pressed = false;
  }
  //command
  else if(event.metaKey == false && command_pressed == true){
   command_pressed = false;
   ctrl_pressed = false;
  }
 };
 //draw pasted image to canvas
 this.paste_createImage = function (source) {
  var pastedImage = new Image();
  pastedImage.onload = function () {
   if(autoresize == true){
    //resize
    canvas.width = pastedImage.width;
    canvas.height = pastedImage.height;
   }
   else{
    //clear canvas
    ctx.clearRect(0, 0, canvas.width, canvas.height);
   }
   ctx.drawImage(pastedImage, 0, 0);
  };
  pastedImage.src = source;
 };
}
1. Copy image data into clipboard or press Print Screen <br>
2. Press Ctrl+V (page/iframe must be focused):
<br /><br />
<canvas style="border:1px solid grey;" id="my_canvas" width="300" height="300"></canvas>

回答by DG.

ViliusL's answer is great, but for those looking for a simple cross-browser way to capture a pasted image:

ViliusL 的回答很好,但对于那些正在寻找一种简单的跨浏览器方式来捕获粘贴图像的人来说:

window.addEventListener("paste", async function(e) {
  e.preventDefault();
  e.stopPropagation();
  let file = e.clipboardData.items[0].getAsFile();
  let objectUrl = URL.createObjectURL(file);
  // do something with url here
});

You'll probably want to do some error checking (like in ViliusL's answer), in case they paste something that's not an image. According to MDN, clipboardDataworks in all modern browsers. I've tested on Chrome and Firefox, and they work fine.

您可能需要进行一些错误检查(如 ViliusL 的回答),以防他们粘贴了不是图像的内容。根据 MDN,clipboardData适用于所有现代浏览器。我已经在 Chrome 和 Firefox 上进行了测试,它们运行良好。