358

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

我很想用 Greasemonkey 和 Firefox 来实现。

4

8 回答 8

418

Note: This only works if the image is from the same domain as the page, or has the crossOrigin="anonymous" attribute and the server supports CORS. It's also not going to give you the original file, but a re-encoded version. If you need the result to be identical to the original, see Kaiido's answer.


You will need to create a canvas element with the correct dimensions and copy the image data with the drawImage function. Then you can use the toDataURL function to get a data: url that has the base-64 encoded image. Note that the image must be fully loaded, or you'll just get back an empty (black, transparent) image.

It would be something like this. I've never written a Greasemonkey script, so you might need to adjust the code to run in that environment.

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,/, "");
}

Getting a JPEG-formatted image doesn't work on older versions (around 3.5) of Firefox, so if you want to support that, you'll need to check the compatibility. If the encoding is not supported, it will default to "image/png".

于 2009-06-01T13:55:36.980 回答
83

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

于 2013-05-15T13:21:47.453 回答
73

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

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

在此过程中,所有浏览器和设备都会发生不同的舍入错误
(请参阅画布指纹)。

因此,如果想要一个图像文件的 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">

于 2017-03-21T01:16:09.560 回答
25

使用 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

于 2017-07-21T21:36:06.540 回答
5

shiv / 垫片 / 假

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

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

.. 但为什么?

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

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

例子

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

GPU 指纹识别

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

于 2019-11-01T01:23:58.913 回答
1

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

function loaded(img) {
  let c = document.createElement('canvas')
  c.getContext('2d').drawImage(img, 0, 0)
  msg.innerText= c.toDataURL();
}
pre { word-wrap: break-word; width: 500px; white-space: pre-wrap; }
<img onload="loaded(this)" src="https://cors-anywhere.herokuapp.com/http://lorempixel.com/200/140" crossorigin="anonymous"/>

<pre id="msg"></pre>

于 2019-04-24T08:03:38.567 回答
0

这就是您需要阅读的全部内容。

https://developer.mozilla.org/en-US/docs/Web/API/FileReader/readAsBinaryString

var height = 200;
var width  = 200;

canvas.width  = width;
canvas.height = height;

var ctx = canvas.getContext('2d');

ctx.strokeStyle = '#090';
ctx.beginPath();
ctx.arc(width/2, height/2, width/2 - width/10, 0, Math.PI*2);
ctx.stroke();

canvas.toBlob(function (blob) {
  //consider blob is your file object

  var reader = new FileReader();

  reader.onload = function () {
    console.log(reader.result);
  }

  reader.readAsBinaryString(blob);
});
于 2020-07-16T18:01:34.443 回答
-1

在 HTML5 中更好地使用这个:

{
//...
canvas.width = img.naturalWidth; //img.width;
canvas.height = img.naturalHeight; //img.height;
//...
}
于 2019-01-12T10:18:20.610 回答