• Blob (≒ File)
  • ArrayBuffer
  • Buffer
  • TypedArray (Uint8Array, Uint16Array, Uint32Array)
  • Canvas (HTMLCanvasElement)
  • Image (HTMLImageElement)
  • 文字列 (普通の文字列, Base64文字列, バイナリ文字列)

JavaScriptの、ここらへん同士の変換方法をむやみやたらにまとめてます。

  1. TypedArray → Blob
  2. Blob → ArrayBuffer
  3. ArrayBuffer → TypedArray
  4. TypedArray → ArrayBuffer
  5. Uint8Array → Uint16Array|Uint32Array
  6. Uint16Array|Uint32Array → Uint8Array
  7. ArrayBuffer → Buffer
  8. Buffer → ArrayBuffer
  9. Buffer → TypedArray
  10. TypedArray → Buffer
  11. 文字列 → Blob (UTF-8)
  12. 文字列 → ArrayBuffer (UTF-8)
  13. ArrayBuffer (UTF-8) → 文字列
  14. 文字列 → Buffer
  15. Blob → Base64文字列
  16. Base64文字列 → バイナリ文字列
  17. バイナリ文字列 → Base64文字列
  18. バイナリ文字列 → Blob
  19. バイナリ文字列 → Uint8Array
  20. Uint8Array → バイナリ文字列
  21. 文字列 → Uint16Array
  22. Uint16Array → 文字列
  23. Blob → Image
  24. Image → Canvas
  25. Canvas → Image
  26. Canvas → Blob
  27. Canvas → Base64文字列

TypedArray → Blob

Blob コンストラクタを使います。

なお、次項の方法で ArrayBuffer にしてみると分かりますが、この時バイトオーダーはリトルエンディアンになります。

function typedArrayToBlob(typedArray, mimeType) {
	mimeType = mimeType === undefined ? 'application/octet-binary' : mimeType;
	return new Blob([typedArray], { type: mimeType });
}

Blob → ArrayBuffer

FileReaderreadAsArrayBuffer() を使います。onload イベントを待つので非同期です。

function blobToArrayBuffer(blob, callback) {
	const reader = new FileReader();
	reader.addEventListener('load', function(event) {
		const arrayBuffer = event.target.result;
		callback(arrayBuffer);
	});
	reader.readAsArrayBuffer(blob);
}

ArrayBuffer → TypedArray

いずれかの TypedArray コンストラクタを使います。ここでは例として Uint8Array を使いました。

function arrayBufferToUint8Array(arrayBuffer) {
	return new Uint8Array(arrayBuffer);
}

TypedArray → ArrayBuffer

ArrayBuffer を参照するビューを作成して、その中に Buffer の内容をコピーする必要があります。

Uint8Array
function uint8ArrayToArrayBuffer(uint8Array) {
	const arrayBuffer = new ArrayBuffer(uint8Array.length);
	const view = new Uint8Array(arrayBuffer);  // ArrayBufferを参照するTypedArray (ビュー) を作成
	for (let i = 0, len = uint8Array.length; i < len; ++i) {
		view[i] = uint8Array[i];  // ビューに元のTypedArrayの中身をコピー
	}
	return arrayBuffer;
}
Uint16Array
function uint16ArrayToArrayBuffer(uint16Array) {
	const arrayBuffer = new ArrayBuffer(uint16Array.length * 2);
	const view = new Uint16Array(arrayBuffer);
	for (let i = 0, len = uint16Array.length; i < len; ++i) {
		view[i] = uint16Array[i];
	}
	return arrayBuffer;
}
Uint32Array
function uint32ArrayToArrayBuffer(uint32Array) {
	const arrayBuffer = new ArrayBuffer(uint32Array.length * 4);
	const view = new Uint32Array(arrayBuffer);
	for (let i = 0, len = uint32Array.length; i < len; ++i) {
		view[i] = uint32Array[i];
	}
	return arrayBuffer;
}

Uint8Array → Uint16Array|Uint32Array

手動で変換できますが、バイトオーダーを気にする必要があります。

例えば Uint8Array([0x11, 0x22, 0xAA, 0xBB])Uint16Array に変換する場合、リトルエンディアンとして扱えば Uint16Array([0x2211, 0xBBAA]) に、ビッグエンディアンとして扱えば Uint16Array([0x1122, 0xAABB]) になります。

同様に Uint8Array([0x11, 0x22, 0xAA, 0xBB])Uint32Array に変換する場合、リトルエンディアンとして扱えば Uint16Array([0xBBAA2211]) に、ビッグエンディアンとして扱えば Uint16Array([0x1122AABB]) になります。

Uint8Array → Uint16Array
/**
 * Uint8Array → Uint16Array
 * @param {*} uint8Array 
 * @param {*} byteOrder BE|LE
 */
function uint8ArrayToUint16Array(uint8Array, byteOrder = 'LE') {
	const len = uint8Array.length;
	if (len % 2 > 0) {
		throw new Error('Uint8Arrayの長さが2の倍数ではありません。');
	}
	const uint16Array = new Uint16Array(len / 2);
	if (byteOrder.toUpperCase() == 'LE') {
		for (let i = 0, j = 0; i < len; ++i) {
			const mod = i % 2;
			if      (mod == 0) { uint16Array[j] += uint8Array[i]; }
			else if (mod == 1) { uint16Array[j] += uint8Array[i] << 8; ++j; }
		}
	} else {
		for (let i = 0, j = 0; i < len; ++i) {
			const mod = i % 2;
			if      (mod == 0) { uint16Array[j] += uint8Array[i] << 8; }
			else if (mod == 1) { uint16Array[j] += uint8Array[i]; ++j; }
		}
	}
	return uint16Array;
}
Uint8Array → Uint32Array
/**
 * Uint8Array → Uint32Array
 * @param {*} uint8Array 
 * @param {*} byteOrder BE|LE
 */
function uint8ArrayToUint32Array(uint8Array, byteOrder = 'LE') {
	const len = uint8Array.length;
	if (len % 4 > 0) {
		throw new Error('Uint8Arrayの長さが4の倍数ではありません。');
	}
	const uint32Array = new Uint32Array(len / 4);
	if (byteOrder.toUpperCase() == 'LE') {
		for (let i = 0, j = 0; i < len; ++i) {
			const mod = i % 4;
			if      (mod == 0) { uint32Array[j] += uint8Array[i]; }
			else if (mod == 1) { uint32Array[j] += uint8Array[i] << 8; }
			else if (mod == 2) { uint32Array[j] += uint8Array[i] << 16; }
			else if (mod == 3) { uint32Array[j] += uint8Array[i] << 24; ++j; }
		}
	} else {
		for (let i = 0, j = 0; i < len; ++i) {
			const mod = i % 4;
			if      (mod == 0) { uint32Array[j] += uint8Array[i] << 24; }
			else if (mod == 1) { uint32Array[j] += uint8Array[i] << 16; }
			else if (mod == 2) { uint32Array[j] += uint8Array[i] << 8; }
			else if (mod == 3) { uint32Array[j] += uint8Array[i]; ++j; }
		}
	}
	return uint32Array;
}

Uint16Array|Uint32Array → Uint8Array

ほぼ同上です。これも手動で変換できますが、バイトオーダーを気にする必要があります。

例えば Uint16Array([0x1122, 0xAABB]) を変換する場合、リトルエンディアンとして扱えば Uint8Array([0x22, 0x11, 0xBB, 0xAA]) に、ビッグエンディアンとして扱えば Uint8Array([0x11, 0x22, 0xAA, 0xBB]) になります。

同様に Uint32Array([0x1122AABB]) を変換する場合、リトルエンディアンとして扱えば Uint8Array([0xBB, 0xAA, 0x22, 0x11]) に、ビッグエンディアンとして扱えば Uint8Array([0x11, 0x22, 0xAA, 0xBB]) になります。

Uint16Array → Uint8Array
/**
 * Uint16Array → Uint8Array
 * @param {*} uint16Array 
 * @param {*} byteOrder BE|LE
 */
function uint16ArrayToUint8Array(uint16Array, byteOrder = 'LE') {
	const len = uint16Array.length;
	const uint8Array = new Uint8Array(len * 2);
	if (byteOrder.toUpperCase() == 'LE') {
		for (let i = 0, j = 0; i < len; ++i, j += 2) {
			uint8Array[j]     =  uint16Array[i] & 0x00ff;
			uint8Array[j + 1] = (uint16Array[i] & 0xff00) >> 8;
		}
	} else {
		for (let i = 0, j = 0; i < len; ++i, j += 2) {
			uint8Array[j]     = (uint16Array[i] & 0xff00) >> 8;
			uint8Array[j + 1] =  uint16Array[i] & 0x00ff;
		}
	}
	return uint8Array;
}
Uint32Array → Uint8Array
/**
 * Uint32Array → Uint8Array
 * @param {*} uint32Array 
 * @param {*} byteOrder BE|LE
 */
function uint32ArrayToUint8Array(uint32Array, byteOrder = 'LE') {
	const len = uint32Array.length;
	const uint8Array = new Uint8Array(len * 4);
	if (byteOrder.toUpperCase() == 'LE') {
		for (let i = 0, j = 0; i < len; ++i, j += 4) {
			uint8Array[j]     =  uint32Array[i] & 0x000000ff;
			uint8Array[j + 1] = (uint32Array[i] & 0x0000ff00) >> 8;
			uint8Array[j + 2] = (uint32Array[i] & 0x00ff0000) >> 16;
			uint8Array[j + 3] = (uint32Array[i] & 0xff000000) >> 24;
		}
	} else {
		for (let i = 0, j = 0; i < len; ++i, j += 4) {
			uint8Array[j]     = (uint32Array[i] & 0xff000000) >> 24;
			uint8Array[j + 1] = (uint32Array[i] & 0x00ff0000) >> 16;
			uint8Array[j + 2] = (uint32Array[i] & 0x0000ff00) >> 8;
			uint8Array[j + 3] =  uint32Array[i] & 0x000000ff;
		}
	}
	return uint8Array;
}

ArrayBuffer → Buffer

普通に Buffer.from() を使います。

function arrayBufferToBuffer(arrayBuffer) {
	return Buffer.from(arrayBuffer);
}

Buffer → ArrayBuffer

ArrayBuffer を参照するビューを作成して、その中に Buffer の内容をコピーする必要があります。

function bufferToArrayBuffer(buffer) {
	const arrayBuffer = new ArrayBuffer(buffer.length);
	const uint8Array = new Uint8Array(arrayBuffer);  // ArrayBufferを参照するTypedArray (ビュー) を作成
	for (let i = 0, len = buffer.length; i < len; ++i) {
		uint8Array[i] = buffer[i];  // ビューにBufferの中身をコピー
	}
	return arrayBuffer;
}

Buffer → TypedArray

いずれかの TypedArray コンストラクタを使います。ここでは例として Uint8Array を使いました。

function bufferToUint8Array(buffer) {
	return new Uint8Array(buffer);
}

TypedArray → Buffer

普通に Buffer.from() を使います。

function typedArrayToBuffer(typedArray) {
	return Buffer.from(typedArray);
}

文字列 → Blob (UTF-8)

Blob コンストラクタを使います。

上述の方法で ArrayBuffer にしてみると分かりますが、この時 Blob が保持するバイト列はUTF-8になってます。なのでJavaScriptの内部文字コードはUTF-16ですが、この方法で生成した Blob をダウンロードすると文字コードはUTF-8です。

function stringToBlob(str) {
	return new Blob([str], { type : 'text/plain' });
}

文字列 → ArrayBuffer (UTF-8)

文字列を Blob に変換するとUTF-8になるのを利用します。

function stringToArrayBufferUTF8(str, callback) {
	const blob = new Blob([str], {type : 'text/plain'});
	const reader = new FileReader();
	reader.addEventListener('load', function(event) {
		const arrayBuffer = event.target.result;
		callback(arrayBuffer);
	});
	reader.readAsArrayBuffer(blob);
}

ArrayBuffer (UTF-8) → 文字列

JavaScriptの内部文字コードはUTF-16ですが、Ajaxの戻りなどでUTF-8のバイト列が手元にある場合にデコードする方法です。以下の記事を参考にさせていただきました。

UTF-8のバイナリ文字列を escape() でURLエンコードした後、decodeURIComponent() で戻すと行けるみたいです。なお、escape() は標準機能ではなくなったそうなので、ここでは自前で移植したものを使っています。

function arrayBufferUTF8ToString(arrayBuffer) {
	const myescape = (str) => {
		// escape() の代わり
		return str.replace(/[^a-zA-Z0-9@*_+\-./]/g, function(m) {
			const code = m.charCodeAt(0);
			if (code <= 0xff) {
				return '%' + ('00' + code.toString(16)).slice(-2).toUpperCase();
			} else {
				return '%u' + ('0000' + code.toString(16)).slice(-4).toUpperCase();
			}
		});
	};
	const uint8Array = new Uint8Array(arrayBuffer);
	const binStr = String.fromCharCode(...uint8Array);
	return decodeURIComponent(myescape(binStr));
}

文字列 → Buffer

Buffer.from() を使います。デフォルトのエンコーディングはUTF-8です。

function stringToBuffer(str) {
	return Buffer.from(str, 'utf-8');
}

Blob → Base64文字列

FileReaderreadAsDataURL() で生成したDataURLから、Base64文字列の部分 (最初のカンマ以降) を切り出して使います。onload イベントを待つので非同期です。

function blobToBase64String(blob, callback) {
	const reader = new FileReader();
	reader.addEventListener('load', (event) => {
		const dataUrl = event.target.result;
		callback(dataUrl.substr(dataUrl.indexOf(',') + 1));
	});
	reader.readAsDataURL(blob);
}

Base64文字列 → バイナリ文字列

atob() を使います。

function base64StringToBinaryString(base64Str) {
	return atob(base64Str);
}

バイナリ文字列 → Base64文字列

btoa() を使います。

function binaryStringToBase64String(binStr) {
	return btoa(binStr);
}

バイナリ文字列 → Blob

Blob コンストラクタを使います。

function binaryStringToBlob(binStr) {
	return new Blob(binStr, { type: 'application/octet-binary' });
}

バイナリ文字列 → Uint8Array

StringcharCodeAt() を使って、文字列を1文字ずつコード値に変換します。

バイナリ文字列なので Uint8Array を使ってます。普通の文字列にはあっちを使ってください。

function binaryStringToUint8Array(str) {
	const newArr = [];
	for (let i = 0, len = str.length; i < len; ++i) {
		const code = str.charCodeAt(i);
		if (code < 0 || 255 < code) {
			throw new Error('文字コードが 0 ~ 255 の範囲外の文字が含まれています。');
		}
		newArr[i] = code;
	}
	return Uint8Array.from(newArr);
}

Uint8Array → バイナリ文字列

全部いっぺんに String.fromCharCode() に渡して変換できます。

function uint8ArrayToBinaryString(uint8Array) {
	return String.fromCharCode(...uint8Array);
}

文字列 → Uint16Array

JavaScriptの内部文字コードはUTF-16 (コード値 0 ~ 65535) なので、Uint16Array なら格納できます。

function stringToUint16Array(str) {
	const newArr = [];
	for (let i = 0, len = str.length; i < len; ++i) {
		newArr[i] = str.charCodeAt(i);
	}
	return Uint16Array.from(newArr);
}

Uint16Array → 文字列

全部いっぺんに String.fromCharCode() に渡して変換します。いっぺんに渡さないと、サロゲートペア使用文字がちゃんと戻りません。

function uint16ArrayToString(uint16Array) {
	return String.fromCharCode(...uint16Array);
}

Blob → Image

Blob の画像データを <img>src に使えます。オブジェクトURLを使う方法とデータURLを使う方法があります。どちらも onload イベントを待つので非同期です。

オブジェクトURLの場合は、URL.createObjectURL() を使います。

function blobToImage(blob, callback) {
	const img = new Image();
	img.src = URL.createObjectURL(blob);
	img.addEventListener('load', (event) => {
		callback(img);
	});
}

データURLを使う場合は、下記のコードです。

function blobToImage(blob, callback) {
	const reader = new FileReader();
	reader.addEventListener('load', (event) => {
		const img = new Image();
		img.src = event.target.result;
		img.addEventListener('load', (event) => {
			callback(img);
		});
	});
	reader.readAsDataURL(blob);
}

Image → Canvas

変換というかですが、Canvasにそのまま描画してしまいます。コンテキストの drawImage() を使います。

function imageToCanvas(img) {
	const canvas = document.createElement('canvas');
	canvas.width = img.width;
	canvas.height = img.height;
	const ctx = canvas.getContext('2d');
	ctx.drawImage(img, 0, 0);
	return canvas;
}

Canvas → Image

Canvasの toDataURL() を使います。onload イベントを待つので非同期です。

function canvasToImage(img, type, callback) {
	type = type === undefined ? 'image/png' : type;
	const img = new Image();
	img.src = canvas.toDataURL(type);
	img.addEventListener('load', (event) => {
		callback(img);
	});
}

Canvas → Blob

Canvasの toBlob() を使えば一発です。toBlob() は非同期の関数で、コールバックに Blob が渡されます。

function canvasToBlob(canvas, callback) {
	canvas.toBlob(callback);
}

Canvas → Base64文字列

Canvasの toDataURL() で生成したDataURLから、Base64文字列の部分を切り出して使います。

function canvasToBase64String(canvas, type) {
	type = type === undefined ? 'image/png' : type;
	const dataUrl = canvas.toDataURL(type);
	return dataUrl.substr(dataUrl.indexOf(',') + 1);
}