📷

<input type="file">で入力した画像をFastapiでImageオブジェクトとして扱う方法

2024/01/03に公開

ChatGPTを使って何とか正解にたどり着いたので、共有しようかと思います。

[Vue.js]フロントエンドで画像を入力するコンポーネントを作成する。

<template>タグ内

はじめにVueファイル内で画像を入力するためのコンポーネントを作成します。

modal-window,modal-buttonは独自で作成したものなので、この部分は各自でなんとかしてください。

main.vue
<template>
  <!-- 中略 -->
  <!-- modal-window:モーダルのウィンドウをつくるためのコンポーネント -->
  <!-- 詳細は省略する -->
  <modal-window>
    <p class="text-center text-xl underline py-3">Change thumbnails</p>
    <p class="text-center text-lg">Enter the thunbnail image of the folder named data02.</p>
    <input @change="InputThumbnailImage" class="mx-auto text-center" type="file" ref="thumbnail" accept=".jpg, .jpeg, .png, .webp, .bmp"/>
    <div v-if="PlannedInsertionThumbnail != null" class="flex justify-center items-center h-[150px]">
      <img class="max-w-full max-h-full" :src="PlannedInsertionThumbnail" alt="" srcset="">
    </div>
    <!-- modal-button:ボタンを横に2つ作成するコンポーネント-->
    <!-- click-itemでChengeボタンが押されたときのイベントを発動することが出来る -->
    <!-- ボタンがchangeなのは許して… -->
    <modal-button @click-item="ApplyModalButtonClick" :button-porps="[{name:'Change',hoverColor:'hover:bg-ApplyColor'},{name:'Cancel',hoverColor:'hover:bg-NormalButtonHover'}]"/>
  </modal-window>
  <!-- 中略 -->
</template>


作成したコンポーネントの画像

画像が入力された時の処理を書く

<input @change="InputThumbnailImage" class="mx-auto text-center" type="file" ref="thumbnail" accept=".jpg, .jpeg, .png, .webp, .bmp"/>

こちらのinputタグをいれることで画像を入力することができます。

ref="thumbnail"というのはscriptタグ上で入力された画像を取得するために必要なものです。

画像が入力することによってInputThumbnailImageという処理がされるのでmethodsの中にInputThumbnailImageの内容を記述します。

PlannedInsertionThumbnailはプレビュー画像のURLを定義しています。

main.vue
methods:{
  //中略
  InputThumbnailImage(){
    const thumbnail = (this.$refs.thumbnail as any).files[0] as any
    if (thumbnail) {
        // FileReaderを使用して画像を読み込む
        const reader = new FileReader();
        reader.onload = () => {
            // 読み込んだ画像をdataに設定
            this.PlannedInsertionThumbnail = reader.result as string;
        };
        reader.readAsDataURL(thumbnail);
    } else {
        // ファイルがない場合、画像をリセット
        this.PlannedInsertionThumbnail = null;
    }
  }
  //中略
}

この処理を記述することで画像が入力されたら入力した画像がプレビューとして表示されます。

this.$refs.thumbnailというのは先ほどのref="thumbnail"が書かれているタグを取得することを意味しています。
this.$refs.thumbnail.files[0]と書くことによって画像ファイルの情報が載っているFileオブジェクトを取得することができます。


作成したコンポーネントの画像

Changeボタンが押された時の処理を書く

main.vue
<modal-button @click-item="ApplyModalButtonClick" :button-porps="[{name:'Change',hoverColor:'hover:bg-ApplyColor'},{name:'Cancel',hoverColor:'hover:bg-NormalButtonHover'}]"/>

こちらのコンポーネントによって「Change」ボタンと「Cancel」ボタンを表示させることができます。

@click-itemはChangeボタンが押されたときに発動するイベントです。(@clickと同じものだと思ってもらって構いません。)

ApplyModalButtonClickにボタンが押された時の処理を記述します。

main.vue
async ApplyModalButtonClick(index:number){
  const thumbnail = this.$refs.thumbnail as any
  if (thumbnail.files[0] != undefined){
    // FormDataオブジェクトの作成
    const formData = new FormData();
    formData.append('image', thumbnail.files[0]);
    //FastApiと通信する
    //getLocalhostName()はhttp://127.0.0.1:8000と同じ意味
    const req = await this.axios.post(getLocalhostName() + "/api/folder-select/thumbnail",formData,{
      headers:{
        'Content-Type': 'multipart/form-data', // ファイルを送信する際には必要なヘッダー
      }
    })
    if (req.data["error"] == undefined){
      //画像がきちんと入力された時の処理
    } else {
      //エラーが発生したときの処理
    }
  }
},

FormDataオブジェクトインスタンスを作成して、そのオブジェクトに画像の情報を入れます。

[FastApi]バックエンドで入力された画像をImageオブジェクトに変更する。

「python-multipart」をインストールする。

Fastapi側でコードを記述する前に「python-multipart」をインストールします。

pip install python-multipart

POST処理を書く

main.py
from fastapi import FastAPI, File, UploadFile, Form
from .save_file_manager import SaveFileManager
	
app = FastAPI()
	
@app.post("/api/folder-select/thumbnail")
async def Folder_Select_Thumbnail(image: UploadFile = File()):
  try:
      manager = SaveFileManager()
      await manager.remake_thumbnail(image)
      return {"message":"Thumbnails have been set up!!!!"}
  except Exception as e:
      return {"error": traceback.format_exc()}	

今回は現在作成しているアプリの都合上、SaveFileManagerクラスでImageオブジェクトに変換する処理を記述しています。

SaveFileManagerクラスを書きます。

save_file_manager.py
from PIL import Image
from fastapi import UploadFile, File
import io

class SaveFileManager:
    def __init__(self):
	pass

    async def remake_thumbnail(self,image: UploadFile = File()):
	# 画像を読み込む
        content = await image.read()
	# Image.openで使用できるようにバイナリデータをメモリ内で扱うようにする。
	img_bin = io.BytesIO(content) 
        image = Image.open(img_bin)
        image.show()	

画像が表示できた!…かな…?

これで画像が表示されるようになるはずです。


画像が出てきた!!!

あとはご自由に

Imageオブジェクトとして扱えるようになったので、加工をしたりすることが出来るようになったはずです。

初投稿なので疲れました…

誰かほめて()

Discussion