简体   繁体   English

将二进制数据转换为 base64 不适用于 btoa unescape

[英]Convert binary data to base64 does not work with btoa unescape

I am new to React and want to display an image downloaded as binary data.我是 React 的新手,想显示下载为二进制数据的图像。 I download the image data from api call to adobe lightroom api. The api call works since the image is displayed in Postman without problems.我从 api 调用 adobe lightroom api 下载图像数据。api 调用有效,因为图像在 Postman 中显示没有问题。 I can also save the image data to a jpeg-file and it is displayed ok.我还可以将图像数据保存到 jpeg 文件中,并且可以正常显示。

In React I want to do <img src={`data:image/jpeg;base64,${theImage}`} /> and for that to work I need to convert the binary data to a base64 encoded string.在 React 中,我想做<img src={`data:image/jpeg;base64,${theImage}`} />为了让它工作,我需要将二进制数据转换为 base64 编码的字符串。 When i convert the downloaded jpeg using cat image.jpeg|base64 > base64.txt the resulting string works in my React app.当我使用cat image.jpeg|base64 > base64.txt转换下载的 jpeg 时,生成的字符串在我的 React 应用程序中有效。

But when I try var theImage = btoa(binarydata) in React I get Unhandled Rejection (InvalidCharacterError): Failed to execute 'btoa' on 'Window': The string to be encoded contains characters outside of the Latin1 range.但是当我在 React 中尝试var theImage = btoa(binarydata)时,我得到Unhandled Rejection (InvalidCharacterError): Failed to execute 'btoa' on 'Window': The string to be encoded contains characters outside of the Latin1 range.

After searching the issue I try use var theImage = btoa(unescape(encodeURIComponent( binarydata ))) and similar proposed solution but resulting strings from those does not turn out to be a valid base64 encodings of the jpeg as it seem (I try the result from the conversions in online base64->image services and no image is shown).搜索问题后,我尝试使用var theImage = btoa(unescape(encodeURIComponent( binarydata )))和类似的建议解决方案,但从中得到的字符串并不是 jpeg 的有效 base64 编码,因为它看起来(我尝试了结果来自在线 base64-> 图像服务中的转换,没有显示图像)。 I have also tried other proposed solution such as base64-js and js-base64 libraries and non of those create a valid base64 valid image that can be shown in my React code.我还尝试了其他建议的解决方案,例如base64-jsjs-base64库,但没有一个创建有效的 base64 有效图像,可以在我的 React 代码中显示。

How do you convert jpeg binary data to valid Base64 image encoding when btoa throws latin1 exception?btoa抛出 latin1 异常时,如何将 jpeg 二进制数据转换为有效的 Base64 图像编码?

You've said you're using axios.get to get the image from the server.你说过你正在使用axios.get从服务器获取图像。 What you'll presumably get back will be a Buffer or ArrayBuffer or Blob , etc., but it depends on what you do with the response you get from axios .您可能会返回BufferArrayBufferBlob等,但这取决于您如何处理从axios获得的响应。

I don't use axios (never felt the need to), but you can readily get a data URI for binary data from the server via fetch :我不使用axios (从未觉得有必要),但您可以通过fetch从服务器轻松获取二进制数据的data URI:

// 1.
const response = await fetch("/path/to/resource");
// 2.
if (!response.ok) {
    throw new Error("HTTP error " + response.status);
}
// 3.
const buffer = await response.arrayBuffer();
// 4.
const byteArray = new Uint8Array(buffer);
// 5.
const charArray = Array.from(byteArray, byte => String.fromCharCode(byte));
// 6.
const binaryString = charArray.join("");
// 7.
const theImage = btoa(binaryString);

Or more concisely:或者更简洁:

const response = await fetch("/path/to/resource");
if (!response.ok) {
    throw new Error("HTTP error " + response.status);
}
const buffer = await response.arrayBuffer();
const binaryString = Array.from(new Uint8Array(buffer), byte => String.fromCharCode(byte)).join("");
const theImage = btoa(binaryString);

Here's how that works:这是它的工作原理:

  1. We request the image data.我们请求图像数据。
  2. We check that the request worked ( fetch only rejects its promise on network errors, not HTTP errors; those are reported via the status and ok props.我们检查请求是否有效( fetch仅拒绝其 promise网络错误,而不是 HTTP 错误;这些通过statusok道具报告。
  3. We read the body of the response into an ArrayBuffer ;我们将响应的主体读入ArrayBuffer the buffer will have the binary image data.缓冲区将包含二进制图像数据。
  4. We want to convert that buffer data into a binary string .我们想将该缓冲区数据转换为二进制字符串 To do that, we need to access the bytes individually, so we create a Uint8Array (using that buffer) to access them.为此,我们需要单独访问字节,因此我们创建了一个Uint8Array (使用该缓冲区)来访问它们。
  5. To convert that byte array into a binary string, we need to convert each byte into its equivalent character, and join those together into a string.要将该字节数组转换为二进制字符串,我们需要将每个字节转换为其等效字符,并将它们连接在一起形成一个字符串。 Let's do that by using Array.from and in its mapping function (called for each byte), we'll use String.fromCharCode to convert the byte to a character.让我们通过使用Array.from和它的映射 function(为每个字节调用)来做到这一点,我们将使用String.fromCharCode将字节转换为字符。 (It's not really much of a conversion. The byte 25 [for instance] becomes the character with character code 25 in the string.) (这并不是真正的转换。字节 25 [例如] 变成字符串中字符代码为 25 的字符。)
  6. Now we create the binary string by joining the characters in that array together into one string.现在我们通过将数组中的字符连接成一个字符串来创建二进制字符串。
  7. Finally, we convert that string to Base64.最后,我们将该字符串转换为 Base64。

Looking at the docs, it looks like axios lets you provide the option responseType: "arraybuffer" to get an array buffer.查看文档,看起来axios让您提供选项responseType: "arraybuffer"来获取数组缓冲区。 If I'm reading right, you could use axios like this:如果我没看错,你可以像这样使用axios

const response = await axios.get("/path/to/resource", {responseType: "arraybuffer"});
const binaryString = Array.from(new Uint8Array(response.body), v => String.fromCharCode(v)).join("");
const theImage = btoa(binaryString);

Fetch your image as a Blob and generate a blob:// URI from it.将图像作为Blob获取并从中生成blob:// URI

data:// URLs are completely inefficient and require far more memory space than blob:// URLs. data:// URLs是完全低效的,需要比 blob:// URLs 多得多的 memory 空间。 The data:// URL takes 34% more space than the actual data it represents and it must be stored in the DOM + decoded as binary again to be read by the image decoder. data:// URL比它代表的实际数据多占用 34% 的空间,它必须存储在 DOM 中 + 再次解码为二进制文件才能被图像解码器读取。 The blob:// URI on the other hand is just a pointer to the binary data in memory.另一方面, blob:// URI只是指向 memory 中二进制数据的指针。

blob:// URLs are not perfect, but until browsers implement srcDoc correctly, it's still the best we have. blob:// URL并不完美,但在浏览器正确实现srcDoc之前,它仍然是我们拥有的最好的。

So if as per the comments you are using axios in a browser, you can do因此,如果根据您在浏览器中使用 axios 的评论,您可以这样做

const blob = await axios.get("/path/to/resource", {responseType: "blob"});
const theImage = URL.createObjectURL(blob);

And if you want to use the fetch API如果你想使用fetch API

const response = await fetch("/path/to/resource");
if (!response.ok) {
    throw new Error("HTTP error " + response.status);
}
const blob = await response.blob();
const theImage = URL.createObjectURL(blob);

Ps:附:
If you don't have any particular reason to fetch this image through AJAX (eg credentials or special POST params), then pass directly the URL of the resource as the src of your image:如果您没有任何特殊原因通过 AJAX 获取此图像(例如凭据或特殊的 POST 参数),则直接将资源的 URL 作为图像的src传递:

<img src="/path/to/resource" />

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM