Invalid filename after converting base64 string to blob - javascript

I am using the following function to convert a base64 string to blob. This is working fine. However, when I upload the file to a third party API, it fails. The reason is because the API expects proper fileName(with extension) and the blob I create doesn't seems to have it. It assigns the filename "blob" instead of "blob.jpg"
Here is the request I traced:
------WebKitFormBoundarytqD15GSBoU08Xz1l
Content-Disposition: form-data; name="image"; filename="blob"
Content-Type: image/jpeg
How can I get the filename when I convert the string to Blob? Here is the function:
function b64toBlob(b64Data, contentType, sliceSize) {
contentType = contentType || '';
sliceSize = sliceSize || 512;
var byteCharacters = atob(b64Data);
var byteArrays = [];
for (var offset = 0; offset < byteCharacters.length; offset += sliceSize) {
var slice = byteCharacters.slice(offset, offset + sliceSize);
var byteNumbers = new Array(slice.length);
for (var i = 0; i < slice.length; i++) {
byteNumbers[i] = slice.charCodeAt(i);
}
var byteArray = new Uint8Array(byteNumbers);
byteArrays.push(byteArray);
}
var blob = new Blob(byteArrays, { type: contentType });
return blob;
}

While appending the image data to form, I was doing like:
formData.append('image', BlobICreatedFromTheAboveFunction);
The correct way to assign image name is:
formData.append('image', BlobICreatedFromTheAboveFunction, "Whatever.jpg");

Related

Encode a Blob with PHP and Decode with JavaScript through an AJAX request [duplicate]

I have Base64-encoded binary data in a string:
const contentType = 'image/png';
const b64Data = 'iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg==';
I would like to create a blob: URL containing this data and display it to the user:
const blob = new Blob(????, {type: contentType});
const blobUrl = URL.createObjectURL(blob);
window.location = blobUrl;
I haven't been been able to figure out how to create the BLOB.
In some cases I am able to avoid this by using a data: URL instead:
const dataUrl = `data:${contentType};base64,${b64Data}`;
window.location = dataUrl;
However, in most cases the data: URLs are prohibitively large.
How can I decode a Base64 string to a BLOB object in JavaScript?
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:
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);
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)
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
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()
Optimized (but less readable) implementation:
function base64toBlob(base64Data, contentType) {
contentType = contentType || '';
var sliceSize = 1024;
var byteCharacters = atob(base64Data);
var bytesLength = byteCharacters.length;
var slicesCount = Math.ceil(bytesLength / sliceSize);
var byteArrays = new Array(slicesCount);
for (var sliceIndex = 0; sliceIndex < slicesCount; ++sliceIndex) {
var begin = sliceIndex * sliceSize;
var end = Math.min(begin + sliceSize, bytesLength);
var bytes = new Array(end - begin);
for (var offset = begin, i = 0; offset < end; ++i, ++offset) {
bytes[i] = byteCharacters[offset].charCodeAt(0);
}
byteArrays[sliceIndex] = new Uint8Array(bytes);
}
return new Blob(byteArrays, { type: contentType });
}
Following is my TypeScript code which can be converted easily into JavaScript and you can use
/**
* Convert BASE64 to BLOB
* #param base64Image Pass Base64 image data to convert into the BLOB
*/
private convertBase64ToBlob(base64Image: string) {
// Split into two parts
const parts = base64Image.split(';base64,');
// Hold the content type
const imageType = parts[0].split(':')[1];
// Decode Base64 string
const decodedData = window.atob(parts[1]);
// Create UNIT8ARRAY of size same as row data length
const uInt8Array = new Uint8Array(decodedData.length);
// Insert all character code into uInt8Array
for (let i = 0; i < decodedData.length; ++i) {
uInt8Array[i] = decodedData.charCodeAt(i);
}
// Return BLOB image after conversion
return new Blob([uInt8Array], { type: imageType });
}
See this example: https://jsfiddle.net/pqhdce2L/
function b64toBlob(b64Data, contentType, sliceSize) {
contentType = contentType || '';
sliceSize = sliceSize || 512;
var byteCharacters = atob(b64Data);
var byteArrays = [];
for (var offset = 0; offset < byteCharacters.length; offset += sliceSize) {
var slice = byteCharacters.slice(offset, offset + sliceSize);
var byteNumbers = new Array(slice.length);
for (var i = 0; i < slice.length; i++) {
byteNumbers[i] = slice.charCodeAt(i);
}
var byteArray = new Uint8Array(byteNumbers);
byteArrays.push(byteArray);
}
var blob = new Blob(byteArrays, {type: contentType});
return blob;
}
var contentType = 'image/png';
var b64Data = Your Base64 encode;
var blob = b64toBlob(b64Data, contentType);
var blobUrl = URL.createObjectURL(blob);
var img = document.createElement('img');
img.src = blobUrl;
document.body.appendChild(img);
For all browser support, especially on Android, perhaps you can add this:
try{
blob = new Blob(byteArrays, {type : contentType});
}
catch(e){
// TypeError old Google Chrome and Firefox
window.BlobBuilder = window.BlobBuilder ||
window.WebKitBlobBuilder ||
window.MozBlobBuilder ||
window.MSBlobBuilder;
if(e.name == 'TypeError' && window.BlobBuilder){
var bb = new BlobBuilder();
bb.append(byteArrays);
blob = bb.getBlob(contentType);
}
else if(e.name == "InvalidStateError"){
// InvalidStateError (tested on FF13 WinXP)
blob = new Blob(byteArrays, {type : contentType});
}
else{
// We're screwed, blob constructor unsupported entirely
}
}
For all copy-paste lovers out there like me, here is a cooked download function which works on Chrome, Firefox and Edge:
window.saveFile = function (bytesBase64, mimeType, fileName) {
var fileUrl = "data:" + mimeType + ";base64," + bytesBase64;
fetch(fileUrl)
.then(response => response.blob())
.then(blob => {
var link = window.document.createElement("a");
link.href = window.URL.createObjectURL(blob, { type: mimeType });
link.download = fileName;
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
});
}
I'm posting a more declarative way of sync Base64 converting. While async fetch().blob() is very neat and I like this solution a lot, it doesn't work on Internet Explorer 11 (and probably Edge - I haven't tested this one), even with the polyfill - take a look at my comment to Endless' post for more details.
const blobPdfFromBase64String = base64String => {
const byteArray = Uint8Array.from(
atob(base64String)
.split('')
.map(char => char.charCodeAt(0))
);
return new Blob([byteArray], { type: 'application/pdf' });
};
Bonus
If you want to print it you could do something like:
const isIE11 = !!(window.navigator && window.navigator.msSaveOrOpenBlob); // Or however you want to check it
const printPDF = blob => {
try {
isIE11
? window.navigator.msSaveOrOpenBlob(blob, 'documents.pdf')
: printJS(URL.createObjectURL(blob)); // http://printjs.crabbly.com/
} catch (e) {
throw PDFError;
}
};
Bonus x 2 - Opening a BLOB file in new tab for Internet Explorer 11
If you're able to do some preprocessing of the Base64 string on the server you could expose it under some URL and use the link in printJS :)
For image data, I find it simpler to use canvas.toBlob (asynchronous)
function b64toBlob(b64, onsuccess, onerror) {
var img = new Image();
img.onerror = onerror;
img.onload = function onload() {
var canvas = document.createElement('canvas');
canvas.width = img.width;
canvas.height = img.height;
var ctx = canvas.getContext('2d');
ctx.drawImage(img, 0, 0, canvas.width, canvas.height);
canvas.toBlob(onsuccess);
};
img.src = b64;
}
var base64Data = 'data:image/jpg;base64,/9j/4AAQSkZJRgABAQA...';
b64toBlob(base64Data,
function(blob) {
var url = window.URL.createObjectURL(blob);
// do something with url
}, function(error) {
// handle error
});
If you can stand adding one dependency to your project there's the great blob-util npm package that provides a handy base64StringToBlob function. Once added to your package.json you can use it like this:
import { base64StringToBlob } from 'blob-util';
const contentType = 'image/png';
const b64Data = 'iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg==';
const blob = base64StringToBlob(b64Data, contentType);
// Do whatever you need with your blob...
I noticed that Internet Explorer 11 gets incredibly slow when slicing the data like Jeremy suggested. This is true for Chrome, but Internet Explorer seems to have a problem when passing the sliced data to the Blob-Constructor. On my machine, passing 5 MB of data makes Internet Explorer crash and memory consumption is going through the roof. Chrome creates the blob in no time.
Run this code for a comparison:
var byteArrays = [],
megaBytes = 2,
byteArray = new Uint8Array(megaBytes*1024*1024),
block,
blobSlowOnIE, blobFastOnIE,
i;
for (i = 0; i < (megaBytes*1024); i++) {
block = new Uint8Array(1024);
byteArrays.push(block);
}
//debugger;
console.profile("No Slices");
blobSlowOnIE = new Blob(byteArrays, { type: 'text/plain'});
console.profileEnd();
console.profile("Slices");
blobFastOnIE = new Blob([byteArray], { type: 'text/plain'});
console.profileEnd();
So I decided to include both methods described by Jeremy in one function. Credits go to him for this.
function base64toBlob(base64Data, contentType, sliceSize) {
var byteCharacters,
byteArray,
byteNumbers,
blobData,
blob;
contentType = contentType || '';
byteCharacters = atob(base64Data);
// Get BLOB data sliced or not
blobData = sliceSize ? getBlobDataSliced() : getBlobDataAtOnce();
blob = new Blob(blobData, { type: contentType });
return blob;
/*
* Get BLOB data in one slice.
* => Fast in Internet Explorer on new Blob(...)
*/
function getBlobDataAtOnce() {
byteNumbers = new Array(byteCharacters.length);
for (var i = 0; i < byteCharacters.length; i++) {
byteNumbers[i] = byteCharacters.charCodeAt(i);
}
byteArray = new Uint8Array(byteNumbers);
return [byteArray];
}
/*
* Get BLOB data in multiple slices.
* => Slow in Internet Explorer on new Blob(...)
*/
function getBlobDataSliced() {
var slice,
byteArrays = [];
for (var offset = 0; offset < byteCharacters.length; offset += sliceSize) {
slice = byteCharacters.slice(offset, offset + sliceSize);
byteNumbers = new Array(slice.length);
for (var i = 0; i < slice.length; i++) {
byteNumbers[i] = slice.charCodeAt(i);
}
byteArray = new Uint8Array(byteNumbers);
// Add slice
byteArrays.push(byteArray);
}
return byteArrays;
}
}
The method with fetch is the best solution, but if anyone needs to use a method without fetch then here it is, as the ones mentioned previously didn't work for me:
function makeblob(dataURL) {
const BASE64_MARKER = ';base64,';
const parts = dataURL.split(BASE64_MARKER);
const contentType = parts[0].split(':')[1];
const raw = window.atob(parts[1]);
const rawLength = raw.length;
const uInt8Array = new Uint8Array(rawLength);
for (let i = 0; i < rawLength; ++i) {
uInt8Array[i] = raw.charCodeAt(i);
}
return new Blob([uInt8Array], { type: contentType });
}
In browser just
Uint8Array.from(atob(YOUR_BASE64_DATA), (c) => c.charCodeAt(0))
compare with fetch
!(async () => {
const start = performance.now();
let i = 0;
while (i++ < 1e3) {
const dataUrl =
"data:application/octet-stream;base64,H4sIAAAAAAAAA0vOzyvOz0nVy8lP10jISM3JyVdIr8osUFCpdkksSdXLyy/X0KxN0ORKHlU3qm5U3ai6UXWj6kauOgBVt1KRLwcAAA==";
body = await (await fetch(dataUrl)).blob();
}
console.log(performance.now() - start); // 508.19999999925494ms
})();
!(async () => {
const start = performance.now();
let i = 0;
while (i++ < 1e3) {
const base64Data =
"H4sIAAAAAAAAA0vOzyvOz0nVy8lP10jISM3JyVdIr8osUFCpdkksSdXLyy/X0KxN0ORKHlU3qm5U3ai6UXWj6kauOgBVt1KRLwcAAA==";
body = Uint8Array.from(atob(base64Data), (c) => c.charCodeAt(0));
}
console.log(performance.now() - start); // 7.899999998509884ms
})();
Depends on your data size, choose performance one.
Two different variations
function base64ToBlob(base64, contentType='image/png', chunkLength=512) {
const byteCharsArray = Array.from(atob(base64.substr(base64.indexOf(',') + 1)));
const chunksIterator = new Array(Math.ceil(byteCharsArray.length / chunkLength));
const bytesArrays = [];
for (let c = 0; c < chunksIterator.length; c++) {
bytesArrays.push(new Uint8Array(byteCharsArray.slice(c * chunkLength, chunkLength * (c + 1)).map(s => s.charCodeAt(0))));
}
const blob = new Blob(bytesArrays, {type: contentType});
return blob;
}
/* Not sure how it performs with big images */
async function base64ToBlobLight(base64) { return await fetch(base64).then(res => res.blob()); }
/* Test */
const base64Data = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAMAAADXqc3KAAAB+FBMVEUAAAA/mUPidDHiLi5Cn0XkNTPmeUrkdUg/m0Q0pEfcpSbwaVdKskg+lUP4zA/iLi3msSHkOjVAmETdJSjtYFE/lkPnRj3sWUs8kkLeqCVIq0fxvhXqUkbVmSjwa1n1yBLepyX1xxP0xRXqUkboST9KukpHpUbuvRrzrhF/ljbwaljuZFM4jELaoSdLtElJrUj1xxP6zwzfqSU4i0HYnydMtUlIqUfywxb60AxZqEXaoifgMCXptR9MtklHpEY2iUHWnSjvvRr70QujkC+pUC/90glMuEnlOjVMt0j70QriLS1LtEnnRj3qUUXfIidOjsxAhcZFo0bjNDH0xxNLr0dIrUdmntVTkMoyfL8jcLBRuErhJyrgKyb4zA/5zg3tYFBBmUTmQTnhMinruBzvvhnxwxZ/st+Ktt5zp9hqota2vtK6y9FemNBblc9HiMiTtMbFtsM6gcPV2r6dwroseLrMrbQrdLGdyKoobKbo3Zh+ynrgVllZulTsXE3rV0pIqUf42UVUo0JyjEHoS0HmsiHRGR/lmRz/1hjqnxjvpRWfwtOhusaz0LRGf7FEfbDVmqHXlJeW0pbXq5bec3fX0nTnzmuJuWvhoFFhm0FtrziBsjaAaDCYWC+uSi6jQS3FsSfLJiTirCOkuCG1KiG+wSC+GBvgyhTszQ64Z77KAAAARXRSTlMAIQRDLyUgCwsE6ebm5ubg2dLR0byXl4FDQzU1NDEuLSUgC+vr6urq6ubb29vb2tra2tG8vLu7u7uXl5eXgYGBgYGBLiUALabIAAABsElEQVQoz12S9VPjQBxHt8VaOA6HE+AOzv1wd7pJk5I2adpCC7RUcHd3d3fXf5PvLkxheD++z+yb7GSRlwD/+Hj/APQCZWxM5M+goF+RMbHK594v+tPoiN1uHxkt+xzt9+R9wnRTZZQpXQ0T5uP1IQxToyOAZiQu5HEpjeA4SWIoksRxNiGC1tRZJ4LNxgHgnU5nJZBDvuDdl8lzQRBsQ+s9PZt7s7Pz8wsL39/DkIfZ4xlB2Gqsq62ta9oxVlVrNZpihFRpGO9fzQw1ms0NDWZz07iGkJmIFH8xxkc3a/WWlubmFkv9AB2SEpDvKxbjidN2faseaNV3zoHXvv7wMODJdkOHAegweAfFPx4G67KluxzottCU9n8CUqXzcIQdXOytAHqXxomvykhEKN9EFutG22p//0rbNvHVxiJywa8yS2KDfV1dfbu31H8jF1RHiTKtWYeHxUvq3bn0pyjCRaiRU6aDO+gb3aEfEeVNsDgm8zzLy9egPa7Qt8TSJdwhjplk06HH43ZNJ3s91KKCHQ5x4sw1fRGYDZ0n1L4FKb9/BP5JLYxToheoFCVxz57PPS8UhhEpLBVeAAAAAElFTkSuQmCC';
const blob = base64ToBlob(base64Data);
const blobUrl = URL.createObjectURL(blob);
const img = document.createElement('img');
img.src = blobUrl;
document.body.appendChild(img);
/**********************/
/* Test */
(async () => {
const blob = await base64ToBlobLight(base64Data);
const blobUrl = URL.createObjectURL(blob);
const img = document.createElement('img');
img.src = blobUrl;
document.body.appendChild(img);
})();
This would prove to be much short solution.
const byteArray = new Buffer(base64String.replace(/^[\w\d;:\/]+base64\,/g, ''), 'base64');
base64String is the string containing the base 64 string.
byteArray is the array you need.
The regex replacement is optional and is just there to deal with prefix as in the case of dataurl string.

URL.createobjecturl() not creating the url for the correct image [duplicate]

I have Base64-encoded binary data in a string:
const contentType = 'image/png';
const b64Data = 'iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg==';
I would like to create a blob: URL containing this data and display it to the user:
const blob = new Blob(????, {type: contentType});
const blobUrl = URL.createObjectURL(blob);
window.location = blobUrl;
I haven't been been able to figure out how to create the BLOB.
In some cases I am able to avoid this by using a data: URL instead:
const dataUrl = `data:${contentType};base64,${b64Data}`;
window.location = dataUrl;
However, in most cases the data: URLs are prohibitively large.
How can I decode a Base64 string to a BLOB object in JavaScript?
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:
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);
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)
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
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()
Optimized (but less readable) implementation:
function base64toBlob(base64Data, contentType) {
contentType = contentType || '';
var sliceSize = 1024;
var byteCharacters = atob(base64Data);
var bytesLength = byteCharacters.length;
var slicesCount = Math.ceil(bytesLength / sliceSize);
var byteArrays = new Array(slicesCount);
for (var sliceIndex = 0; sliceIndex < slicesCount; ++sliceIndex) {
var begin = sliceIndex * sliceSize;
var end = Math.min(begin + sliceSize, bytesLength);
var bytes = new Array(end - begin);
for (var offset = begin, i = 0; offset < end; ++i, ++offset) {
bytes[i] = byteCharacters[offset].charCodeAt(0);
}
byteArrays[sliceIndex] = new Uint8Array(bytes);
}
return new Blob(byteArrays, { type: contentType });
}
Following is my TypeScript code which can be converted easily into JavaScript and you can use
/**
* Convert BASE64 to BLOB
* #param base64Image Pass Base64 image data to convert into the BLOB
*/
private convertBase64ToBlob(base64Image: string) {
// Split into two parts
const parts = base64Image.split(';base64,');
// Hold the content type
const imageType = parts[0].split(':')[1];
// Decode Base64 string
const decodedData = window.atob(parts[1]);
// Create UNIT8ARRAY of size same as row data length
const uInt8Array = new Uint8Array(decodedData.length);
// Insert all character code into uInt8Array
for (let i = 0; i < decodedData.length; ++i) {
uInt8Array[i] = decodedData.charCodeAt(i);
}
// Return BLOB image after conversion
return new Blob([uInt8Array], { type: imageType });
}
See this example: https://jsfiddle.net/pqhdce2L/
function b64toBlob(b64Data, contentType, sliceSize) {
contentType = contentType || '';
sliceSize = sliceSize || 512;
var byteCharacters = atob(b64Data);
var byteArrays = [];
for (var offset = 0; offset < byteCharacters.length; offset += sliceSize) {
var slice = byteCharacters.slice(offset, offset + sliceSize);
var byteNumbers = new Array(slice.length);
for (var i = 0; i < slice.length; i++) {
byteNumbers[i] = slice.charCodeAt(i);
}
var byteArray = new Uint8Array(byteNumbers);
byteArrays.push(byteArray);
}
var blob = new Blob(byteArrays, {type: contentType});
return blob;
}
var contentType = 'image/png';
var b64Data = Your Base64 encode;
var blob = b64toBlob(b64Data, contentType);
var blobUrl = URL.createObjectURL(blob);
var img = document.createElement('img');
img.src = blobUrl;
document.body.appendChild(img);
For all browser support, especially on Android, perhaps you can add this:
try{
blob = new Blob(byteArrays, {type : contentType});
}
catch(e){
// TypeError old Google Chrome and Firefox
window.BlobBuilder = window.BlobBuilder ||
window.WebKitBlobBuilder ||
window.MozBlobBuilder ||
window.MSBlobBuilder;
if(e.name == 'TypeError' && window.BlobBuilder){
var bb = new BlobBuilder();
bb.append(byteArrays);
blob = bb.getBlob(contentType);
}
else if(e.name == "InvalidStateError"){
// InvalidStateError (tested on FF13 WinXP)
blob = new Blob(byteArrays, {type : contentType});
}
else{
// We're screwed, blob constructor unsupported entirely
}
}
For all copy-paste lovers out there like me, here is a cooked download function which works on Chrome, Firefox and Edge:
window.saveFile = function (bytesBase64, mimeType, fileName) {
var fileUrl = "data:" + mimeType + ";base64," + bytesBase64;
fetch(fileUrl)
.then(response => response.blob())
.then(blob => {
var link = window.document.createElement("a");
link.href = window.URL.createObjectURL(blob, { type: mimeType });
link.download = fileName;
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
});
}
I'm posting a more declarative way of sync Base64 converting. While async fetch().blob() is very neat and I like this solution a lot, it doesn't work on Internet Explorer 11 (and probably Edge - I haven't tested this one), even with the polyfill - take a look at my comment to Endless' post for more details.
const blobPdfFromBase64String = base64String => {
const byteArray = Uint8Array.from(
atob(base64String)
.split('')
.map(char => char.charCodeAt(0))
);
return new Blob([byteArray], { type: 'application/pdf' });
};
Bonus
If you want to print it you could do something like:
const isIE11 = !!(window.navigator && window.navigator.msSaveOrOpenBlob); // Or however you want to check it
const printPDF = blob => {
try {
isIE11
? window.navigator.msSaveOrOpenBlob(blob, 'documents.pdf')
: printJS(URL.createObjectURL(blob)); // http://printjs.crabbly.com/
} catch (e) {
throw PDFError;
}
};
Bonus x 2 - Opening a BLOB file in new tab for Internet Explorer 11
If you're able to do some preprocessing of the Base64 string on the server you could expose it under some URL and use the link in printJS :)
For image data, I find it simpler to use canvas.toBlob (asynchronous)
function b64toBlob(b64, onsuccess, onerror) {
var img = new Image();
img.onerror = onerror;
img.onload = function onload() {
var canvas = document.createElement('canvas');
canvas.width = img.width;
canvas.height = img.height;
var ctx = canvas.getContext('2d');
ctx.drawImage(img, 0, 0, canvas.width, canvas.height);
canvas.toBlob(onsuccess);
};
img.src = b64;
}
var base64Data = 'data:image/jpg;base64,/9j/4AAQSkZJRgABAQA...';
b64toBlob(base64Data,
function(blob) {
var url = window.URL.createObjectURL(blob);
// do something with url
}, function(error) {
// handle error
});
If you can stand adding one dependency to your project there's the great blob-util npm package that provides a handy base64StringToBlob function. Once added to your package.json you can use it like this:
import { base64StringToBlob } from 'blob-util';
const contentType = 'image/png';
const b64Data = 'iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg==';
const blob = base64StringToBlob(b64Data, contentType);
// Do whatever you need with your blob...
I noticed that Internet Explorer 11 gets incredibly slow when slicing the data like Jeremy suggested. This is true for Chrome, but Internet Explorer seems to have a problem when passing the sliced data to the Blob-Constructor. On my machine, passing 5 MB of data makes Internet Explorer crash and memory consumption is going through the roof. Chrome creates the blob in no time.
Run this code for a comparison:
var byteArrays = [],
megaBytes = 2,
byteArray = new Uint8Array(megaBytes*1024*1024),
block,
blobSlowOnIE, blobFastOnIE,
i;
for (i = 0; i < (megaBytes*1024); i++) {
block = new Uint8Array(1024);
byteArrays.push(block);
}
//debugger;
console.profile("No Slices");
blobSlowOnIE = new Blob(byteArrays, { type: 'text/plain'});
console.profileEnd();
console.profile("Slices");
blobFastOnIE = new Blob([byteArray], { type: 'text/plain'});
console.profileEnd();
So I decided to include both methods described by Jeremy in one function. Credits go to him for this.
function base64toBlob(base64Data, contentType, sliceSize) {
var byteCharacters,
byteArray,
byteNumbers,
blobData,
blob;
contentType = contentType || '';
byteCharacters = atob(base64Data);
// Get BLOB data sliced or not
blobData = sliceSize ? getBlobDataSliced() : getBlobDataAtOnce();
blob = new Blob(blobData, { type: contentType });
return blob;
/*
* Get BLOB data in one slice.
* => Fast in Internet Explorer on new Blob(...)
*/
function getBlobDataAtOnce() {
byteNumbers = new Array(byteCharacters.length);
for (var i = 0; i < byteCharacters.length; i++) {
byteNumbers[i] = byteCharacters.charCodeAt(i);
}
byteArray = new Uint8Array(byteNumbers);
return [byteArray];
}
/*
* Get BLOB data in multiple slices.
* => Slow in Internet Explorer on new Blob(...)
*/
function getBlobDataSliced() {
var slice,
byteArrays = [];
for (var offset = 0; offset < byteCharacters.length; offset += sliceSize) {
slice = byteCharacters.slice(offset, offset + sliceSize);
byteNumbers = new Array(slice.length);
for (var i = 0; i < slice.length; i++) {
byteNumbers[i] = slice.charCodeAt(i);
}
byteArray = new Uint8Array(byteNumbers);
// Add slice
byteArrays.push(byteArray);
}
return byteArrays;
}
}
The method with fetch is the best solution, but if anyone needs to use a method without fetch then here it is, as the ones mentioned previously didn't work for me:
function makeblob(dataURL) {
const BASE64_MARKER = ';base64,';
const parts = dataURL.split(BASE64_MARKER);
const contentType = parts[0].split(':')[1];
const raw = window.atob(parts[1]);
const rawLength = raw.length;
const uInt8Array = new Uint8Array(rawLength);
for (let i = 0; i < rawLength; ++i) {
uInt8Array[i] = raw.charCodeAt(i);
}
return new Blob([uInt8Array], { type: contentType });
}
In browser just
Uint8Array.from(atob(YOUR_BASE64_DATA), (c) => c.charCodeAt(0))
compare with fetch
!(async () => {
const start = performance.now();
let i = 0;
while (i++ < 1e3) {
const dataUrl =
"data:application/octet-stream;base64,H4sIAAAAAAAAA0vOzyvOz0nVy8lP10jISM3JyVdIr8osUFCpdkksSdXLyy/X0KxN0ORKHlU3qm5U3ai6UXWj6kauOgBVt1KRLwcAAA==";
body = await (await fetch(dataUrl)).blob();
}
console.log(performance.now() - start); // 508.19999999925494ms
})();
!(async () => {
const start = performance.now();
let i = 0;
while (i++ < 1e3) {
const base64Data =
"H4sIAAAAAAAAA0vOzyvOz0nVy8lP10jISM3JyVdIr8osUFCpdkksSdXLyy/X0KxN0ORKHlU3qm5U3ai6UXWj6kauOgBVt1KRLwcAAA==";
body = Uint8Array.from(atob(base64Data), (c) => c.charCodeAt(0));
}
console.log(performance.now() - start); // 7.899999998509884ms
})();
Depends on your data size, choose performance one.
Two different variations
function base64ToBlob(base64, contentType='image/png', chunkLength=512) {
const byteCharsArray = Array.from(atob(base64.substr(base64.indexOf(',') + 1)));
const chunksIterator = new Array(Math.ceil(byteCharsArray.length / chunkLength));
const bytesArrays = [];
for (let c = 0; c < chunksIterator.length; c++) {
bytesArrays.push(new Uint8Array(byteCharsArray.slice(c * chunkLength, chunkLength * (c + 1)).map(s => s.charCodeAt(0))));
}
const blob = new Blob(bytesArrays, {type: contentType});
return blob;
}
/* Not sure how it performs with big images */
async function base64ToBlobLight(base64) { return await fetch(base64).then(res => res.blob()); }
/* Test */
const base64Data = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAMAAADXqc3KAAAB+FBMVEUAAAA/mUPidDHiLi5Cn0XkNTPmeUrkdUg/m0Q0pEfcpSbwaVdKskg+lUP4zA/iLi3msSHkOjVAmETdJSjtYFE/lkPnRj3sWUs8kkLeqCVIq0fxvhXqUkbVmSjwa1n1yBLepyX1xxP0xRXqUkboST9KukpHpUbuvRrzrhF/ljbwaljuZFM4jELaoSdLtElJrUj1xxP6zwzfqSU4i0HYnydMtUlIqUfywxb60AxZqEXaoifgMCXptR9MtklHpEY2iUHWnSjvvRr70QujkC+pUC/90glMuEnlOjVMt0j70QriLS1LtEnnRj3qUUXfIidOjsxAhcZFo0bjNDH0xxNLr0dIrUdmntVTkMoyfL8jcLBRuErhJyrgKyb4zA/5zg3tYFBBmUTmQTnhMinruBzvvhnxwxZ/st+Ktt5zp9hqota2vtK6y9FemNBblc9HiMiTtMbFtsM6gcPV2r6dwroseLrMrbQrdLGdyKoobKbo3Zh+ynrgVllZulTsXE3rV0pIqUf42UVUo0JyjEHoS0HmsiHRGR/lmRz/1hjqnxjvpRWfwtOhusaz0LRGf7FEfbDVmqHXlJeW0pbXq5bec3fX0nTnzmuJuWvhoFFhm0FtrziBsjaAaDCYWC+uSi6jQS3FsSfLJiTirCOkuCG1KiG+wSC+GBvgyhTszQ64Z77KAAAARXRSTlMAIQRDLyUgCwsE6ebm5ubg2dLR0byXl4FDQzU1NDEuLSUgC+vr6urq6ubb29vb2tra2tG8vLu7u7uXl5eXgYGBgYGBLiUALabIAAABsElEQVQoz12S9VPjQBxHt8VaOA6HE+AOzv1wd7pJk5I2adpCC7RUcHd3d3fXf5PvLkxheD++z+yb7GSRlwD/+Hj/APQCZWxM5M+goF+RMbHK594v+tPoiN1uHxkt+xzt9+R9wnRTZZQpXQ0T5uP1IQxToyOAZiQu5HEpjeA4SWIoksRxNiGC1tRZJ4LNxgHgnU5nJZBDvuDdl8lzQRBsQ+s9PZt7s7Pz8wsL39/DkIfZ4xlB2Gqsq62ta9oxVlVrNZpihFRpGO9fzQw1ms0NDWZz07iGkJmIFH8xxkc3a/WWlubmFkv9AB2SEpDvKxbjidN2faseaNV3zoHXvv7wMODJdkOHAegweAfFPx4G67KluxzottCU9n8CUqXzcIQdXOytAHqXxomvykhEKN9EFutG22p//0rbNvHVxiJywa8yS2KDfV1dfbu31H8jF1RHiTKtWYeHxUvq3bn0pyjCRaiRU6aDO+gb3aEfEeVNsDgm8zzLy9egPa7Qt8TSJdwhjplk06HH43ZNJ3s91KKCHQ5x4sw1fRGYDZ0n1L4FKb9/BP5JLYxToheoFCVxz57PPS8UhhEpLBVeAAAAAElFTkSuQmCC';
const blob = base64ToBlob(base64Data);
const blobUrl = URL.createObjectURL(blob);
const img = document.createElement('img');
img.src = blobUrl;
document.body.appendChild(img);
/**********************/
/* Test */
(async () => {
const blob = await base64ToBlobLight(base64Data);
const blobUrl = URL.createObjectURL(blob);
const img = document.createElement('img');
img.src = blobUrl;
document.body.appendChild(img);
})();
This would prove to be much short solution.
const byteArray = new Buffer(base64String.replace(/^[\w\d;:\/]+base64\,/g, ''), 'base64');
base64String is the string containing the base 64 string.
byteArray is the array you need.
The regex replacement is optional and is just there to deal with prefix as in the case of dataurl string.

b64toBlob() just returns size and type instead of full image data

Here is my b64toBlob() function which I'm using for converting base64 to blob so I'll be able to upload it into the server by appending to a formData:
function b64toBlob(b64Data, contentType, sliceSize) {
contentType = contentType || '';
sliceSize = sliceSize || 512;
var byteCharacters = atob(b64Data);
var byteArrays = [];
for (var offset = 0; offset < byteCharacters.length; offset += sliceSize) {
var slice = byteCharacters.slice(offset, offset + sliceSize);
var byteNumbers = new Array(slice.length);
for (var i = 0; i < slice.length; i++) {
byteNumbers[i] = slice.charCodeAt(i);
}
var byteArray = new Uint8Array(byteNumbers);
byteArrays.push(byteArray);
}
var blob = new Blob(byteArrays, { type: contentType });
return blob;
}
and Here is my base64 code:
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
But when I run it, it just returns Blob(15598) {size: 15598, type: "image/jpeg"} without image data.
---- Update:
I'm sure It's not an error about back-end (because I'm using the same API in other components for upload) but, here is the rest of my code:
(I'm using react and 'that' is equal to this)
...
var myDURL = c.toDataURL('image/jpeg')
var base64result = myDURL.split(',')[1];
var theblob = that.b64toBlob(base64result, 'image/jpeg')
var photosformdata = new FormData()
photosformdata.append('files', theblob);
let authUserID = await localStorage.getItem('usrid')
let filesResult = await requester(config.serverurl + 'v1/panel/users/' + await authUserID + '/profile/avatar', 'PUT', true, null, photosformdata, true)
if (filesResult.statusCode == 200 || filesResult.statusCode == 201) {
console.log(filesResult)
this.props.actions.setUploadedFilesOnAddNewMedia(filesResult.data.filesArray)
}
...
and here is in down below: (first one is what am I getting and secound one is what am I had to get):
Wow, EVERYTHING works fine and good as expected! I just missed a name for my file on formData.append()
I just added a name for it as down below:
photosformdata.append('files', theblob, 'image.jpg');
The content of the blob is not displayed in the console. Use FilerReader:
var b = b64toBlob(b64, 'image/jpeg')
var fileReader = new FileReader();
fileReader.addEventListener('loadend', (e) => {
console.log(e.srcElement.result);
});
fileReader.readAsText(b);
[ https://jsfiddle.net/srL845g7/ ]

Blob to Base64 in javascript

I have successfully converted my base64 (DATA_URI) image into blob but not able to revert it back.
My base64 to blob code look like below for more info look this link.
b64toBlob(b64Data, contentType, sliceSize) {
contentType = contentType || '';
sliceSize = sliceSize || 512;
var byteCharacters = atob(b64Data);
var byteArrays = [];
for (var offset = 0; offset < byteCharacters.length; offset += sliceSize) {
var slice = byteCharacters.slice(offset, offset + sliceSize);
var byteNumbers = new Array(slice.length);
for (var i = 0; i < slice.length; i++) {
byteNumbers[i] = slice.charCodeAt(i);
}
var byteArray = new Uint8Array(byteNumbers);
byteArrays.push(byteArray);
}
var blob = new Blob(byteArrays, {type: contentType});
return blob;
}
I am trying to convert my blob to base64 I get an error as
ERROR TypeError: Failed to execute 'readAsDataURL' on 'FileReader': parameter 1 is not of type 'Blob'.
here is my response for getting back my blob image res
I am invoking success callback but not able to under stand this
here is the code where I try to convert blob to base64
if(window.FileReader) {
var reader = new FileReader();
reader.readAsDataURL(blob);
reader.onloadend = () => {
var base64data = reader.result;
console.log(base64data);
}
}
While debugging i am not able to see reader.onloadend it is null and i am not able to invoke it.
Any help??
I believe you need to define onloadend before you start reading the data. It is likely completing the read and firing the null function before you've assigned it. Or more precisely at the moment you call readAsDataURL, onloadend is null.
var reader = new FileReader();
reader.onloadend = () => {
var base64data = reader.result;
console.log(base64data);
}
reader.readAsDataURL(blob);

How to solve error: Failed to create temp file 18

Iam using this code to receive list base64 and print multiple pdf file, I handle this problem by convert each base64 to arraybuffer to blob pdf. But it has error Failed to create temp file 18 : It was determined that certain files are unsafe for access within a Web application, or that too many calls are being made on file resources. when pass base64 many time.
$scope.b64toBlob = function (b64Data, contentType, sliceSize) {
contentType = contentType || '';
sliceSize = sliceSize || 1024;
var byteCharacters = atob(b64Data);
var byteArrays = [];
for (var offset = 0; offset < byteCharacters.length; offset += sliceSize) {
var slice = byteCharacters.slice(offset, offset + sliceSize);
var byteNumbers = new Array(slice.length);
for (var i = 0; i < slice.length; i++) {
byteNumbers[i] = slice.charCodeAt(i);
}
var byteArray = new Uint8Array(byteNumbers);
byteArrays.push(byteArray);
}
var blob = new Blob(byteArrays, {type: contentType});
return blob;
}
return $http.post(api, params).then(function(response) {
$scope.isSaving = false;
var datas = response.data;
for(var i = 0; i < datas.length; i++) {
var uint8Array = new Uint8Array(datas[i]);
var arrayBuffer = uint8Array.buffer;
var file = $scope.b64toBlob(datas[i], typeReport);
var fileURL = window.URL.createObjectURL(file);
window.open(fileURL);
}
$scope.clear();
}, function(){
$scope.isSaving = false;
});
Sorry for my English. Thanks for help.

Categories

Resources