在JavaScript中获取图像数据URL ?

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

我希望通过Greasemonkey和Firefox实现这一目标。

533245 次浏览

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


你需要创建一个具有正确尺寸的canvas元素,并使用drawImage函数复制图像数据。然后你可以使用toDataURL函数来获取一个data: url,其中包含base-64编码的图像。注意,图像必须是完全加载的,否则你只会得到一个空的(黑色,透明)图像。

大概是这样的。我从未编写过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,/, "");
}

在旧版本(3.5左右)的Firefox上无法获取jpeg格式的图像,因此如果您希望支持该格式,则需要检查兼容性。如果编码不支持,它将默认为“image/png”。

这个函数接受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") < / p >

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

当在画布上绘制时,传递的图像是未压缩的+所有预相乘 当导出时,它将用不同的算法解压缩或重压缩,并且不相乘 在这个过程中,所有浏览器和设备都会有不同的舍入错误 (见帆布指纹)。< / p >

因此,如果一个人想要一个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">

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

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

在HTML5中最好使用这个:

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

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

Shiv / shim / sham

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

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

.. 但是为什么呢?

这样做的好处是使用&;already loaded&;图像数据,因此不需要额外的请求。此外,它让最终用户(像你这样的程序员)决定歌珥和/或mime-typequality - or -你可以像中数规范在这里中描述的那样省略这些参数/参数。

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

例子

HTML

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

JS

console.log(document.getElementById("someImgID").toDataURL());

GPU指纹

如果你担心“准确性”;然后你可以根据@Kaiido的回答来改变这个工具来满足你的需求。

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

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

它是2022年,为什么仍然使用onload事件,使用createImageBitmap()代替。

* 注意:图像应该是同源的或者启用了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)
})();
<img id="wikiImg">

PWA可能是答案。链接在这里