Why it doesn't work?

作業のメモ、記録をブログに残しています。

JavaScript バイナリの画像データをBase64でエンコードする

JavaScript バイナリファイルを読み込む - Why it doesn't work?
JavaScript バイナリデータを扱う。4バイトの数値の配列をunsigned long(uint32)型の数値へ変換する - Why it doesn't work?
JavaScript バイナリデータの配列をUTF-8文字列へ変換する - Why it doesn't work?

久しぶりのJavaScriptです。そして、このバイナリシリーズもまだ続いてます。
外部データのバイナリデータに含まれてるPNG画像のデータを抽出し、それをブラウザ上で表示したいと考えました。
通常はファイル名をimgタグに指定します、当然ながらバイナリデータを指定しても表示されません。

<img src="sample.png">

調べたところ、Base64エンコードした画像データなら表示できると言うことで、バイナリの画像データをBase64エンコードすることにしました。

<img src="data:image/png;base64,iVBORw0KGgo....">

ちょっと大きなデータで申し訳ないですが、実際のPNG画像のバイナリデータを使用してみました。

1. 取得したバイナリデータを文字列に変換後、base64文字列に変換する方法

var data = [
  0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A, 0x00, 0x00, 0x00, 0x0D, 0x49, 0x48, 0x44, 0x52,
  0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x0C, 0x08, 0x06, 0x00, 0x00, 0x00, 0xB9, 0xB7, 0x37,
  0xD9, 0x00, 0x00, 0x00, 0x01, 0x73, 0x52, 0x47, 0x42, 0x00, 0xAE, 0xCE, 0x1C, 0xE9, 0x00, 0x00,
  0x00, 0x04, 0x67, 0x41, 0x4D, 0x41, 0x00, 0x00, 0xB1, 0x8F, 0x0B, 0xFC, 0x61, 0x05, 0x00, 0x00,
  0x00, 0x09, 0x70, 0x48, 0x59, 0x73, 0x00, 0x00, 0x0E, 0xC4, 0x00, 0x00, 0x0E, 0xC4, 0x01, 0x95,
  0x2B, 0x0E, 0x1B, 0x00, 0x00, 0x00, 0x1E, 0x49, 0x44, 0x41, 0x54, 0x28, 0x53, 0x63, 0xBC, 0x72,
  0xE1, 0xC4, 0x7F, 0x06, 0x12, 0x01, 0x13, 0x94, 0x26, 0x09, 0x8C, 0x6A, 0x82, 0x82, 0x51, 0x4D,
  0x60, 0xC0, 0xC0, 0x00, 0x00, 0x95, 0xD0, 0x03, 0x83, 0x79, 0x73, 0x2C, 0x33, 0x00, 0x00, 0x00,
  0x00, 0x49, 0x45, 0x4E, 0x44, 0xAE, 0x42, 0x60, 0x82
];
var b64 = "data:image/png;base64," + btoa(String.fromCharCode.apply(String, data));
console.log(b64);

2. BlobとFile APIを使用する方法

var data = new Uint8Array([
0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A, 0x00, 0x00, 0x00, 0x0D, 0x49, 0x48, 0x44, 0x52,
0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x0C, 0x08, 0x06, 0x00, 0x00, 0x00, 0xB9, 0xB7, 0x37,
0xD9, 0x00, 0x00, 0x00, 0x01, 0x73, 0x52, 0x47, 0x42, 0x00, 0xAE, 0xCE, 0x1C, 0xE9, 0x00, 0x00,
0x00, 0x04, 0x67, 0x41, 0x4D, 0x41, 0x00, 0x00, 0xB1, 0x8F, 0x0B, 0xFC, 0x61, 0x05, 0x00, 0x00,
0x00, 0x09, 0x70, 0x48, 0x59, 0x73, 0x00, 0x00, 0x0E, 0xC4, 0x00, 0x00, 0x0E, 0xC4, 0x01, 0x95,
0x2B, 0x0E, 0x1B, 0x00, 0x00, 0x00, 0x1E, 0x49, 0x44, 0x41, 0x54, 0x28, 0x53, 0x63, 0xBC, 0x72,
0xE1, 0xC4, 0x7F, 0x06, 0x12, 0x01, 0x13, 0x94, 0x26, 0x09, 0x8C, 0x6A, 0x82, 0x82, 0x51, 0x4D,
0x60, 0xC0, 0xC0, 0x00, 0x00, 0x95, 0xD0, 0x03, 0x83, 0x79, 0x73, 0x2C, 0x33, 0x00, 0x00, 0x00,
0x00, 0x49, 0x45, 0x4E, 0x44, 0xAE, 0x42, 0x60, 0x82
]);
var blob = new Blob([data], { type: "image/png" });
var reader = new FileReader();
reader.onload = function() {
var b64 = reader.result;
console.log(b64);
}
reader.readAsDataURL(blob);

どちらの方法でも以下のようなデータが出力されるので、これをイメージタグに設定すればブラウザ上で表示されます。

data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA0AAAAMCAYAAAC5tzfZAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAAeSURBVChTY7xy4cR/BhIBE5QmCYxqgoJRTWDAwAAAldADg3lzLDMAAAAASUVORK5CYII=

方法2のポイントは、Uint8Arrayタイプの配列にデータを設定すること、エンコードの完了は非同期で通知されることです。
他にも方法はあるようですが、今回はこれまで。