Имам двоични данни, кодирани по base64, в низ.
const contentType = 'image/png';
const b64Data = 'iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg==';
Бих искал да създам blob:
URL адрес, съдържащ тези данни, и да го покажа на потребителя.
const blob = new Blob(????, {type: contentType});
const blobUrl = URL.createObjectURL(blob);
window.location = blobUrl;
Не успях да разбера как да създам Blob
.
В някои случаи успявам да избегна това, като вместо това използвам URL адрес data:
.
const dataUrl = `data:${contentType};base64,${b64Data}`;
window.location = dataUrl;
В повечето случаи обаче URL адресите data:
са прекалено големи.
Как мога да декодирам base64 низ в обект Blob
в JavaScript?
Функцията atob
ще декодира низ, кодиран по base64, в нов низ с по един символ за всеки байт от двоичните данни.
const byteCharacters = atob(b64Data);
Кодовата точка на всеки символ (charCode) ще бъде стойността на байта. Можем да създадем масив от байтови стойности, като приложим това, използвайки метода .charCodeAt
за всеки символ в низ.
const byteNumbers = new Array(byteCharacters.length);
for (let i = 0; i < byteCharacters.length; i++) {
byteNumbers[i] = byteCharacters.charCodeAt(i);
}
Можете да преобразувате този масив от байтови стойности в реално типизиран батов масив, като го предадете на конструктора Uint8Array
.
const byteArray = new Uint8Array(byteNumbers);
Той от своя страна може да бъде превърнат в Blob
, като се обвие в масив и се предаде на конструктора Blob
.
const blob = new Blob([byteArray], {type: contentType});
Горният код работи. Въпреки това производителността може да се подобри малко, като се обработват byteCharacters
на по-малки части, а не наведнъж. При моите груби тестове 512 байта изглежда е добър размер на частите. Това ни дава следната функция.
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;
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);
Оптимизирана (но по-малко четивна) реализация:
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 });
}
За данни за изображения смятам, че е по-лесно да се използва canvas.toBlob
(асинхронно)
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
});