首页 > 解决方案 > Javascript将图像转换为文件返回零

问题描述

我有来自其他服务器的 img

<img src="https://cloudserver/1.jpg">

单击此 img 时,我想转换为 File 对象以将发布请求发送到服务器。在这个函数之后,我看到数据所有字节 = 0,不明白发生了什么?在搜索中,我发现需要等待然后图像加载完成但我 100% 已经加载图像的问题。

imgToFile: function (imageElement){
    imageElement.crossOrigin="anonymous";

    var canvasElement = document.createElement("canvas");
    canvasElement.width = imageElement.width;
    canvasElement.height = imageElement.height;
    var canvasContext = canvasElement.getContext("2d");
    canvasContext.drawImage(imageElement, 0, 0);

    var imageData = canvasContext.getImageData(0, 0, imageElement.width, imageElement.height).data;
    var buffer = new Uint8Array(imageData.length);
    for(var index = 0; index < imageData.length; index++)
        buffer[index] = imageData[index];

    var imageBlob = new Blob(buffer);
    return new File([imageBlob], /\/([^/]+)$/.exec(imageElement.src)[1]);
}

沙盒: https ://liveweave.com/DCXuNY

标签: javascriptcanvashtml5-canvasblobfileapi

解决方案


这让我很惊讶,以为我知道这部分规范,但事实证明,自 2016 年以来,更改crossorigin属性状态是 img相关突变的一部分,这将强制重新获取图像源

Chrome最近才赶上了规格(M84),Firefox 仍然没有,因此只会抛出一个错误,抱怨图像确实污染了画布。

另一方面,Chrome 会在您更改crossOriginIDL 属性后立即重新获取图像,这次使用正确的 CORS 标头。因此,当您drawImage在该浏览器中点击时,它仍然不会获取符合 CORS 的资源(即使它是同一个文件,因为它具有不同的标头,浏览器将再次完全获取它)。

因此,与您的想法相反,您的图像仍未加载到 Chrome 中。

要解决这个问题,您可以onload在 js 脚本中添加一个事件处理程序,但您还需要通过再次设置src属性(甚至设置相同的值)来强制为其他浏览器重新获取图像:

onload = (evt) => {
  const img = document.querySelector( 'img' );
  img.onload = (evt) => {
    const canvas = document.createElement('canvas');
    const ctx = canvas.getContext('2d');
    ctx.drawImage(img,0,0);
    console.log(...ctx.getImageData(250,120,1,1).data);
  };
  img.crossOrigin = 'anonymous';
  img.src = img.src; // force refetching for non-Chrome browsers
};
img { width: 300px }
<img src="https://upload.wikimedia.org/wikipedia/commons/4/47/PNG_transparency_demonstration_1.png">

但最好的方法当然是从一开始就直接使用正确的 CORS 标头请求您的图像,这样您就不会让您的用户白白下载两次相同的文件。

onload = (evt) => {
  const img = document.querySelector( 'img' );
  const canvas = document.createElement('canvas');
  const ctx = canvas.getContext('2d');
  ctx.drawImage(img,0,0);
  console.log(...ctx.getImageData(250,120,1,1).data);
};
img { width: 300px }
<img src="https://upload.wikimedia.org/wikipedia/commons/4/47/PNG_transparency_demonstration_1.png" crossorigin="anonymous">


推荐阅读