React - how to copy an image to clipboard?

UNl*_*nel 4 html javascript image copy-paste reactjs

im working on react web app and one of the feature needs to be implemented is to copy an image when clicked, so the user could paste it in: paint, word, etc...

i tried several approaches, first was to follow the instructions detailed in this post: /sf/answers/2838322931/

这就是我想到的(containerId 指的是一个 div 元素,其中包含一个图像元素作为其第一个子元素):

copyImg = (containerId) => {
const imgContainerElement = document.getElementById(containerId);
this.selectText(imgContainerElement.children[0]);
document.execCommand('copy');
window.getSelection().removeAllRanges();
alert('image copied!');
}

selectText = (element) => {
    var doc = document;
    if (doc.body.createTextRange) {
      var range = document.body.createTextRange();
      range.moveToElementText(element);
      range.select();
    } else if (window.getSelection) {
      var selection = window.getSelection();
      var range = document.createRange();
      range.selectNodeContents(element);
      selection.removeAllRanges();
      selection.addRange(range);
    }
  }
Run Code Online (Sandbox Code Playgroud)

没用。我尝试在这里实现标有 2 颗星的解决方案:https://www.tek-tips.com/viewthread.cfm ?qid=833917

  function copyImg(imgId){
  var r = document.body.createControlRange();
  r.add(document.getElementById(imgId));
  r.select();
  r.execCommand("COPY");
}
Run Code Online (Sandbox Code Playgroud)

但 createControlRange() 未定义。

我尝试使用 navigator.clipboard api,但它仅适用于 png,而该应用程序适用于 jpg。

我寻找一个可以完成此任务的 npm 库,但我找到的只是用于文本复制。npm 类似:react-copy-to-clipboard

任何帮助,将不胜感激。

编辑1:

遵循 dw_ /sf/answers/4142858891/说明,这就是我想到的:(注意:我必须 npm 安装 babel-polyfill 并将其导入 App.js,以便使异步功能工作并传递此错误:regeneratorRuntime 未定义)

    copyImg = async (imgElementId) => {
    const imgElement = document.getElementById(imgElementId);
    const src = imgElement.src;
    const img = await fetch(src);
    const imgBlob = await img.blob();
    if (src.endsWith(".jpg") || src.endsWith(".jpeg")) {
      copyService.convertToPng(imgBlob);
    } else if (src.endsWith(".png")) {
      copyService.copyToClipboard(imgBlob);
    } else {
      console.error("Format unsupported");
    }
 }

convertToPng = (imgBlob) => {
    const imageUrl = window.URL.createObjectURL(imgBlob);
    const canvas = document.createElement("canvas");
    const ctx = canvas.getContext("2d");
    const imageEl = createImage({ src: imageUrl });
    imageEl.onload = (e) => {
        canvas.width = e.target.width;
        canvas.height = e.target.height;
        ctx.drawImage(e.target, 0, 0, e.target.width, e.target.height);
        canvas.toBlob(copyToClipboard, "image/png", 1);
    };
}

createImage = (options) => {
    options = options || {};
    const img = (Image) ? new Image() : document.createElement("img");
    if (options.src) {
        img.src = options.src;
    }
    return img;
  }

copyToClipboard = (pngBlob) => {
    try {
        navigator.clipboard.write([
            new ClipboardItem({
                [pngBlob.type]: pngBlob
            })
        ]);
        console.log("Image copied");
    } catch (error) {
        console.error(error);
    }
}
Run Code Online (Sandbox Code Playgroud)

代码到达图像复制消息,但将其粘贴到单词上时仍然不显示。另一件事是我得到

控制台错误:未捕获(承诺中)DOMException

dw_*_*dw_ 5

基于 @Zohaib Ijaz 的回答和使用 HTML5 URL 和 Canvas 将 JPG 图像转换为 PNG 的文章。

如果图像是 jpeg/jpg,它会首先使用 HTML5 canvas 将图像转换为 png。

function createImage(options) {
  options = options || {};
  const img = (Image) ? new Image() : document.createElement("img");
  if (options.src) {
  	img.src = options.src;
  }
  return img;
}
       
function convertToPng(imgBlob) {
  const imageUrl = window.URL.createObjectURL(imgBlob);
  const canvas = document.createElement("canvas");
  const ctx = canvas.getContext("2d");
  const imageEl = createImage({ src: imageUrl });
  imageEl.onload = (e) => {
    canvas.width = e.target.width;
    canvas.height = e.target.height;
    ctx.drawImage(e.target, 0, 0, e.target.width, e.target.height);
    canvas.toBlob(copyToClipboard, "image/png", 1);
  };      
}

async function copyImg(src) {
   const img = await fetch(src);
   const imgBlob = await img.blob();
   if (src.endsWith(".jpg") || src.endsWith(".jpeg")) {
     convertToPng(imgBlob);
   } else if (src.endsWith(".png")) {
     copyToClipboard(imgBlob);
   } else {
     console.error("Format unsupported");
   }
}

async function copyToClipboard(pngBlob) {
    try {
      await navigator.clipboard.write([
        new ClipboardItem({
            [pngBlob.type]: pngBlob
        })
      ]);
      console.log("Image copied");
    } catch (error) {
        console.error(error);
    }
}

function copyImageViaSelector(selector) {
	copyImg(document.querySelector(selector).src);
}
Run Code Online (Sandbox Code Playgroud)
  <img id="image" width="100" src="https://i.imgur.com/Oq3ie1b.jpg">
  <button onclick="copyImageViaSelector('#image')">Copy image</button>
Run Code Online (Sandbox Code Playgroud)

反应:

import React, { useRef } from "react";

const createImage = (options) => {
  options = options || {};
  const img = document.createElement("img");
  if (options.src) {
    img.src = options.src;
  }
  return img;
};

const copyToClipboard = async (pngBlob) => {
  try {
    await navigator.clipboard.write([
      // eslint-disable-next-line no-undef
      new ClipboardItem({
        [pngBlob.type]: pngBlob
      })
    ]);
    console.log("Image copied");
  } catch (error) {
    console.error(error);
  }
};

const convertToPng = (imgBlob) => {
  const canvas = document.createElement("canvas");
  const ctx = canvas.getContext("2d");
  const imageEl = createImage({ src: window.URL.createObjectURL(imgBlob) });
  imageEl.onload = (e) => {
    canvas.width = e.target.width;
    canvas.height = e.target.height;
    ctx.drawImage(e.target, 0, 0, e.target.width, e.target.height);
    canvas.toBlob(copyToClipboard, "image/png", 1);
  };
};

const copyImg = async (src) => {
  const img = await fetch(src);
  const imgBlob = await img.blob();
  const extension = src.split(".").pop();
  const supportedToBeConverted = ["jpeg", "jpg", "gif"];
  if (supportedToBeConverted.indexOf(extension.toLowerCase())) {
    return convertToPng(imgBlob);
  } else if (extension.toLowerCase() === "png") {
    return copyToClipboard(imgBlob);
  }
  console.error("Format unsupported");
  return;
};

const Image = () => {
  const ref = useRef(null);
  return (
    <div>
      <img id="image" ref={ref} width="100" src="https://i.imgur.com/Oq3ie1b.jpg" alt="" />
      <button onClick={() => copyImg(ref.current.src)}>copy img</button>
    </div>
  );
};

export default Image;
Run Code Online (Sandbox Code Playgroud)

已知限制:

  • 不适用于 IE / Safari /(Pre-chromium)Edge。
  • 仅适用于同一域中的映像或具有宽松 CORS 设置的服务器。