LoginSignup
0
0

More than 1 year has passed since last update.

サブフォルダを含むフォルダ内の画像をまとめてエクセルに貼り付け

Posted at

はじめに

以前、1つのファルダの複数画像を指定してエクセルファイルのA列に画像を貼り付けるコードを作成した↓
フォルダ内の画像をまとめてエクセルに貼り付け

指定したフォルダにサブフォルダがあった場合にサブフォルダの画像は選択できない問題あった。

なので、指定したフォルダにサブフォルダがある場合にはサブフォルダ内の画像も再帰的に検索して貼り付けるようにした。

仕様

・画像が存在するフォルダと貼り付け先のエクセルはGUIで選択
・画像をエクセルに貼り付ける際はフォルダごとに列を分けて貼り付ける
・エクセルの各列の1行目は貼り付ける画像のフォルダのパスを入力
・1つの画像を1つのセルに貼り付ける
・各画像が重ならないようにセルの高さと幅を調整
・貼り付け処理が終わったら「処理が完了しました」というダイアログで通知

コード

import tkinter as tk 
import tkinter.filedialog as fl 
import tkinter.messagebox as mb 
import openpyxl as px
import os
import glob

# 画像ファイルのpixelをエクセルのpixelに合わせるための補正係数
PIX_PER_CELL_HEIGH = 0.75
PIX_PER_CELL_WIDTH = 0.13

# ファイルダイアログを表示する初期ディレクトリ
INI_DIR = "D:/Python/Hello"

def get_file_paths(dir_path):
    # ディレクトリ内のファイル名取得(ファイル名のみの一覧を取得)
    file_names = os.listdir(dir_path)
    file_paths = [os.path.join(dir_path, file_name) for file_name in file_names if os.path.isfile(os.path.join(dir_path, file_name))] # ファイルかどうかを判定
    return file_paths

#GUIのボタンを押した時の処理
def get(*args):
    #CSVファイルを選択する ※複数選択可
    filetype = [('png file', '*.png'), ("jpg file",".jpg"), ('jpeg file', '*.jpeg')]
    root_dir = fl.askdirectory(initialdir=INI_DIR,
                                title="貼り付ける画像のディレクトリを選択")
    dir_paths = glob.glob(os.path.join(root_dir, '**' + os.sep), recursive=True)

    #保存用Excelファイル名を指定する
    typ = [("Excel", ".xlsx")]
    savefile = fl.asksaveasfilename(title="保存ファイル名を指定",
                                    filetypes=typ,
                                    initialdir=INI_DIR)

    #書き込み&グラフ描画用のExcelを新規作成
    wb = px.Workbook()

    #Excel内に新しいシートを作成してファイル名をつける
    wb.create_sheet(index=0, title='グラフ')
    ws = wb['グラフ']
    #自動で作成される不要なシートであるSheetを削除
    wb.remove(wb['Sheet'])

    # 各行のセルの高さを各列の最も大きい画像のサイズに合わせる。最大高さを保持する箱を初期化
    max_height = [18] # 1行目にはディレクトリのパスが入る。セルの高さはデフォルト値とする

    for dir_num, dir_path in enumerate(dir_paths, start=1):
        path_list = get_file_paths(dir_path)

        # 1行目にディレクトリのパスを記載
        ws.cell(row=1, column=dir_num).value = dir_path

        # 画像が重ならないようにするために画像の幅の最大値を保持する。そのための変数を初期化
        max_width = 0

        # 読み取った複数のCSVファイルを1つのExcelファイルにまとめる
        for i, path in enumerate(path_list, start=1): # 1行目はフォルダパスなので、画像を貼り付けるセルは2行目から
            # グラフの画像読み出し
            img = px.drawing.image.Image(path)

            # 画像を貼り付ける位置をExcel形式で表す(列のアルファベット+行の番号)
            inColLetter = px.utils.get_column_letter(dir_num) # 画像を貼り付ける列を指定
            inCellLetter = inColLetter + str(i+1) # 各ファイルの画像を重ならないように貼り付ける。+1はエクセルの行は1スタートのため

            ## 画像のサイズを取得して、セルの大きさを合わせる(画像同士が重ならないようにするため)
            # i行目の高さの最大値がリストに存在しなければ、挿入
            if i >= len(max_height):
                max_height.insert(i, img.height)
                ws.row_dimensions[i+1].height = max_height[i] * PIX_PER_CELL_HEIGH
            # セル高さ更新
            if img.height > max_height[i]:
                max_height[i] = img.height
                ws.row_dimensions[i+1].height = max_height[i] * PIX_PER_CELL_HEIGH
            # セル幅更新
            if img.width > max_width:
                max_width = img.width
                ws.column_dimensions[inColLetter].width = max_width * PIX_PER_CELL_WIDTH

            #シートにグラフを追加
            ws.add_image(img, inCellLetter)


    #Excelデータを保存
    wb.save(savefile + ".xlsx")

    #処理が完了したことをユーザーに知らせる
    mb.showinfo("確認","Excelファイルの作成が完了しました")
    message["text"] = "処理が完了しました"

## main処理
root = tk.Tk()

message = tk.Label(root, text="画像があるフォルダを選択してください", width=30)
message.grid(row=0, column=0)

button = tk.Button(text="開く", command=get)
button.grid(row=0, column=1)

root.mainloop()

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0