はじめに
- Webブラウザ上に画像を表示したいとき、通常であればサーバーに保存した画像のファイルパスをフロントに渡すことで表示を行うかと思います。
- しかし、ファイルパスではなく画像そのものをフロントに渡してブラウザ上に表示したいことがあるかもしれません。(まあ、あんまりないですよね。僕はあったので書いているわけですが。)
- そこで今回は画像をファイルパスではなくデータとしてフロントに渡す方法を解説します。
- 具体的には、サーバーに保存した画像をFlaskでJavaScriptに渡し、HTMLに埋め込むまでの流れを説明します。
環境
バックエンド:Flask
フロント:JavaScript・HTML
手順
- サーバーサイドに画像を用意
- FlaskからJavaScriptに画像を渡す
- JavaScriptで画像を受け取りHTMLで表示
1. サーバーサイドに画像を用意
- 何らかの方法で用意した画像ファイルが既にサーバーに保存されている前提で話を進めます。
- static/images こんな感じで画像フォルダがある想定です。
2. FlaskからJavaScriptに画像を渡す
- バックエンド(Flaskサイド)からフロント(JavaScript)に画像データを渡すサンプルプログラムです。
- ちなみにバックフロント間のデータの受け渡しはJSON形式が望ましいです。詳しくはこちらの記事を参照してください。
@app.route('/get-images')
def get_images():
images_folder = 'static/images' # 画像が保存されているフォルダのパス
encoded_images = []
for filename in os.listdir(images_folder):
if filename.endswith(('.png', '.jpg')):
with open(os.path.join(images_folder, filename), 'rb') as image_file:
encoded_string = base64.b64encode(image_file.read()).decode()
encoded_images.append(encoded_string)
return jsonify({'encoded_images' : encoded_images})
コード解説
-
@app.route('/get-images'): これはFlaskのデコレータで、特定のURLパス(この場合は/get-images)にHTTPリクエストが来たときに、直下に定義されている関数を呼び出すように設定しています。
-
def get_images(): get_imagesという名前の関数を定義しています。この関数が/get-imagesのエンドポイントにリクエストがあったときに呼び出されます。
-
images_folder = 'static/images': static/imagesというパスを画像が保存されているフォルダとして指定しています。このパスはサーバー上のフォルダを指します。
-
encoded_images = []: Base64エンコードされた画像データを格納するための空のリストを初期化しています。
-
for filename in os.listdir(images_folder): images_folderで指定されたフォルダ内のファイル名を反復処理するループを開始します。
-
if filename.endswith(('.png', '.jpg')):: ファイル名が.pngまたは.jpgで終わるかどうかをチェックします。これにより、画像ファイルのみを処理するようにしています。
-
with open(os.path.join(images_folder, filename), 'rb') as image_file:: 画像ファイルをバイナリ読み取りモード('rb')で開きます。os.path.joinはフォルダ名とファイル名を結合してフルパスを生成します。
-
encoded_string = base64.b64encode(image_file.read()).decode(): 画像ファイルを読み込み、Base64形式でエンコードします。その後、得られたバイト列をデコードして文字列に変換します。
-
encoded_images.append(encoded_string): Base64エンコードされた画像データをencoded_imagesリストに追加します。
-
return jsonify({'encoded_images' : encoded_images}): encoded_imagesリストを含む辞書をJSON形式でレスポンスとして返します。これにより、Webクライアントはこのエンドポイントから画像データを取得できます。
3. JavaScriptで画像を受け取りHTMLで表示
Flaskから画像データを取得する
fetch("/get-images")
.then((response) => response.json())
.then((data) => {
const images = data.encoded_images;
images.forEach(base64Image => {
// 新しいimg要素を作成
const img = document.createElement('img');
// src属性をBase64文字列に設定
img.src = 'data:image/jpeg;base64,' + base64Image;
// img要素をDOMに追加(例えばbodyの最後に)
document.body.appendChild(img);
});
});
コード解説
- fetchを使ってサーバーからデータを取得し、JSON形式で解析
- 解析したデータからBase64エンコードされた画像の配列を取得
- 各画像データに対して、新しい要素を作成
- 要素のsrc属性をBase64文字列に設定します。ここで、data:image/jpeg;base64,のプレフィックスを追加することで、ブラウザがこの文字列を画像データとして解釈できる。
- 最後に、この要素をDOMに追加します。ここでは例としてdocument.bodyの子要素として追加していますが、他の要素に追加することも可能。
補足
fetchについては改訂3版JavaScript本格入門 ~モダンスタイルによる基礎から現場での応用までp544からの説明が最もわかりやすかった。この本はJavaScriptを使う人は持っておくと必ず役に立つと思います。
本持ってない人用に fetch 要約
~本格入門より~
- fetch API とは Single Page Application の核となる技術である。
- 覚えるべき基本イディオムは、fetch + then(レスポンス処理)+ then(結果処理)
// fetch 構文 サンプル
fetch('book.json')
.then(res => res.json())
.then(data => console.log(data.title))
2行目 jsonメソッドで応答データをJSON文字列として取得・解析。
3行目 jsonメソッドの戻り値はPromiseなのでこれをさらに処理する。
コールバック関数は今度は解析済みオブジェクトを受け取るのであとはそのtitleプロパティにアクセスして、console.logでログ出力という流れ。
参考