我正在尝试使用Ajax和数据URI的组合来加载JPEG图像并使用单个HTTP请求提取其EXIF数据。我正在修改一个库(https://github.com/kennydude/photosphere)来做这件事;目前,该库使用两个HTTP请求来设置图像源并获取EXIF数据。
让EXIF正常工作,没问题。但是,我很难将ajax请求中的原始数据用作图像的源。
该技术的小测试的源代码:
<!DOCTYPE html>
<html>
<head>
<script type='text/javascript'>
function init()
{
// own ajax library - using it to request a test jpg image
new Ajax().sendRequest
(
"/images/photos/badger.jpg",
{ method : "GET",
callback: function(xmlHTTP)
{
var encoded = btoa (unescape(encodeURIComponent(xmlHTTP.responseText)));
var dataURL="data:image/jpeg;base64,"+encoded;
document.getElementById("image").src = dataURL;
}
}
);
}
</script>
<script type="text/javascript" src="http://www.free-map.org.uk/0.6/js/lib/Ajax.js"></script>
</head>
<body onload='init()'>
<img id="image" alt="data url loaded image" />
</body>
</html>
我得到了发回的合理jpeg数据,原始数据的长度(以字节为单位)和base64编码然后未编码的原始数据是相同的。但是,在Firefox(25)和Chrome(31)(当前版本)上设置图像src的尝试失败 - chrome显示“损坏的图像”图标,表明src是无效格式。
我使用这个mozilla页面获取有关base64编码/解码的信息:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Base64_encoding_and_decoding
知道可能出错的是什么?环顾四周,我可以创建base64编码的图像服务器端,但它可以像这样在客户端完成吗?首先,base64编码服务器端显然增加了数据大小,本练习的目的是减少从服务器传输的数据量以及请求数量。
谢谢, 尼克
答案 0 :(得分:32)
谢谢你。我已经对此进行了更多的挖掘,结果发现至少在当前版本的Firefox和Chrome上有一个解决方案(编辑:IE10也可以)。您可以使用XMLHttpRequest2并使用类型化数组(Uint8Array)。以下代码有效:
<!DOCTYPE html>
<html>
<head>
<script type='text/javascript'>
function init()
{
var xmlHTTP = new XMLHttpRequest();
xmlHTTP.open('GET','/images/photos/badger.jpg',true);
// Must include this line - specifies the response type we want
xmlHTTP.responseType = 'arraybuffer';
xmlHTTP.onload = function(e)
{
var arr = new Uint8Array(this.response);
// Convert the int array to a binary string
// We have to use apply() as we are converting an *array*
// and String.fromCharCode() takes one or more single values, not
// an array.
var raw = String.fromCharCode.apply(null,arr);
// This works!!!
var b64=btoa(raw);
var dataURL="data:image/jpeg;base64,"+b64;
document.getElementById("image").src = dataURL;
};
xmlHTTP.send();
}
</script>
</head>
<body onload='init()'>
<img id="image" alt="data url loaded image" />
</body>
</html>
基本上你要求二进制响应,然后在将数据转换回(二进制友好的)字符串String.fromCharCode()之前创建数据的8位无符号int视图。 apply是必要的,因为String.fromCharCode()不接受数组参数。然后使用btoa()创建数据网址然后就可以了。
以下资源对此非常有用:
和
http://www.html5rocks.com/en/tutorials/file/xhr2/
尼克
答案 1 :(得分:16)
尼克的答案非常有效。但是当我使用相当大的文件执行此操作时,我在
上出现了堆栈溢出var raw = String.fromCharCode.apply(null,arr);
以块的形式生成原始字符串对我来说很有效。
var raw = '';
var i,j,subArray,chunk = 5000;
for (i=0,j=arr.length; i<j; i+=chunk) {
subArray = arr.subarray(i,i+chunk);
raw += String.fromCharCode.apply(null, subArray);
}
答案 2 :(得分:15)
我遇到了上述ArrayBuffer -> String -> Base64
方法的问题,但使用了Blob的另一种方法运行得很好。它是不将原始数据转换为Base 64的方式(如标题中所示),但它是显示原始图像数据的方式(如实际问题中所示):
var xhr = new XMLHttpRequest();
xhr.responseType = 'arraybuffer';
xhr.onload = function() {
var blb = new Blob([xhr.response], {type: 'image/png'});
var url = (window.URL || window.webkitURL).createObjectURL(blb);
image.src = url;
}
xhr.open('GET', 'http://whatever.com/wherever');
xhr.send();
归功于this fiddle的作者Jan Miksovsky。我偶然发现了它,并认为这对这次讨论有用。
答案 3 :(得分:0)
您必须在服务器端执行base64编码,因为responseText被视为String,服务器发送的响应数据是二进制的。
答案 4 :(得分:0)
我已经在这个问题上工作了两天,因为我需要一个解决方案来从Microsoft Graft收到的原始数据中呈现用户的Outlook配置文件图片。我已经实施了上述所有解决方案,但没有成功。然后我发现了这个git: get base64 raw data of image from responseBody using jquery ajax
就我而言,我刚刚将"data:image/png;base64,"
替换为"data:image/jpg;base64,"
它就像一个魅力。
答案 5 :(得分:0)
用于图像下载的现代ES6驱动解决方案: (未指定图像类型)
async function downloadImageFromUrl(url) { // returns dataURL
const xmlHTTP = new XMLHttpRequest();
xmlHTTP.open('GET', url, true);
xmlHTTP.responseType = 'blob';
const imageBlob = await new Promise((resolve, reject) => {
xmlHTTP.onload = e => xmlHTTP.status >= 200 && xmlHTTP.status < 300 && xmlHTTP.response.type.startsWith('image/') ? resolve(xmlHTTP.response) : reject(Error(`wrong status or type: ${xmlHTTP.status}/${xmlHTTP.response.type}`));
xmlHTTP.onerror = reject;
xmlHTTP.send();
});
return blobToDataUrl(imageBlob);
}
function blobToDataUrl(blob) { return new Promise(resolve => {
const reader = new FileReader(); // https://developer.mozilla.org/en-US/docs/Using_files_from_web_applications
reader.onload = e => resolve(e.target.result);
reader.readAsDataURL(blob);
})}
用法:
downloadImageFromUrl('https://a.b/img.png').then(console.log, console.error)