JavaScript에서 base64 문자열로 Blob 만들기
문자열에 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이 엄청나게 큽니다.
Blob
JavaScript에서 base64 문자열을 객체로 어떻게 디코딩 합니까?
이 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);
다음은 종속성이나 라이브러리가없는보다 최소한의 방법입니다.
새로운 가져 오기 API가 필요합니다. ( 사용할 수 있습니까? )
var url = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg=="
fetch(url)
.then(res => res.blob())
.then(blob => console.log(blob))
이 방법을 사용하면 ArrayBuffer, 텍스트 및 JSON을 쉽게 얻을 수 있습니다.
비동기 함수로 :
const b64toBlob = async (b64Data, contentType='application/octet-stream') => {
const url = `data:${contentType};base64,${b64Data}`;
const response = await fetch(url);
const blob = await response.blob();
return blob;
};
Jeremy의 ES6 동기화 버전에 대한 간단한 성능 테스트를 수행했습니다.
동기화 버전은 UI를 잠시 차단합니다. devtool을 열어두면 가져 오기 성능이 느려질 수 있습니다.
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 = 1000
console.time('b64')
while (i--) {
await b64toBlob(b64Data)
}
console.timeEnd('b64')
// bench non blocking
i = 1000
// 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()
최적화 된 (하지만 읽기 어려운) 구현 :
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 chrome and FF
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에 해당하지만 IE는 슬라이스 데이터를 Blob-Constructor로 전달할 때 문제가있는 것 같습니다. 내 컴퓨터에서 5MB의 데이터를 전달하면 IE가 충돌하고 메모리 소비가 지붕을 통과합니다. 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();
그래서 제레미가 설명한 두 가지 방법을 하나의 기능으로 포함하기로 결정했습니다. 크레딧은 그를 위해 간다.
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 IE 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 IE 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;
}
}
프로젝트에 하나의 종속성을 추가 할 수 있다면 편리한 기능 을 제공하는 훌륭한 blob-util
npm 패키지 가 base64StringToBlob
있습니다. package.json
당신에 추가되면 다음과 같이 사용할 수 있습니다 :
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...
다음은 Javascript로 쉽게 변환 할 수 있고 사용할 수있는 Typescript 코드입니다.
/**
* CONVERT BASE64 TO BLOB
* @param Base64Image Pass base64 image data to convert into the blob
*/
private convertBase64ToBlob(Base64Image: any) {
// 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 });
}
나는 base64 변환을보다 선언적인 방법으로 게시하고 있습니다. 비동기 fetch().blob()
가 매우 깔끔하고이 솔루션을 좋아할 때 IE11에서는 작동하지 않습니다 (아마도 Edge는 이것을 테스트하지 않았 음).
const blobPdfFromBase64String = base64String => {
const byteArray = Uint8Array.from(
atob(base64String)
.split('')
.map(char => char.charCodeAt(0))
);
return new Blob([byteArray], { type: 'application/pdf' });
};
보너스
당신이 그것을 인쇄하려면 다음과 같이 sth 할 수 있습니다 :
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;
}
};
BONUSx2-IE11의 새 탭에서 Blob 파일 열기
서버에서 base64 문자열을 사전 처리 할 수 있다면 URL 아래에 노출시키고 링크를 사용할 수 있습니다 printJS
:)
페치가있는 방법이 가장 좋은 해결책이지만, 페치없이 방법을 사용해야하는 사람이 있다면 위에서 언급 한 방법이 효과가 없기 때문에 여기에 있습니다.
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 });
}
참고 URL : https://stackoverflow.com/questions/16245767/creating-a-blob-from-a-base64-string-in-javascript
'development' 카테고리의 다른 글
문자열 표현을 사용하지 않고 설정된 시간대로 날짜 만들기 (0) | 2020.02.23 |
---|---|
왜 IDE를 사용해야합니까? (0) | 2020.02.23 |
Swift 3에서 디스패치 큐를 생성하는 방법 (0) | 2020.02.23 |
macOS에서 터미널에서 숭고한 텍스트 열기 (0) | 2020.02.23 |
생성자 또는 선언시 클래스 필드를 초기화 하시겠습니까? (0) | 2020.02.23 |