I am new to React and want to display an image downloaded as binary data. 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. I can also save the image data to a jpeg-file and it is displayed ok.
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. When i convert the downloaded jpeg using cat image.jpeg|base64 > base64.txt
the resulting string works in my React app.
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.
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). 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.
How do you convert jpeg binary data to valid Base64 image encoding when btoa
throws latin1 exception?
You've said you're using axios.get
to get the image from the server. 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
.
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
:
// 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:
fetch
only rejects its promise on network errors, not HTTP errors; those are reported via the status
and ok
props.ArrayBuffer
; the buffer will have the binary image data.Uint8Array
(using that buffer) to access them.Array.from
and in its mapping function (called for each byte), we'll use String.fromCharCode
to convert the byte to a character. (It's not really much of a conversion. The byte 25 [for instance] becomes the character with character code 25 in the string.) Looking at the docs, it looks like axios
lets you provide the option responseType: "arraybuffer"
to get an array buffer. If I'm reading right, you could use axios
like this:
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.
data:// URLs are completely inefficient and require far more memory space than blob:// URLs. 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. The blob:// URI on the other hand is just a pointer to the binary data in memory.
blob:// URLs are not perfect, but until browsers implement srcDoc
correctly, it's still the best we have.
So if as per the comments you are using axios in a browser, you can do
const blob = await axios.get("/path/to/resource", {responseType: "blob"});
const theImage = URL.createObjectURL(blob);
And if you want to use the 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:
<img src="/path/to/resource" />
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.