In Node.js you don't have Blobs but Buffers. You can create a buffer from a base64 string like this:
var str = "iAAANS....SUVORK5CYII="; // <-- use real base64 string here
var buf = Buffer.from(str, "base64");
stream.write(buf);
Answer from Marc on Stack Overflownode.js - How to convert a string to blob/longblob in nodejs - MySQL - Stack Overflow
Javascript convert a Blob object to a string and back - Stack Overflow
node.js - Conversion of buffer data to blob in NodeJS - Stack Overflow
html - Javascript - I created a blob from a string, how do I get the string back out? - Stack Overflow
» npm install blob-util
To convert a string to a blob, you use the new Blob interface:
const blob = new Blob([string], {
type: 'image/jpeg' // or whatever your Content-Type is
});
See this section of the document you linked to.
If you have a Blob object called blob, blob.type will give its content type. So you could deconstruct and reconstruct it as follows:
const string = await blob.text();
const type = blob.type;
const blob2 = new Blob([string], {type: type});
const base64Data = "dGVRAXXRoZXIUl";
Depending on the format of the base64 string, you might need to prepend content type data. For example, a JPEG image
const base64Return = await fetch(`data:image/jpeg;base64,${base64Data}`);
Then, convert the response to a blob
const blob = await base64Return.blob();
For "text/html" format, for example, you can get the raw text
const text = await base64Return.text();
In order to extract data from a Blob, you need a FileReader.
var reader = new FileReader();
reader.onload = function() {
alert(reader.result);
}
reader.readAsText(blob);
@joey asked how to wrap @philipp's answer in a function, so here's a solution that does that in modern Javascript (thanks @Endless):
const text = await new Response(blob).text()
The atob function will decode a base64-encoded string into a new string with a character for each byte of the binary data.
const byteCharacters = atob(b64Data);
Each character's code point (charCode) will be the value of the byte. We can create an array of byte values by applying this using the .charCodeAt method for each character in the string.
const byteNumbers = new Array(byteCharacters.length);
for (let i = 0; i < byteCharacters.length; i++) {
byteNumbers[i] = byteCharacters.charCodeAt(i);
}
You can convert this array of byte values into a real typed byte array by passing it to the Uint8Array constructor.
const byteArray = new Uint8Array(byteNumbers);
This in turn can be converted to a Blob by wrapping it in an array and passing it to the Blob constructor.
const blob = new Blob([byteArray], {type: contentType});
The code above works. However the performance can be improved a little by processing the byteCharacters in smaller slices, rather than all at once. In my rough testing 512 bytes seems to be a good slice size. This gives us the following function.
const b64toBlob = (b64Data, contentType='', sliceSize=512) => {
const byteCharacters = atob(b64Data);
const byteArrays = [];
for (let offset = 0; offset < byteCharacters.length; offset += sliceSize) {
const slice = byteCharacters.slice(offset, offset + sliceSize);
const byteNumbers = new Array(slice.length);
for (let i = 0; i < slice.length; i++) {
byteNumbers[i] = slice.charCodeAt(i);
}
const byteArray = new Uint8Array(byteNumbers);
byteArrays.push(byteArray);
}
const blob = new Blob(byteArrays, {type: contentType});
return blob;
}
const blob = b64toBlob(b64Data, contentType);
const blobUrl = URL.createObjectURL(blob);
window.location = blobUrl;
Full Example:
Show code snippet
const b64toBlob = (b64Data, contentType='', sliceSize=512) => {
const byteCharacters = atob(b64Data);
const byteArrays = [];
for (let offset = 0; offset < byteCharacters.length; offset += sliceSize) {
const slice = byteCharacters.slice(offset, offset + sliceSize);
const byteNumbers = new Array(slice.length);
for (let i = 0; i < slice.length; i++) {
byteNumbers[i] = slice.charCodeAt(i);
}
const byteArray = new Uint8Array(byteNumbers);
byteArrays.push(byteArray);
}
const blob = new Blob(byteArrays, {type: contentType});
return blob;
}
const contentType = 'image/png';
const b64Data = 'iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg==';
const blob = b64toBlob(b64Data, contentType);
const blobUrl = URL.createObjectURL(blob);
const img = document.createElement('img');
img.src = blobUrl;
document.body.appendChild(img);
Run code snippetEdit code snippet Hide Results Copy to answer Expand
Here is a more minimal method without any dependencies or libraries.
It requires the new fetch API. (Can I use it?)
var url = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg=="
fetch(url)
.then(res => res.blob())
.then(console.log)
Run code snippetEdit code snippet Hide Results Copy to answer Expand
With this method you can also easily get a ReadableStream, ArrayBuffer, text, and JSON.
(fyi this also works with node-fetch in Node)
As a function:
const b64toBlob = (base64, type = 'application/octet-stream') =>
fetch(`data:${type};base64,${base64}`).then(res => res.blob())
But I would encourage you to don't use base64 in the first place. There are better ways to send and receive binary data. JSON isn't always the best option. it takes up more bandwidth and waste processing time (de)encodeing stuff. Us eg canvas.toBlob instead of canvas.toDataURL and use FormData to send binary files. you can also return back a multipart payload and decode it using await response.formData() that is coming from a server response. FormData can go both ways.
I did a simple performance test towards Jeremy's ES6 sync version.
The sync version will block UI for a while.
keeping the devtool open can slow the fetch performance
Show code snippet
document.body.innerHTML += '<input autofocus placeholder="try writing">'
// get some dummy gradient image
var img=function(){var a=document.createElement("canvas"),b=a.getContext("2d"),c=b.createLinearGradient(0,0,1500,1500);a.width=a.height=3000;c.addColorStop(0,"red");c.addColorStop(1,"blue");b.fillStyle=c;b.fillRect(0,0,a.width,a.height);return a.toDataURL()}();
async function perf() {
const blob = await fetch(img).then(res => res.blob())
// turn it to a dataURI
const url = img
const b64Data = url.split(',')[1]
// Jeremy Banks solution
const b64toBlob = (b64Data, contentType = '', sliceSize=512) => {
const byteCharacters = atob(b64Data);
const byteArrays = [];
for (let offset = 0; offset < byteCharacters.length; offset += sliceSize) {
const slice = byteCharacters.slice(offset, offset + sliceSize);
const byteNumbers = new Array(slice.length);
for (let i = 0; i < slice.length; i++) {
byteNumbers[i] = slice.charCodeAt(i);
}
const byteArray = new Uint8Array(byteNumbers);
byteArrays.push(byteArray);
}
const blob = new Blob(byteArrays, {type: contentType});
return blob;
}
// bench blocking method
let i = 500
console.time('blocking b64')
while (i--) {
await b64toBlob(b64Data)
}
console.timeEnd('blocking b64')
// bench non blocking
i = 500
// so that the function is not reconstructed each time
const toBlob = res => res.blob()
console.time('fetch')
while (i--) {
await fetch(url).then(toBlob)
}
console.timeEnd('fetch')
console.log('done')
}
perf()
Run code snippetEdit code snippet Hide Results Copy to answer Expand