1. ホーム
  2. ジャバスクリプト

[解決済み】JavaScriptでBase64文字列からBLOBを作成する場合

2022-03-23 09:56:32

質問

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 のコンストラクタを使用します。

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