【问题标题】:How can I convert image binary from API call to data URI in Javascript?如何将图像二进制从 API 调用转换为 Javascript 中的数据 URI?
【发布时间】:2012-01-13 17:58:05
【问题描述】:

我使用的 Google API 仅将图像作为二进制数据传输。

我完全不知道如何将其放入数据 URI 中以显示它,感谢您的帮助!

我说的电话是this API call

如你所见,上面写着:

服务器返回照片的字节数。

对于调用(它是一个扩展),我使用 chrome_ex_oauth 方法。也许我需要在标题中添加一些东西来获取真正的二进制数据,而不是现在出现的字符串......

我需要做的是将生成的二进制文件转换为数据 URI,以便我可以显示它。


好的,我从 XHR 请求中得到了这个

现在,我不太了解二进制的东西。这是我假设的某种编码二进制数据?我试图将它放入 btoa 和其他 base64 编码器中,一切都会引发错误。 我试图用不同的东西覆盖MimeType,并且“响应”以一些奇怪的方式发生了变化,但没有任何东西接受数据。

所以现在我有了这个代码:

var nxhr = new XMLHttpRequest();
nxhr.onreadystatechange = function (data) {
    if (nxhr.readyState == 4) {
        console.log(nxhr);
    }
};
nxhr.open(method, url, true);
nxhr.setRequestHeader('GData-Version', '3.0');
nxhr.setRequestHeader('Authorization', oauth.getAuthorizationHeader(url, method, params));
nxhr.send('Data to send');

任何人都知道如何将这个对我来说无法理解的响应转换为数据 uri???

感谢您的帮助

【问题讨论】:

  • 二进制...数千 [of] 丑陋的字符...您知道二进制只有两个值,对吗?
  • 文件阅读器?这听起来像java,而不是javascript。显示SSCCE 怎么样?否则,我真的不知道你在问什么。
  • @Joseph,也许他真的很讨厌 1 和 0 的样子。
  • html5 HAS FileReader ;-) 是的 Joseph,我知道 :) 但是将二进制数据放入字符串中,您会看到两个以上的值,对吧?
  • 当您将二进制放入字符串时,它只显示从一系列 1 字节字符值中获取的字符。如果您在某处存储一个 4 字节整数并尝试通过 4 * 1 字节的数组读取它,您将获得 4 个不同的字符。字符串表示无关紧要,位序列是。

标签: javascript google-api data-uri


【解决方案1】:

在进行了一些测试后,这是我的答案:

要使用<img> 标记简单地显示图像,您必须首先使用 Base64 对结果二进制文件进行编码。您可以通过两种不同的方式做到这一点:

  1. 使用 Javascript: 使用 Base64 编码器函数 such as this one。对结果二进制数据进行编码后,您可以使用<img> 标签显示图像,如下所示:<img src="data:image/*;base64,[BASE64 ENCODED BINARY]" />。您必须将[BASE64 ENCODED BINARY] 替换为图像的实际编码二进制文件。我假设您已经知道如何通过 Javascript 更改 HTML 元素属性,将编码后的二进制文件放入 <img> 标记的 src 属性相当容易。

  2. 使用 PHP(我的个人偏好):一旦您向 API 提交 GET 请求,它就会返回二进制文件。只需使用 PHP base64_encode() 函数即可。

    <img src="data:image/*;base64,<?php echo base64_encode($result); ?>" />

$result 变量是您从 API 调用中获得的。您可以使用PHP cURL 库。

我希望这会有所帮助。

【讨论】:

  • 谢谢,虽然我已经尝试过一个 Base64 编码器(它告诉我一个错误“只能处理 ascii 代码”)我会试试你的。正如我所说,它是一个扩展(用于 chrome),我只能通过 JS 访问。此外,我必须依赖这个 chrome_ex_oauth,它使 Ajax 调用了我。虽然我要尝试您的解决方案,但我想请您查看 oauth,也许有一些东西使返回的数据无法满足我的需要。 code.google.com/chrome/extensions/tut_oauth.html
  • 图片处理的回调函数添加了吗?在“发送签名的 API 请求”下,该示例使用带有回调函数的 GET。此函数的输出参数“resp”是响应数据。在您的情况下,这是二进制数据。由于您只是为 Chrome 开发,因此使用 btoa() 函数将此二进制文件转换为 Base64 并将其添加到 data:image/*;base64,[BASE64 BINARY] 的末尾,将其用作图像的 URI。
  • 很抱歉,这不起作用。 btoa 和其他 base64 编码器都无法处理我收到的内容。我在 XHR 对象上尝试了具有不同字符集的 overrideMimeType,我几乎尝试了所有方法。
  • 好的,让我们深入研究一下代码。你能给我一个你的代码的sn-p,你在哪里做GET请求来拍照?如果您不想在此处显示,可以将其发送到我的电子邮箱,在我的个人资料中。
  • 据我了解,您没有使用 OAuth sendSignedRequest 方法。您得到的 XMLHttpRequest 响应确实是我所期望的。假设您有<img id="imageTag" src="" />。用document.getElementById("imageTag").src = "data:image/*;base64," + btoa(nxhr.response);更改图像源。
【解决方案2】:

好的,我找到了解决方案...

首先,请求必须将返回的Type覆盖成x-user-defined

xhr.overrideMimeType('text\/plain; charset=x-user-defined');

之后,浏览器不会触及数据。

使用以下 Base64 编码器

Base64 = {

            // private property
            _keyStr: "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",

            encodeBinary: function (input) {
                var output = "";
                var bytebuffer;
                var encodedCharIndexes = new Array(4);
                var inx = 0;
                var paddingBytes = 0;

                while (inx < input.length) {
                    // Fill byte buffer array
                    bytebuffer = new Array(3);
                    for (jnx = 0; jnx < bytebuffer.length; jnx++)
                        if (inx < input.length)
                            bytebuffer[jnx] = input.charCodeAt(inx++) & 0xff; // throw away high-order byte, as documented at: https://developer.mozilla.org/En/Using_XMLHttpRequest#Handling_binary_data
                        else
                            bytebuffer[jnx] = 0;

                    // Get each encoded character, 6 bits at a time
                    // index 1: first 6 bits
                    encodedCharIndexes[0] = bytebuffer[0] >> 2;
                    // index 2: second 6 bits (2 least significant bits from input byte 1 + 4 most significant bits from byte 2)
                    encodedCharIndexes[1] = ((bytebuffer[0] & 0x3) << 4) | (bytebuffer[1] >> 4);
                    // index 3: third 6 bits (4 least significant bits from input byte 2 + 2 most significant bits from byte 3)
                    encodedCharIndexes[2] = ((bytebuffer[1] & 0x0f) << 2) | (bytebuffer[2] >> 6);
                    // index 3: forth 6 bits (6 least significant bits from input byte 3)
                    encodedCharIndexes[3] = bytebuffer[2] & 0x3f;

                    // Determine whether padding happened, and adjust accordingly
                    paddingBytes = inx - (input.length - 1);
                    switch (paddingBytes) {
                        case 2:
                            // Set last 2 characters to padding char
                            encodedCharIndexes[3] = 64;
                            encodedCharIndexes[2] = 64;
                            break;
                        case 1:
                            // Set last character to padding char
                            encodedCharIndexes[3] = 64;
                            break;
                        default:
                            break; // No padding - proceed
                    }
                    // Now we will grab each appropriate character out of our keystring
                    // based on our index array and append it to the output string
                    for (jnx = 0; jnx < encodedCharIndexes.length; jnx++)
                        output += this._keyStr.charAt(encodedCharIndexes[jnx]);
                }
                return output;
            }
        };

Mozilla 发布了一些神奇的东西,让我无法正确编码这些东西

bytebuffer[jnx] = input.charCodeAt(inx++) & 0xff

最终的代码将如下所示...

oauth.authorize(function () {
    var method = "GET", params = {}, url = photo.href;

    var nxhr = new XMLHttpRequest();
    nxhr.onreadystatechange = function (data) {
        if (nxhr.readyState == 4) {
            console.log("<img src='data:image/*;base64," + Base64.encodeBinary(nxhr.response) + "' />");
        }
    };
    nxhr.open(method, url, true);
    nxhr.setRequestHeader('GData-Version', '3.0');
    nxhr.setRequestHeader('Authorization', oauth.getAuthorizationHeader(url, method, params));
    nxhr.overrideMimeType('text\/plain; charset=x-user-defined'); 
});

附:如果直接将“data:image/*”放入浏览器窗口,会下载文件,无法打开。但是如果你直接把它放到一个img src中就可以了!

【讨论】:

  • 我无法使此解决方案有效。你能提供一个工作小提琴吗?
  • 你好@luke你能提供小提琴吗?
【解决方案3】:

所有其他解决方案都已过时。不需要 Base64。查看my answer on Getting BLOB data from XHR request

【讨论】:

    【解决方案4】:

    如果您使用data: URI,我认为您不关心旧浏览器。在这种情况下,请按照How can you encode a string to Base64 in JavaScript? 中的建议使用btoa(),然后使用the alternative mentioned in the second answer。然后,data: URI 很简单:

    data:image/*;base64,<the btoa output>
    

    【讨论】:

    • AFAIK,Internet Explorer 从 IE7 开始支持 img data。 IE7 应该已经够老了。此外,btoa() 函数是 Gecko DOM 的一部分,不适用于 IE。
    • @Ozbekov:不仅仅是壁虎。 Safari 和 Chrome 也支持它。编辑以包含我的意思。
    • 但是IE没有,所以我提供了一个外部函数进行编码。
    • @Ozbekov:以及为什么我编辑我的答案以提及包含替代功能的第二个答案。
    • 大家好,别担心,只用chrome,没别的,就是chrome扩展。哈,那不是很好,不用担心 IE 吗? :)
    【解决方案5】:

    我知道这是一个非常古老的问题,但由于这是参考 XHR 上的图像和二进制数据,所以对我来说秘诀在于两个重要步骤:

    第 1 步:确保您使用自定义的用户定义字符集,以防止浏览器更改内容。例如

    xhr.overrideMimeType('text\/plain; charset=x-user-defined');
    

    第 2 步: 使用 String.fromCharCode(response.charCodeAt(...) &amp; 0xff) 解决 btoa() 无法处理二进制字符串的问题。这是受到要点@https://gist.github.com/graylikeme/867848 的启发(现在对我来说它是黑魔法)。

    End Eesult:以下是结果的简化版本。请注意,通常您也会这样做,因为您还需要发送 Authorization 标头或其他内容,但这不包括在此示例中。

    <div id="output-el"></div>
    <script>
        var xhr = new XMLHttpRequest();
        xhr.addEventListener('readystatechange', function() {
            var outputEl = document.getElementById('xhr-output');
    
            // Done?
            if (this.readyState === 4) {
    
                // Make sure this is an image.
                var contentType = this.getResponseHeader('content-type');
                if (contentType !== null && contentType.indexOf('image/') === 0) {
                    // Prepare binary response so we can base64 encode it (and btoa() function doesn't freak out).
                    // Thanks to: https://gist.github.com/graylikeme/867848
                    var response = this.responseText;
                    var binary = '';
                    for(i=0; i < response.length; i++) {
                        binary += String.fromCharCode(response.charCodeAt(i) & 0xff);
                    }
    
                    // Drop into data URI.
                    var encoded = btoa(binary);
                    outputEl.innerHTML = `<img alt="image preview" src="data:${contentType};base64,${encoded}">`;
    
                } else {
                    console.log('Got a non-image response:', this.responseText);
                }
            }
        });
    
        // Make sure browser doesn't alter the response before we handle it.
        xhr.overrideMimeType('text\/plain; charset=x-user-defined');
        xhr.open('GET', 'https://example.com/path/to/some/image.jpg');
        xhr.send();
    </script>
    

    【讨论】:

      猜你喜欢
      • 2019-04-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-07-22
      • 2020-10-26
      • 2017-06-17
      • 1970-01-01
      相关资源
      最近更新 更多