如何将图像从 url 沿侧输入类型文件加载到 html5 画布?

Posted

技术标签:

【中文标题】如何将图像从 url 沿侧输入类型文件加载到 html5 画布?【英文标题】:How can I load image from url along side input type file to html5 canvas? 【发布时间】:2021-05-29 11:55:53 【问题描述】:

我正在开发这个应用程序,我需要从 url 以及用户的硬盘驱动器将图像上传到 html5 画布。我已经为用户从硬盘驱动器输入实现了功能,但我不知道如何从 url 添加图像。

我用来从input type file 加载的代码都在输入的事件监听器中。它有很多功能,因为该应用程序还需要在图像上输入text。所以image from url 也应该有同样的功能。

请注意imgObj 在事件监听器中。我尝试将 img.src 更改为 url 来测试它,但即使图像加载,我也无法再下载它。控制台抛出此错误:

Uncaught DOMException: Failed to execute 'toDataURL' on 'HTMLCanvasElement': Tainted canvases may not be exported.
    at HTMLButtonElement.<anonymous>

这里的代码减去了一些不需要在这里展示的函数:

const canvas            = document.getElementById('canvas');
const ctx               = canvas.getContext('2d');
const btnDownload       = document.getElementById('btnDownload');
const fileUpload        = document.getElementById('file-upload');

fileUpload.addEventListener('change', function(e) 
    let imgObj          = new Image();
    imgObj.onload       = draw;
    imgObj.onerror      = failed;
    imgObj.src          = URL.createObjectURL(this.files[0]);
    // imgObj.src          = 'https://static.vecteezy.com/system/resources/previews/000/094/478/original/free-abstract-pattern-vector.jpg';
    

    // some functions to write on image

);


function draw() 
    canvas.width        = this.naturalWidth;
    canvas.height       = this.naturalHeight;
    const nw            = this.naturalWidth;
    const nh            = this.naturalHeight;

    ctx.drawImage(this, 0, 0, nw, nh);
;
    
function failed() 
    console.error("The provided file couldn't be loaded as an Image media");
;

btnDownload.addEventListener('click', () => 

    const a = document.createElement('a');
    document.body.appendChild(a);
    a.href = canvas.toDataURL();
    a.download = "canvas-image.png";
    a.click();
    document.body.removeChild(a);

);
<canvas id="canvas"  ></canvas>
<input type="file" id="file-upload" />
<button id="btnDownload">Download</button>

简而言之,如何通过保留upload from input 功能来添加upload from url 功能?

请注意,对于upload from url 功能,输入侦听器内部的内容将是相同的。所以可能我必须对imgObjimg.src 做点什么。

【问题讨论】:

【参考方案1】:

您遇到了 CORS 问题。 CORS 是一种协议,旨在防止网站从其他网站访问您的数据(跨域数据)。由于图像在网络早期就已经存在,由于向后兼容性问题,无法阻止跨域图像加载,但可能会阻止访问此类数据。

因此,当您将跨域图像绘制到画布中时,画布会被“污染”,因此您无法再用它做很多事情,包括将其内容作为数据 URL 检索。从文件系统上传的图像是安全的,因为用户必须选择加入。

所以为了使用图片数据,你必须告诉浏览器图片必须以跨域方式加载。您可以通过设置 crossOrigin 属性或属性来做到这一点:

<img src="https://static.vecteezy.com/system/resources/previews/000/094/478/original/free-abstract-pattern-vector.jpg" crossorigin>
let imgObj = new Image();
imgObj.src =
      "https://static.vecteezy.com/system/resources/previews/000/094/478/original/free-abstract-pattern-vector.jpg";
imgObj.crossOrigin = "";

使用此属性/属性,如果图像不支持 CORS,则加载将失败,甚至不会显示。但如果确实如此,就像本例一样,您将能够获取图像数据。

【讨论】:

嘿。感谢您的详细回答。在过去的半小时里,我一直在尝试这个crossOrigin 解决方案,但它似乎不起作用。我每次都会收到此错误:Access to image at 'https://static.vecteezy.com/system/resources/previews/000/094/478/original/free-abstract-pattern-vector.jpg' from origin 'http://127.0.0.1:5500' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. 嘿,我现在可以下载它,因为我使用了来自 Imgur 的图像 url。我认为他们有 CORS 支持。现在你能帮我解决事件监听器的问题吗? @Zak Huh,这很奇怪。 Access-Control-Allow-Origin 是标头服务器必须包含以支持 CORS。在这种情况下,服务器似乎根据请求来自哪个站点(和端口!)来选择接受或拒绝请求:http://localhost:8000(在我的测试中)很好,但即使http://localhost:8080 也会被阻止。呵呵。 @Zak 不,没有。但支持 CORS 是一种最佳做法,因此如果您发现某些网站不支持图片等内容,请考虑与他们联系。 @Zak 顺便说一下,还有一些 CORS 代理可以让您访问一个站点,就像它支持 CORS 一样。这不会遇到“访问您的数据”问题,因为这些代理没有您的 cookie。

以上是关于如何将图像从 url 沿侧输入类型文件加载到 html5 画布?的主要内容,如果未能解决你的问题,请参考以下文章

如何从 URL 将图像加载到 imageView? [复制]

将图像保存到数据库并从服务器加载

如何将图像从 url 加载到小部件的 android 远程视图中

如何将图像文件加载到 ImageView?

如何从从json获得的url加载图像到collectionview

将图像从 URL 加载到 ListView