在 JavaScript 中获取图像数据 URL?

IT技术 javascript image firefox greasemonkey base64
2021-02-02 22:35:09

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

我很想用 Greasemonkey 和 Firefox 来实现这一点。

6个回答

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


您将需要创建一个具有正确尺寸的画布元素并使用该drawImage函数复制图像数据然后您可以使用该toDataURL函数来获取具有 base-64 编码图像的 data: 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,/, "");
}

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

@trusktrdrawImage什么都不做,你最终会得到一个空白的画布和结果图像。
2021-03-13 22:35:09
Firefox 可能使用了不同的压缩级别,这会影响编码。另外,我认为 PNG 支持一些额外的标题信息,如注释,这些信息会丢失,因为画布只获取像素数据。如果您需要它完全相同,您可以使用 AJAX 来获取文件并手动对其进行 base64 编码。
2021-03-14 22:35:09
是的,您将使用 XMLHttpRequest 下载图像。希望它会使用图像的缓存版本,但这取决于服务器和浏览器配置,并且您将有请求开销来确定文件是否已更改。这就是为什么我一开始不建议这样做的原因:-) 不幸的是,据我所知,这是获取原始文件的唯一方法。
2021-03-16 22:35:09
@JohnSewell 那只是因为 OP 想要内容,而不是 URL。如果要将其用作图像源,则需要跳过 replace(...) 调用。
2021-03-17 22:35:09
虽然这似乎有效(除了未转义的 / 在返回中),但它不会创建与我在使用 file_get_contents 函数获得的文件上执行 base64_encode 时从 PHP 获得的相同的 base64 字符串。图像看起来非常相似/相同,但 Javascripted 的图像仍然较小,我希望它们完全相同。还有一件事:输入图像是一个小的(594 字节)28x30 PNG,带有透明背景——如果这有什么改变的话。
2021-04-03 22:35:09

此函数获取 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;
}

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

有没有办法将图像从外部链接转换为 base 64?
2021-03-18 22:35:09
@Hakkar 内存泄漏只会发生在使用静止引用计数来通知垃圾收集的旧浏览器中据我了解,循环引用不会在标记和扫描设置中造成泄漏一旦退出 imggetBase64FromImageUrl(url)的函数范围,img.onload = function ()就无法访问并进行垃圾收集。除了 IE 6/7,这还可以。
2021-03-20 22:35:09
必须放在img.src =之后img.onload =,因为在某些浏览器中,例如 Opera 中,该事件不会发生。
2021-03-29 22:35:09
@dinodsaurus 您可以将其加载到图像标签中,或执行 ajax 查询。
2021-03-31 22:35:09
好吧,它要求他们实现 CORS,但是你只需执行 $.ajax(theimageurl) 并且它应该返回一些合理的东西。否则(如果他们没有启用 CORS)它将无法工作;互联网的安全模型不允许这样做。当然,除非您在 chrome 插件中,在这种情况下,一切都是允许的 - 即使是上面的例子
2021-04-01 22:35:09

很久以后,但这里的答案都不是完全正确的。

在画布上绘制时,传递的图像是未压缩的 + 全部预乘。
导出时,其未压缩或使用不同的算法重新压缩,并且未相乘。

所有浏览器和设备在此过程中都会发生不同的舍入错误
(请参阅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
  });
<img id="myImage" src="https://dl.dropboxusercontent.com/s/4e90e48s5vtmfbd/aaa.png" crossOrigin="anonymous">
<img id="result">

经过更多研究,看起来图像可以使用 crossOrigin 属性来请求访问,但托管服务器可以通过 CORS 标头sitepoint.com/an-in-depth-look-at-cors提供访问权限至于 XMLHttpRequest 的,看起来服务器必须通过 CORS 标头提供与图像相同的访问权限,但不需要更改您的代码,除非将 xhr.withCredentials 设置为 false(默认值)。
2021-03-11 22:35:09
刚刚经历了 5 个以上不同的问题,您的代码是唯一一个可以正常工作的问题,谢谢:)
2021-03-17 22:35:09
我用上面的代码收到这个错误。 XMLHttpRequest cannot load data:image/jpeg;base64,/9j/4AA ... /2Q==. Invalid response. Origin 'https://example.com' is therefore not allowed access.
2021-03-18 22:35:09
@STWilson,是的,这种方法也与同源策略相关,就像画布一样。在跨域请求的情况下,您需要配置托管服务器以允许此类跨域请求发送到您的脚本。
2021-03-20 22:35:09
@Kaiido 所以如果图像在另一个服务器上而不是托管服务器必须启用跨源请求的脚本?如果您设置 img.setAttribute('crossOrigin', 'anonymous') 是否可以防止错误?
2021-04-08 22:35:09

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

function toObjectUrl(url) {
  return fetch(url)
      .then((response)=> {
        return response.blob();
      })
      .then(blob=> {
        return URL.createObjectURL(blob);
      });
}

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

编辑:正如评论中指出的那样,这将返回一个指向本地系统中文件的对象 url,而不是实际的 DataURL,因此根据您的用例,这可能不是您需要的。

您可以查看以下答案以使用 fetch 和实际的 dataURL:https ://stackoverflow.com/a/50463054/599602

注意:DataURL(base64 编码)与 ObjectURL(引用 blob)不一样
2021-03-09 22:35:09
URL.revokeObjectURL()如果您有长时间运行的应用程序使用此方法,请不要忘记调用,否则您的内存会变得混乱。
2021-04-06 22:35:09
ObjectURL 肯定不是数据 URL。这不是一个正确的答案。
2021-04-07 22:35:09

shiv / shim / 假

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

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);
    }}
);

.. 但为什么?

这具有使用“已加载”图像数据的优点,因此不需要额外的请求。的方法,另外它可以让最终用户(程序员喜欢你)决定CORS和/或mime-typequality-或-您可以将这些参数/中所描述的参数MDN规范在这里

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

例子

HTML
<img src="/yo.jpg" onload="console.log(this.toDataURL('image/jpeg'))">
JS
console.log(document.getElementById("someImgID").toDataURL());

GPU指纹识别

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

很棒的方法!说得好。
2021-03-14 22:35:09
凉爽的!!!太有用了。这应该被投票给最高。
2021-03-21 22:35:09