문자열에 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을 만드는 방법을 알 수 없었습니다.
어떤 경우에는 data:
대신 URL 을 사용하여 이것을 피할 수 있습니다 .
const dataUrl = `data:${contentType};base64,${b64Data}`;
window.location = dataUrl;
그러나 대부분의 경우 data:
URL이 엄청나게 큽니다.
JavaScript에서 Base64 문자열을 BLOB 객체로 어떻게 디코딩합니까?
답변
이 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;
전체 예 :
답변
다음은 종속성이나 라이브러리가없는보다 최소한의 방법입니다.
새로운 가져 오기 API가 필요합니다. ( 사용할 수 있습니까? )
var url = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg=="
fetch(url)
.then(res => res.blob())
.then(console.log)
이 방법을 사용하면 ReadableStream, ArrayBuffer, text 및 JSON도 쉽게 얻을 수 있습니다.
기능으로서 :
const b64toBlob = (base64, type = 'application/octet-stream') =>
fetch(`data:${type};base64,${base64}`).then(res => res.blob())
Jeremy의 ES6 동기화 버전에 대한 간단한 성능 테스트를 수행했습니다.
동기화 버전은 UI를 잠시 차단합니다. devtool을 열린 상태로 유지하면 가져 오기 성능이 느려질 수 있습니다
답변
최적화 된 (하지만 읽기 어려운) 구현 :
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 });
}
답변
모든 브라우저 지원, 특히 Android에서 다음을 추가 할 수 있습니다.
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
}
}
답변
이미지 데이터의 경우 사용이 더 간단합니다 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
});
답변
이 예를 참조하십시오 : 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);
답변
Jeremy가 제안한대로 데이터를자를 때 Internet Explorer 11이 매우 느려집니다. 이것은 Chrome의 경우에 해당하지만 Internet Explorer는 슬라이스 된 데이터를 Blob-Constructor로 전달할 때 문제가있는 것 같습니다. 내 컴퓨터에서 5MB의 데이터를 전달하면 Internet Explorer가 중단되고 메모리 소비가 급증합니다. Chrome은 신속하게 얼룩을 만듭니다.
비교를 위해이 코드를 실행하십시오.
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();
그래서 Jeremy가 설명한 두 가지 방법을 하나의 함수에 포함하기로 결정했습니다. 크레딧은 그를 위해 간다.
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;
}
}