DBに画像ファイルを取り込んでおき、JSONとして画像をブラウザへ配信します。
このときクライアント側で画像ファイルにもどすことにつまづいたのでメモします。
成功事例
ChatGPTが教えてくれました。
uint8arrayで保存されているバイナリデータをJSONでarrayとして送るには
クライアント側で受け取ったUint8Arrayを画像データに変換するには、次の手順に従うことができます。以下の例では、JavaScriptを使用しています。
// 受け取ったUint8Array
var receivedData = new Uint8Array([/* 受け取ったデータを入力 */]);
// Uint8ArrayをBlobオブジェクトに変換
var blob = new Blob([receivedData], { type: 'image/jpeg' }); // typeを適切な画像形式に合わせて設定
// BlobオブジェクトをURLに変換
var imageUrl = URL.createObjectURL(blob);
// 画像要素を作成して表示
var imgElement = document.createElement('img');
imgElement.src = imageUrl;
document.body.appendChild(imgElement);
上記の例では、受け取ったUint8ArrayをBlobオブジェクトに変換します。Blobオブジェクトはバイナリデータを表現するためのオブジェクトであり、その後、URL.createObjectURLメソッドを使用してBlobオブジェクトをURLに変換します。
最後に、img要素を作成し、URLを設定して画像を表示することができます。この例では、画像要素をbody要素に追加していますが、表示方法は実際の使用環境に応じて変更してください。
この方法を使用すると、クライアント側で受け取ったUint8Arrayを画像として表示することができます。
気をつけるべきこと
サーバー側
JSONで送るとき、arrayにして送りましょう。Uint8Arrayのままではだめです。
理由は深く解説できないのですが…、
// ダメな例
let jsonData = {data: binaryData as Uint8Array}
// 良い例
jsonData = {data: Array.from(binaryData as Uint8Array)}
クライアント側
Uint8Arrayを作ってからBlobを作りましょう。
さらに、そのBlobをURLへ変換してユーザーにクリックさせればダウンロードできます。
具体的には
// ArrayからUint8Arrayへ変換
const array = new Uint8Array(data);
// Uint8ArrayからBlobへ変換
const blob = new Blob([array]);
// Blobをaタグへ埋め込み
const a = document.createElement("a");
// Blob オブジェクトをURLへ変換
a.href = URL.createObjectURL(blob)
a.download = "image.jpg";
a.textContent = "click to download";
ただし、Arrayとして送る方法はブラウザ互換(特にIEとかIEとかIEのこと)が保証されないそうです。しかしながらIEはもうとっくに死滅したと思われ、私の周囲では使用しない前提で開発していますので、ここはArrayで送る方法を採用しました。
下記、AIによる解説では互換性においてBase64を勧められています。
Base64を使う場合はサーバー側でArrayをUint8Arrayにして、クライアント側でその逆を行う必要があります。
base64?Uint8Array?
JSONに載せるバイナリデータはbase64?Uint8Arrayどちらがよい?
JSONにバイナリデータを載せる場合は、通常base64エンコード文字列が使われます。
Uint8Arrayはバイナリデータを直接含めることができますが、JSON仕様には含まれていないデータ型です。ブラウザ間の互換性などを考えるとbase64がおすすめです。
base64とUint8Arrayの主な違いは以下の通りです:
- base64: JSON仕様に含まれる文字列型で移 port・互換性が高い。データサイズが原データの約33%大きくなる。
- Uint8Array: バイナリデータを直接含められるため効率的。ただしブラウザ間でのサポート状況は不明。
一般的な用途ではbase64が最も安全な選択肢だと思います。
ブラウザ間互換性や他のシステムとのインタフェースを考慮する必要がない専用アプリケーションならUint8Arrayも可能性の1つです。
要件や利用シーンに合わせて両方の長短を比較検討して選択することをおすすめします。
失敗例
結果、15BのObject objectという文字列をダウンロードした。
JPEG画像をブラウザでダウンロードできるようにするには以下のようにします。
- サーバ側でJPEG画像を読み込み、Uint8Arrayに変換します。
const imageBuffer = fs.readFileSync(imagePath);
const imageArray = new Uint8Array(imageBuffer);
- imageArrayをJSONでエンコードします。
const imageData = JSON.stringify(imageArray);
- クライアントにimageDataを返却します。
- クライアント側では、 JSONからimageArrayを復元します。
const imageArray = JSON.parse(imageData);
- Blobオブジェクトを作成します。
const blob = new Blob([imageArray], {type: 'image/jpeg'});
- アンカータグでダウンロードリンクを作成します。
<a href= data:image/jpeg;base64,${btoa(blob)} download="image.jpg">
Download
</a>
- ユーザーがリンクをクリックするとブラウザによってJPEG画像がダウンロードされます。
この手順でサーバーからUint8Array画像データを受け取り、ブラウザで簡単にJPEG画像としてダウンロードできるようになります。