用JavaScript获取图像数据?

Det*_*ael 326 javascript firefox base64 greasemonkey image

我有一个带有一些图像的常规HTML页面(只是常规的<img />HTML标签).我想得到他们的内容,优选base64编码,而不需要重新下载图像(即它已经被浏览器加载,所以现在我想要内容).

我很想用Greasemonkey和Firefox实现这一目标.

Mat*_*ley 392

注意:这仅在图像来自与页面相同的域中,或者具有crossOrigin="anonymous"属性且服务器支持CORS 时才有效.它也不会给你原始文件,而是一个重新编码的版本.如果您需要的结果与原始结果相同,请参阅Kaiido的答案.


您需要创建具有正确尺寸的canvas元素,并使用该drawImage函数复制图像数据.然后,您可以使用该toDataURL函数获取数据:具有base-64编码图像的url.请注意,图像必须完全加载,否则您只需返回空(黑色,透明)图像.

这将是这样的.我从未编写过Greasemonkey脚本,因此您可能需要调整代码以在该环境中运行.

function getBase64Image(img) {
    // Create an empty canvas element
    var canvas = document.createElement("canvas");
    canvas.width = img.width;
    canvas.height = img.height;

    // Copy the image contents to the canvas
    var ctx = canvas.getContext("2d");
    ctx.drawImage(img, 0, 0);

    // Get the data-URL formatted image
    // Firefox supports PNG and JPEG. You could check img.src to
    // guess the original format, but be aware the using "image/jpg"
    // will re-encode the image.
    var dataURL = canvas.toDataURL("image/png");

    return dataURL.replace(/^data:image\/(png|jpg);base64,/, "");
}
Run Code Online (Sandbox Code Playgroud)

获取JPEG格式的图像不适用于Firefox的旧版本(大约3.5),因此如果您想支持它,则需要检查兼容性.如果不支持编码,则默认为"image/png".

  • Firefox可能使用不同的压缩级别,这会影响编码.此外,我认为PNG支持一些额外的标题信息,如笔记,这些信息会丢失,因为画布只获取像素数据.如果你需要它完全相同,你可以使用AJAX来获取文件,base64可以手动编码. (7认同)
  • 是的,您可以使用XMLHttpRequest下载图像.希望它会使用映像的缓存版本,但这取决于服务器和浏览器配置,并且您将获得请求开销以确定文件是否已更改.这就是为什么我首先没有建议:-)不幸的是,据我所知,这是获取原始文件的唯一方法. (7认同)
  • @trusktr`rawImage`什么都不做,你最终会得到一张空白画布和结果图像. (2认同)

Mun*_*niR 73

此函数接受URL然后返回图像BASE64

function getBase64FromImageUrl(url) {
    var img = new Image();

    img.setAttribute('crossOrigin', 'anonymous');

    img.onload = function () {
        var canvas = document.createElement("canvas");
        canvas.width =this.width;
        canvas.height =this.height;

        var ctx = canvas.getContext("2d");
        ctx.drawImage(this, 0, 0);

        var dataURL = canvas.toDataURL("image/png");

        alert(dataURL.replace(/^data:image\/(png|jpg);base64,/, ""));
    };

    img.src = url;
}
Run Code Online (Sandbox Code Playgroud)

像这样称呼它: getBase64FromImageUrl("images/slbltxt.png")

  • 有没有办法将图像从外部链接转换为基础64? (8认同)
  • 好吧,它需要他们实现CORS,但是你只需要执行$ .ajax(theimageurl)它应该返回一些合理的东西.否则(如果他们没有启用CORS)它将无法工作; 互联网的安全模式不允许它.当然,除非你是一个chrome插件,在这种情况下,一切都是允许的 - 即使是上面的例子 (6认同)
  • 你必须把`img.src =`放在`img.onload =`之后,因为在某些浏览器中,比如Opera,事件不会发生. (4认同)
  • @Hakkar内存泄漏只会发生在仍使用[引用计数](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Memory_Management#Reference-counting_garbage_collection)来通知垃圾收集的旧浏览器中。据我理解,循环引用不会在[标记和扫描](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Memory_Management#Mark-and-sweep_algorithm)设置中造成泄漏。一旦退出“getBase64FromImageUrl(url)”和“img.onload = function ()”函数的作用域,img 就无法访问并被垃圾收集。除了 IE 6/7 之外,这是可以的。 (2认同)

Kai*_*ido 51

很久以后,但这里没有一个答案是完全正确的.

在画布上绘制时,传递的图像未压缩+全部预乘.
导出时,使用不同的算法对其进行未压缩或重新压缩,并且不成倍增加.

所有浏览器和设备在此过程中都会发生不同的舍入错误
(请参阅Canvas指纹识别).

因此,如果想要一个base64版本的图像文件,他们必须再次请求它(大部分时间它将来自缓存),但这次是一个Blob.

然后,您可以使用FileReader将其作为ArrayBuffer或dataURL读取.

function toDataURL(url, callback){
    var xhr = new XMLHttpRequest();
    xhr.open('get', url);
    xhr.responseType = 'blob';
    xhr.onload = function(){
      var fr = new FileReader();
    
      fr.onload = function(){
        callback(this.result);
      };
    
      fr.readAsDataURL(xhr.response); // async call
    };
    
    xhr.send();
}

toDataURL(myImage.src, function(dataURL){
  result.src = dataURL;

  // now just to show that passing to a canvas doesn't hold the same results
  var canvas = document.createElement('canvas');
  canvas.width = myImage.naturalWidth;
  canvas.height = myImage.naturalHeight;
  canvas.getContext('2d').drawImage(myImage, 0,0);

  console.log(canvas.toDataURL() === dataURL); // false - not same data
  });
Run Code Online (Sandbox Code Playgroud)
<img id="myImage" src="https://dl.dropboxusercontent.com/s/4e90e48s5vtmfbd/aaa.png" crossOrigin="anonymous">
<img id="result">
Run Code Online (Sandbox Code Playgroud)

  • 刚刚经历了 5 个以上不同的问题,您的代码是唯一一个可以正常工作的问题,谢谢:) (2认同)
  • 我用上面的代码得到这个错误。`XMLHttpRequest 无法加载数据:image/jpeg;base64,/9j/4AA ... /2Q==。无效响应。因此,不允许访问来源“https://example.com”。 (2认同)
  • @STWilson,是的,此方法也与同源策略相关联,就像画布一样。如果是跨域请求,则需要配置托管服务器以允许对脚本进行此类跨域请求。 (2认同)

Zap*_*ree 17

使用fetch的更现代版本的kaiido答案将是:

function toDataURL(url) {
  return fetch(url)
      .then((response)=> {
        return response.blob();
      })
      .then(blob=> {
        return URL.createObjectURL(blob);
      });
}
Run Code Online (Sandbox Code Playgroud)

https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch

  • 如果您有长时间运行的应用程序使用此方法,请不要忘记调用 `URL.revokeObjectURL()`,否则您的内存会变得混乱。 (2认同)
  • 注意:DataURL(base64 编码)与 ObjectURL(引用 blob)不同 (2认同)
  • ObjectURL 当然不是数据 URL。这不是正确的答案。 (2认同)

arg*_*gon 9

刀 / 垫片 / 假手术

如果您的图像已经加载(或未加载),这个“工具”可能会派上用场:

Object.defineProperty
(
    HTMLImageElement.prototype,'toDataURL',
    {enumerable:false,configurable:false,writable:false,value:function(m,q)
    {
        let c=document.createElement('canvas');
        c.width=this.naturalWidth; c.height=this.naturalHeight;
        c.getContext('2d').drawImage(this,0,0); return c.toDataURL(m,q);
    }}
);
Run Code Online (Sandbox Code Playgroud)

.. 但为什么?

这样做的优点是使用“已加载”的图像数据,因此不需要额外的请求。此外,它还允许最终用户(像您这样的程序员)决定CORS和/或-mime-type或者quality- 您可以省略这些参数/参数,如MDN规范所述。

如果你加载了这个 JS(在需要它之前),那么转换为dataURL就像这样简单:

例子

HTML

<img src="/yo.jpg" onload="console.log(this.toDataURL('image/jpeg'))">
Run Code Online (Sandbox Code Playgroud)

JS

console.log(document.getElementById("someImgID").toDataURL());
Run Code Online (Sandbox Code Playgroud)

GPU 指纹识别

如果您担心这些位的“精确性”,那么您可以更改此工具以满足您的需求,如 @Kaiido 的答案所提供。


uin*_*tea 7

现在是 2022 年,我更喜欢使用现代createImageBitmap()而不是onload事件。

*注意:图像应同源或启用 CORS

async function imageToDataURL(imageUrl) {
  let img = await fetch(imageUrl);
  img = await img.blob();
  let bitmap = await createImageBitmap(img);
  let canvas = document.createElement("canvas");
  let ctx = canvas.getContext("2d");
  canvas.width = bitmap.width;
  canvas.height = bitmap.height;
  ctx.drawImage(bitmap, 0, 0, bitmap.width, bitmap.height);
  return canvas.toDataURL("image/png");
  // image compression? 
  // return canvas.toDataURL("image/png", 0.9);
};

(async() => {
  let dataUrl = await imageToDataURL('https://en.wikipedia.org/static/images/project-logos/enwiki.png')
  wikiImg.src = dataUrl;
  console.log(dataUrl)
})();
Run Code Online (Sandbox Code Playgroud)
<img id="wikiImg">
Run Code Online (Sandbox Code Playgroud)