🖨️

Flet で証明写真をL判に割り付けるアプリを作ってみる

2023/01/23に公開約3,200字

毎回忘れて Gimp と格闘しているのでツール化。せっかくなので最近話題の Flet を使ってみます。

できたもの

https://github.com/AWtnb/flet_4up_idphoto


Python しか書いていないのに GUI が!


L判に4枚割り付けます

手順の振り返り

割り付け処理

画像処理には Pillow を使います。事前に pip install しておきましょう。

処理の該当部分 にコメントで加筆するとこんな感じです。

# 保存時の名前を作るための関数
def with_stem_tail(path:str, tail:str) -> str:
    target = Path(path)
    return str(target.stem + tail + target.suffix)

# メイン処理。対象ファイルのパスと出力先、印刷時の証明写真の幅、出力ファイルのサイズ上限を指定。
def allocate(path:str, out_dir:str, photo_width_mm:int=30, max_frame_width:int=2000):
    # 保存先のパス
    out_path = Path(out_dir, with_stem_tail(path, "_print"))

    # 画像とその情報を読み込む
    img = Image.open(path)
    img_width, img_height = img.size

    # 証明写真が印刷時に何mmになるかを基準に、台紙となる画像のサイズを計算する
    frame_width = int(img_width * 89 / int(photo_width_mm)) # L判は幅89mm
    frame_height = int(frame_width * 1.43) # L判の縦横比

    # 台紙となる白画像を生成
    frame = Image.new("RGB", (frame_width, frame_height), (255,255,255))

    # 台紙の5%は余白を開けたい
    margin_x = int(frame_width * 0.05)
    margin_y = int(frame_height * 0.05)

    # 証明写真を四隅に乗せていく
    for x in (margin_x, (frame_width - img_width - margin_x)):
        for y in (margin_y, frame_height - img_height - margin_y):
            frame.paste(img, (x, y))

    # 証明写真のサイズが大きいと台紙のサイズが巨大になりファイルサイズも膨れ上がるので最大ピクセルを超える場合にリサイズ
    if frame.width > max_frame_width:
        frame = frame.resize((max_frame_width, int(frame.height * max_frame_width / frame_width)))

    # 保存
    frame.save(out_path, quality=95)

GUI 部分

公式ドキュメント が親切です。

pip install flet でインストールしたら、main 関数の中にひと通りの命令を書いて GUI を定義し、最後に .app() で呼び出します。

以下、 import flet as ft とした前提で書いていきます。

レイアウトの考え方

  • ft.Row(controls=[]) に渡されたコントロールは横並びの「行」として扱われる
  • 行をさらにリストに格納して ft.Column(controls=[]) に渡すことで縦並びの「列」となる

簡単なアプリであれば、処理ごとに行を作っていき、最後に列にまとめて page.add() するという書き方が一番楽そうです。

コントロールの Ref は、こうして最後にまとめて page に追加するケースを考えると理解が進むかもしれません。

ダイアログ関連

  1. ダイアログの処理が完了したときに呼ばれる処理を用意してから、
  2. ダイアログのコントロールを作って、
  3. ダイアログを表示する関数を用意し、
  4. ボタンのコントロールから呼び出せるようにする

という手順で作るので少し直観に反しているような気もします。

https://github.com/AWtnb/flet_4up_idphoto/blob/a67b0fe9dad3e022938c5481a5d123d21011194a/main.py#L43-L67

ここで、 page.overlay.append(file_picker) としなくてはいけない理由が最初はわからなかったのですが、試しにコメントアウトしてみると下記のエラー。

Exception: Control must be added to the page first.

どうやらコントロールはすべて page に何かしらの形で紐づけておかなくてはいけないようです。

単一バイナリに書き出す

python main.py

で実行して問題ないようなら、exe 形式で書き出しましょう。

下記コマンドを実行するとビルド処理が走り、 builddist というディレクトリが作られます。

flet pack main.py --name (好きなファイル名).exe

dist 内に最終的なバイナリファイルが生成されます。

Discussion

ログインするとコメントできます