获取JavaScript中的图片数据网址?


335

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

我很乐意使用Greasemonkey和Firefox实现这一目标。

Answers:


400

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


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

获取JPEG格式的图像在Firefox的较旧版本(约3.5版)上不起作用,因此,如果要支持该功能,则需要检查兼容性。如果不支持编码,则默认为“ image / png”。


1
尽管这似乎可行(除了未转义的/除外),但在使用file_get_contents函数获取的文件上执行base64_encode时,它不会创建与我从PHP获得的base64字符串相同的字符串。图像看起来非常相似/相同,但仍然使用Javascript绘制的图像较小,我希望它们完全相同。还有一件事:输入图像是一小幅(594字节),28x30 PNG,透明背景-如果可以更改任何内容。
Detariael

7
Firefox可能会使用不同的压缩级别,这会影响编码。另外,我认为PNG支持一些额外的标头信息(如注释),因为画布仅获取像素数据,因此这些信息会丢失。如果需要完全相同,则可以使用AJAX来获取文件并进行base64手动编码。
马修·克鲁姆利2009年

7
是的,您将使用XMLHttpRequest下载该图像。希望它会使用映像的缓存版本,但这将取决于服务器和浏览器的配置,并且您将具有请求开销来确定文件是否已更改。这就是为什么我最初不建议这样做的原因:-)不幸的是,据我所知,这是获取原始文件的唯一方法。
马修·

2
@trusktr drawImage不会执行任何操作,最终将得到空白画布和生成的图像。
马修·克鲁姆利

1
@JohnSewell那仅仅是因为OP需要内容,而不是URL。如果要将其用作图像源,则需要跳过replace(...)调用。
马修·克鲁姆利

76

该函数获取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")


8
有没有办法将图像从外部链接转换为base 64?
dinodsaurus

@dinodsaurus可以将其加载到图像标签中,或者进行ajax查询。
杰里德·福赛斯

6
好吧,它要求他们实现CORS,但是您只需执行$ .ajax(theimageurl),它应该返回合理的值。否则(如果他们未启用CORS)将无法正常工作;互联网的安全模型不允许这样做。当然,除非你使用的是Chrome插件内,在这种情况下,一切被允许-甚至上面的例子
贾里德福塞斯

4
您必须放在img.src =之后img.onload =,因为在某些浏览器(例如Opera)中,该事件不会发生。
ostapische 2013年

1
@Hakkar只有在使用静态引用计数来通知垃圾收集的旧浏览器中才会发生内存泄漏。据我所知,圆形基准不会在标记和扫描设置中造成泄漏。一旦功能的范围getBase64FromImageUrl(url),并img.onload = function ()在退出IMG无法访问,垃圾收集。除了IE 6/7以外,都可以。
humanityANDpeace

59

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

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

在此过程中,所有浏览器和设备都会发生不同的舍入错误
(请参阅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">


刚刚经历了5个以上的不同问题,您的代码是唯一可以正常工作的代码,谢谢:)
Peter

1
我在上面的代码中收到此错误。 XMLHttpRequest cannot load data:image/jpeg;base64,/9j/4AA ... /2Q==. Invalid response. Origin 'https://example.com' is therefore not allowed access.
STWilson '17

2
@STWilson,是的,此方法也与同源策略相关联,就像画布一样。如果是跨域请求,则需要配置托管服务器以允许对脚本的此类跨域请求。
海伊多

@Kaiido,因此,如果映像位于脚本之外的其他服务器上,则托管服务器必须启用跨源请求?如果设置img.setAttribute('crossOrigin','anonymous')是否可以防止错误?
1.21吉瓦,

1
经过更多研究,图像可以使用crossOrigin属性来请求访问,但是要由托管服务器通过CORS标头sitepoint.com/an-in-depth-look-at-cors进行访问。至于XMLHttpRequest,看起来服务器必须通过CORS标头提供与图像相同的访问权限,但是您的代码不需要更改,除非可以将xhr.withCredentials设置为false(默认值)。
1.21吉瓦

20

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

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

https://developer.mozilla.org/zh-CN/docs/Web/API/Fetch_API/Using_Fetch

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

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


2
URL.revokeObjectURL()如果您使用此方法的应用程序运行时间较长,请不要忘记调用它,否则您的内存将变得混乱。
工程师

1
注意:DataURL(编码为base64)与ObjectURL(对blob的引用)不同
DaniEll

1
ObjectURL当然不是数据URL。这不是正确答案。
Danny Lin

2

湿/伪/假

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

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的回答提供的方法更改此工具以适合您的需求。


1

onload加载后使用事件转换图像


-3

在HTML5中,最好使用以下命令:

{
//...
canvas.width = img.naturalWidth; //img.width;
canvas.height = img.naturalHeight; //img.height;
//...
}

2
在回答问题时,请尝试更加具体并提供详细说明。
Piyush Zalani
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.