使用来自ajax请求的原始图像数据作为数据URI

时间:2022-08-17 08:58:30

I'm trying to use a combination of Ajax and data URIs to load a JPEG image and extract its EXIF data with a single HTTP request. I am modifying a library (https://github.com/kennydude/photosphere) to do this; currently this library uses two HTTP requests to set the source of the image and to get the EXIF data.

我尝试使用Ajax和数据uri的组合来加载JPEG图像,并使用单个HTTP请求提取其EXIF数据。我正在修改一个库(https://github.com/kennydude/photosphere)来实现这一点;目前,这个库使用两个HTTP请求来设置映像的源并获取EXIF数据。

Getting the EXIF works, no problem. However I am having difficulty using the raw data from the ajax request as source for the image.

让EXIF起作用,没问题。但是,我很难将来自ajax请求的原始数据作为映像的源。

Source code for a small test of the technique:

小测试技术的源代码:

<!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>

I get what looks like sensible jpeg data sent back, and the length (in bytes) of the raw data and the base64-encoded-then-unencoded-again raw data is the same. However the attempt to set the image src fails on both Firefox (25) and Chrome (31) (current versions) - chrome displays "broken image" icon suggesting the src is an invalid format.

我得到了看起来像发送回来的合理的jpeg数据,原始数据和base64-encoded-then-unencoded-同样是原始数据的长度(以字节为单位)是相同的。然而,在Firefox(25)和Chrome(31)(当前版本)中,设置图像src的尝试失败了——Chrome显示了“损坏的图像”图标,表明src是无效的格式。

I used this mozilla page for info on base64 encoding/decoding:

我使用这个mozilla页面来获取关于base64编码/解码的信息:

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Base64_encoding_and_decoding

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Base64_encoding_and_decoding

Any idea what might be wrong? Looking around I can create the base64 encoded image server side but can it be done client side like this? For one thing, base64 encoding server side obviously increases the data size and the whole purpose of this exercise is to cut down the amount of data being transferred from the server, as well as the number of requests.

你知道什么地方不对劲吗?环顾四周,我可以创建base64编码的图像服务器端,但它可以像这样在客户端完成吗?首先,base64编码服务器端明显增加了数据大小,本练习的目的是减少从服务器传输的数据量,以及请求的数量。

Thanks, Nick

谢谢你,尼克

5 个解决方案

#1


32  

Thanks for that. I've done a bit more digging on this and it turns out there is a solution at least on current versions of Firefox and Chrome (EDIT: IE10 works too). You can use XMLHttpRequest2 and use a typed array (Uint8Array). The following code works:

谢谢你,。我对此做了更多的研究,发现至少在当前版本的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>

Basically you ask for a binary response, then create an 8-bit unsigned int view of the data before converting it back into a (binary-friendly) string String.fromCharCode(). The apply is necessary as String.fromCharCode() does not accept an array argument. You then use btoa(), create your data url and it then works.

基本上,您需要一个二进制响应,然后创建数据的8位无符号int视图,然后将其转换为(二进制友好的)字符串string . fromcharcode()。应用程序是必要的,因为String.fromCharCode()不接受数组参数。然后使用btoa()创建数据url,然后它就可以工作了。

The following resources were useful for this:

以下资源在这方面是有用的:

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Typed_arrays?redirectlocale=en-US&redirectslug=JavaScript%2FTyped_arrays

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Typed_arrays?redirectlocale=en-US&redirectslug=JavaScript%2FTyped_arrays

and

http://www.html5rocks.com/en/tutorials/file/xhr2/

http://www.html5rocks.com/en/tutorials/file/xhr2/

Nick

尼克

#2


16  

Nick's answer works very well. But when I did this with a fairly large file, I got a stack overflow on

尼克的回答很有效。但是当我用一个相当大的文件做这个时,我得到了一个堆栈溢出

var raw = String.fromCharCode.apply(null,arr);

Generating the raw string in chunks worked well for me.

以块的形式生成原始字符串对我来说很有用。

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

#3


14  

I had trouble with the ArrayBuffer -> String -> Base64 method described above, but ran across another method using Blob that worked great. It's not a way to convert raw data to Base 64 (as in the title), but it is a way to display raw image data (as in the actual question):

我在上面描述的ArrayBuffer ->字符串-> 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();

All credit goes to Jan Miksovsky, author of this fiddle. I just stumbled across it and thought it'd make a useful addition to this discussion.

这一切都归功于《小提琴》的作者Jan Miksovsky。我只是偶然发现了它,并认为它对这次讨论有帮助。

#4


0  

You will have to do base64 encoding on the server side as the responseText is treated as a String, and the response data that the server is sending is binary.

您将不得不在服务器端进行base64编码,因为responseText作为字符串处理,而服务器发送的响应数据是二进制的。

#5


0  

I've been working for two days on this issue since I needed a solution to render the User's Outlook Profile Picture from the raw data received from Microsoft Graft. I have implemented all the solutions above, with no success. Then I found this git: get base64 raw data of image from responseBody using jquery ajax

我已经在这个问题上工作了两天,因为我需要一个解决方案来从Microsoft Graft中获得的原始数据中呈现用户的Outlook配置文件图片。我已经实现了上面所有的解决方案,但没有成功。然后我找到了这个git:使用jquery ajax从responseBody获取base64原始图像数据

In my case, I just replaced "data:image/png;base64," with "data:image/jpg;base64,"

在我的例子中,我将“data:image/png;base64”替换为“data:image/jpg;base64,”

It works like a charm.

它就像一种魅力。

#1


32  

Thanks for that. I've done a bit more digging on this and it turns out there is a solution at least on current versions of Firefox and Chrome (EDIT: IE10 works too). You can use XMLHttpRequest2 and use a typed array (Uint8Array). The following code works:

谢谢你,。我对此做了更多的研究,发现至少在当前版本的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>

Basically you ask for a binary response, then create an 8-bit unsigned int view of the data before converting it back into a (binary-friendly) string String.fromCharCode(). The apply is necessary as String.fromCharCode() does not accept an array argument. You then use btoa(), create your data url and it then works.

基本上,您需要一个二进制响应,然后创建数据的8位无符号int视图,然后将其转换为(二进制友好的)字符串string . fromcharcode()。应用程序是必要的,因为String.fromCharCode()不接受数组参数。然后使用btoa()创建数据url,然后它就可以工作了。

The following resources were useful for this:

以下资源在这方面是有用的:

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Typed_arrays?redirectlocale=en-US&redirectslug=JavaScript%2FTyped_arrays

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Typed_arrays?redirectlocale=en-US&redirectslug=JavaScript%2FTyped_arrays

and

http://www.html5rocks.com/en/tutorials/file/xhr2/

http://www.html5rocks.com/en/tutorials/file/xhr2/

Nick

尼克

#2


16  

Nick's answer works very well. But when I did this with a fairly large file, I got a stack overflow on

尼克的回答很有效。但是当我用一个相当大的文件做这个时,我得到了一个堆栈溢出

var raw = String.fromCharCode.apply(null,arr);

Generating the raw string in chunks worked well for me.

以块的形式生成原始字符串对我来说很有用。

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

#3


14  

I had trouble with the ArrayBuffer -> String -> Base64 method described above, but ran across another method using Blob that worked great. It's not a way to convert raw data to Base 64 (as in the title), but it is a way to display raw image data (as in the actual question):

我在上面描述的ArrayBuffer ->字符串-> 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();

All credit goes to Jan Miksovsky, author of this fiddle. I just stumbled across it and thought it'd make a useful addition to this discussion.

这一切都归功于《小提琴》的作者Jan Miksovsky。我只是偶然发现了它,并认为它对这次讨论有帮助。

#4


0  

You will have to do base64 encoding on the server side as the responseText is treated as a String, and the response data that the server is sending is binary.

您将不得不在服务器端进行base64编码,因为responseText作为字符串处理,而服务器发送的响应数据是二进制的。

#5


0  

I've been working for two days on this issue since I needed a solution to render the User's Outlook Profile Picture from the raw data received from Microsoft Graft. I have implemented all the solutions above, with no success. Then I found this git: get base64 raw data of image from responseBody using jquery ajax

我已经在这个问题上工作了两天,因为我需要一个解决方案来从Microsoft Graft中获得的原始数据中呈现用户的Outlook配置文件图片。我已经实现了上面所有的解决方案,但没有成功。然后我找到了这个git:使用jquery ajax从responseBody获取base64原始图像数据

In my case, I just replaced "data:image/png;base64," with "data:image/jpg;base64,"

在我的例子中,我将“data:image/png;base64”替换为“data:image/jpg;base64,”

It works like a charm.

它就像一种魅力。