701 Stimmen

Erstellen eines BLOB aus einem Base64-String in JavaScript

Ich habe Base64-codierte Binärdaten in einem String:

const contentType = 'image/png';
const b64Data = 'iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg==';

Ich möchte eine blob: URL erstellen, die diese Daten enthält, und sie dem Benutzer anzeigen:

const blob = new Blob(????, {type: contentType});
const blobUrl = URL.createObjectURL(blob);

window.location = blobUrl;

Ich konnte bisher nicht herausfinden, wie ich den BLOB erstellen kann.

In einigen Fällen kann ich dies vermeiden, indem ich stattdessen eine data: URL verwende:

const dataUrl = `data:${contentType};base64,${b64Data}`;

window.location = dataUrl;

In den meisten Fällen sind die data: URLs jedoch unpraktisch groß.


Wie kann ich einen Base64-String in ein BLOB-Objekt in JavaScript dekodieren?

14voto

martinoss Punkte 4740

Ich habe festgestellt, dass Internet Explorer 11 extrem langsam wird, wenn die Daten so wie von Jeremy vorgeschlagen aufgeteilt werden. Das trifft auch auf Chrome zu, aber Internet Explorer scheint ein Problem zu haben, wenn die aufgeteilten Daten an den Blob-Konstruktor übergeben werden. Auf meinem Rechner lässt Internet Explorer abstürzen, wenn 5 MB Daten übergeben werden und der Speicherverbrauch steigt enorm. Chrome erstellt den Blob dagegen sofort.

Führen Sie diesen Code zum Vergleich aus:

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("Ohne Slices");
blobSlowOnIE = new Blob(byteArrays, { type: 'text/plain'});
console.profileEnd();

console.profile("Slices");
blobFastOnIE = new Blob([byteArray], { type: 'text/plain'});
console.profileEnd();

Also beschloss ich, beide von Jeremy beschriebenen Methoden in einer Funktion zu verwenden. Credits gehen an ihn dafür.

function base64toBlob(base64Data, contentType, sliceSize) {

    var byteCharacters,
        byteArray,
        byteNumbers,
        blobData,
        blob;

    contentType = contentType || '';

    byteCharacters = atob(base64Data);

    // BLOB-Daten abrufen, geschnitten oder nicht
    blobData = sliceSize ? getBlobDataSliced() : getBlobDataAtOnce();

    blob = new Blob(blobData, { type: contentType });

    return blob;

    /*
     * Die BLOB-Daten in einem Stück abrufen.
     * => Schnell in Internet Explorer bei 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];
    }

    /*
     * Die BLOB-Daten in mehreren Stücken abrufen.
     * => Langsam in Internet Explorer bei 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);

            // Slice hinzufügen
            byteArrays.push(byteArray);
        }

        return byteArrays;
    }
}

12voto

akshay Punkte 141

Die Methode mit fetch ist die beste Lösung, aber wenn jemand eine Methode ohne fetch verwenden muss, dann hier ist sie, da die zuvor erwähnten für mich nicht funktioniert haben:

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 });
}

7voto

A.Chan Punkte 270

Im Browser einfach

Uint8Array.from(atob(DEINE_BASE64_DATEN), (c) => c.charCodeAt(0))

vergleichen mit 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
})();

Je nach Datengröße die Leistungsstärkere wählen.

4voto

Puerto AGP Punkte 303

Zwei verschiedene Varianten

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;
}

/* Nicht sicher, wie es mit großen Bildern funktioniert */
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);
})();

0voto

GuruKay Punkte 3287

Dies wäre eine viel kürzere Lösung.

const byteArray = new Buffer(base64String.replace(/^[\w\d;:\/]+base64\,/g, ''), 'base64');

base64String ist der String, der den Base-64-String enthält.

byteArray ist das Array, das du benötigst.

Der Regex-Ersatz ist optional und dient nur dazu, mit einem Präfix wie im Fall eines Data-URL-Strings umzugehen.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X