Reputation: 361
I have some images that will be displayed in a React app. I perform a GET request to a server, which returns images in BLOB format. Then I transform these images to base64. Finally, i'm setting these base64 strings inside the src attribute of an image tag.
Recently I've started using the Fetch API. I was wondering if there is a way to do the transforming in 'one' go.
Below an example to explain my idea so far and/or if this is even possible with the Fetch API. I haven't found anything online yet.
let reader = new window.FileReader();
fetch('http://localhost:3000/whatever')
.then(response => response.blob())
.then(myBlob => reader.readAsDataURL(myBlob))
.then(myBase64 => {
imagesString = myBase64
}).catch(error => {
//Lalala
})
Upvotes: 30
Views: 43147
Reputation: 121
Here's the logic for converting a blob to an image URI, derived from @Augustin Riedinger's answer:
async function imageBlobToBase64(blob: Blob) {
return new Promise((onSuccess, onError) => {
try {
const reader = new FileReader();
reader.onload = function () {
onSuccess(this.result);
};
reader.readAsDataURL(blob);
} catch (e) {
onError(e);
}
});
}
Usage:
const res = await fetch(...);
const blob = await res.blob();
const uri = await imageBlobToBase64(blob);
Upvotes: 2
Reputation: 3209
In case someone is working in a V8 environment (such as Cloudflare Workers).
There's no FileReader
like in the browser, and there's probably1 no Buffer
like in Node.js. So instead, we can use the standard Uint8Array
, which is used under the hood by Buffer
:
/**
* Fetches an image from URL and encodes it into a base64 string
* Adapted from this thread: https://community.cloudflare.com/t/convert-request-body-to-base64-encoded-string-solved/99341/5
* @param {string} url
* @returns {Promise<string>}
*/
async function imageUrlToBase64(url) {
let string = "";
const response = await fetch(url);
const buffer = await response.arrayBuffer();
(new Uint8Array(buffer)).forEach(
(byte) => { string += String.fromCharCode(byte) }
)
return btoa(string);
}
1 In Cloudflare Workers, you could also opt into Buffer compatibility by adding the node_compat flag.
Upvotes: 0
Reputation: 22170
Thanks to @GetFree, here's the async/await
version of it, with promise error handling:
const imageUrlToBase64 = async url => {
const response = await fetch(url);
const blob = await response.blob();
return new Promise((onSuccess, onError) => {
try {
const reader = new FileReader() ;
reader.onload = function(){ onSuccess(this.result) } ;
reader.readAsDataURL(blob) ;
} catch(e) {
onError(e);
}
});
};
Usage:
const base64 = await imageUrlToBase64('https://via.placeholder.com/150');
Upvotes: 15
Reputation: 10162
If somebody gonna need to do it in Node.js:
const fetch = require('cross-fetch');
const response = await fetch(url);
const base64_body = (await response.buffer()).toString('base64');
Upvotes: 3
Reputation: 42434
The return of FileReader.readAsDataURL
is not a promise. You have to do it the old way.
fetch('http://localhost:3000/whatever')
.then( response => response.blob() )
.then( blob =>{
var reader = new FileReader() ;
reader.onload = function(){ console.log(this.result) } ; // <--- `this.result` contains a base64 data URI
reader.readAsDataURL(blob) ;
}) ;
function urlContentToDataUri(url){
return fetch(url)
.then( response => response.blob() )
.then( blob => new Promise( callback =>{
let reader = new FileReader() ;
reader.onload = function(){ callback(this.result) } ;
reader.readAsDataURL(blob) ;
}) ) ;
}
//Usage example:
urlContentToDataUri('http://example.com').then( dataUri => console.log(dataUri) ) ;
//Usage example using await:
let dataUri = await urlContentToDataUri('http://example.com') ;
console.log(dataUri) ;
Upvotes: 36