如何将响应中的二进制图像解析为 base64 字符串?

IT技术 javascript image base64 binaryfiles type-conversion
2021-03-08 23:37:44

我想将 REST API 中请求的图像解析为 base64 字符串。

在此处输入图片说明

首先......我想,这很容易,只是window.btoa()为了这个目的使用函数。

当我尝试在我的应用程序的这一部分执行此操作时:

.done( function( response, position ) {
    var texture = new Image();
    texture.src = "data:image/png;base64," + window.btoa( response ); 

我遇到了下一个错误:未捕获的 InvalidCharacterError:无法在 'Window' 上执行 'btoa':要编码的字符串包含超出 Latin1 范围的字符。

正如我在这里读到的:javascript atob 返回“字符串包含无效字符”

出现问题的原因是newlines in the response,这就是window.btoa()失败的原因任何二进制图像格式当然都会有换行符......但是从上面的链接中,建议是删除/替换这些字符 - 对我来说是一个坏建议,因为如果从二进制图像中删除/替换一些字符,它只会是损坏。

当然,可能的替代方案与 API 设计有关: - 添加一些函数,返回 base64 表示 - 添加一些函数,将 url 返回到图像

如果我不修复它,我将从服务器返回base64表示,但我不喜欢这种方式。

是否存在某种方法来解决我从响应中处理二进制图像的问题,如上面屏幕截图部分所示,不是吗?

6个回答

我认为问题的一部分,你打的是,jQuery.ajax不是原生支持XHR2 BLOB / arraybuffer类型,可以很好地处理二进制数据(见阅读使用jQuery.ajax二进制文件)。

如果您使用带有 的本机 XHR 对象xhr.responseType = 'arraybuffer',然后读取响应数组并将其转换为 Base64,您将得到您想要的。

这是一个对我有用的解决方案:

// http://www.henryalgus.com/reading-binary-files-using-jquery-ajax/
function fetchBlob(uri, callback) {
  var xhr = new XMLHttpRequest();
  xhr.open('GET', uri, true);
  xhr.responseType = 'arraybuffer';

  xhr.onload = function(e) {
    if (this.status == 200) {
      var blob = this.response;
      if (callback) {
        callback(blob);
      }
    }
  };
  xhr.send();
};

fetchBlob('https://i.imgur.com/uUGeiSFb.jpg', function(blob) {
  // Array buffer to Base64:
  var str = btoa(String.fromCharCode.apply(null, new Uint8Array(blob)));

  console.log(str);
  // Or: '<img src="data:image/jpeg;base64,' + str + '">'
});

https://jsfiddle.net/oy1pk8r3/2/

生成 base64 编码的控制台输出: /9j/4AAQSkZJRgABAQEASABIAAD/2wBDAAIBAQIBAQICAgICAgICAw.....

谢谢,我花了一段时间才意识到由于打字错误,这解决了我的问题,但这对我有用。
2021-04-24 23:37:44
这拯救了我的一天
2021-05-04 23:37:44

不是使用 _arrayBufferToBase64() 循环遍历 blob,而是使用 apply() 进行转换,它在我的浏览器中快了 30 倍并且更简洁

// http://www.henryalgus.com/reading-binary-files-using-jquery-ajax/
function fetchBlob(uri, callback) {
  var xhr = new XMLHttpRequest();
  xhr.open('GET', uri, true);
  xhr.responseType = 'arraybuffer';

  xhr.onload = function(e) {
    if (this.status == 200) {
      var blob = this.response;
      if (callback) {
        callback(blob);
      }
    }
  };
  xhr.send();
};

fetchBlob('https://i.imgur.com/uUGeiSFb.jpg', function(blob) {
  var str = String.fromCharCode.apply(null, new Uint8Array(blob));
  console.log(str);
  // the base64 data: image is then
  // '<img src="data:image/jpeg;base64,' + btoa(str) + '" />'	
});

我已将其纳入上述答案。
2021-05-08 23:37:44

我猜escape在将字符串传递给函数之前使用它,如果没有 API 调用,我无法测试自己。

测试

encodeURI("testñ$☺PNW¢=")

回报

"test%C3%B1$%E2%98%BAPNW%C2%A2="

它只是转义所有字符,它应该转义字符串中的所有非法字符

测试

encodeURI("¶!┼Æê‼_ðÄÄ┘Ì+\+,o▬MBc§yþó÷ö")

回报

"%C2%B6!%E2%94%BC%C3%86%C3%AA%E2%80%BC_%C3%B0%C3%84%C3%84%E2%94%98%C3%8C++,o%E2%96%ACMBc%C2%A7y%C3%BE%C3%B3%C3%B7%C3%B6"

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/encodeURI

恐怕转义会损坏图像,因此在转义某些字符后无法显示它,因为正确的图像显示需要一些换行符和二进制字符,但感谢您的帮助并为我花费时间。
2021-05-04 23:37:44
我建议获得该功能请求。
2021-05-14 23:37:44

您遇到的问题是响应被视为 Unicode 字符串。请参阅此处的 Unicode 字符串部分:window.btoa

这篇文章提供了几种解决方案

响应是二进制格式,而不是文本格式(所以它不能像我想的那样是 unicode 字符串),如果你仔细看,我已经捕捉到了 PNG 图像的二进制内容
2021-05-06 23:37:44
@GeloVolro - 我确实看到了。当我使用 btoa 遇到相同的错误时,我做了很多搜索。我不确定 Chrome 是否显示带有引号的对象,但考虑到它显示的数据让我认为它是一个字符串。由于看起来您正在使用 jQuery,您可以使用 jQuery.type(response) 来查看类型。
2021-05-17 23:37:44

试试这个,让它运行良好请尝试一次。@用户2402179

  $.ajax({
    type: 'GET',
    url: baseUrl",
    dataType: 'binary',
    xhr() {
      let myXhr = jQuery.ajaxSettings.xhr();
      myXhr.responseType = 'blob';
      return myXhr;
    },
    headers: {'Authorization': 'Bearer '+token}      
    
}).then((response) => {
    // response is a Blob
    return new Promise((resolve, reject) => {
      let reader = new FileReader();
      reader.addEventListener('load', () => {
        $('#theDiv').append('<img src="' +reader.result+ '" />')
        resolve(reader.result);
      }, false);
      reader.addEventListener('error', () => {
        reject(reader.error);
      }, false);
      reader.readAsDataURL(response);
    });
  });