掲示板<30>2026/1/19
from=TOZ

Pythonを利用⑦「size_table_html_v8.py」

ホームページを自動作成するプログラムを作りました。 (1)最初に写真を多数入れたフォルダーを作ります。 (2)プログラムを実行します。端末で「python3 size_table_html_v8.py」    を起動します。 (3)問に応じて答えていきます。 (4)書き出しを指定したフォルダーに完成しています。 (5)説明文を入れるために、最初の写真の入ったフォルダーにあるcsvファイル    のB列に書き込み保存します。 (6)もう一度(2)から(4)をくりかえします。 (7)説明文の入ったHTMLが書き出し指定のフォルダーに完成します。 ホームページのタグの関係で、プログラム中の「<」「>」は全角表示しています。
import os
import glob
import csv
import tkinter as tk
from tkinter import filedialog, messagebox, simpledialog
from PIL import Image

def create_gallery_final():
    root = tk.Tk()
    root.withdraw()

    # 1. フォルダの選択
    messagebox.showinfo("選択", "1. 元画像が入っているフォルダを選択してください")
    input_dir = filedialog.askdirectory(title="入力フォルダを選択")
    if not input_dir: return

    folder_name = os.path.basename(os.path.normpath(input_dir))
    index_filename = f"{folder_name}.html"
    csv_path = os.path.join(input_dir, "image_descriptions.csv")

    messagebox.showinfo("選択", "2. 保存先(HTML・リサイズ画像)フォルダを選択してください")
    output_dir = filedialog.askdirectory(title="出力先フォルダを選択")
    if not output_dir: return

    # --- 列数の指定 ---
    num_cols = simpledialog.askinteger("列数設定", "一覧表の列数を入力してください(例: 3 や 4):", initialvalue=2, minvalue=1)
    if not num_cols: num_cols = 2

    # 上の階層へのリンク情報の入力
    parent_page_name = simpledialog.askstring("戻り先設定", "上の階層のボタン名:", initialvalue="トップページへ戻る")
    parent_page_url = simpledialog.askstring("戻り先設定", "上の階層のURL:", initialvalue="../index.html")

    # 2. 画像ファイルの取得
    valid_extensions = (".jpg", ".jpeg", ".png", ".bmp", ".webp")
    images = []
    for ext in valid_extensions:
        images.extend(glob.glob(os.path.join(input_dir, f"*{ext}")))
        images.extend(glob.glob(os.path.join(input_dir, f"*{ext.upper()}")))
    images = sorted(list(set(images)))

    if not images:
        messagebox.showwarning("エラー", "画像が見つかりませんでした。")
        return

    # 3. CSVファイルの処理 (説明文の読み込み)
    descriptions = {}
    if not os.path.exists(csv_path):
        with open(csv_path, 'w', encoding='utf-8-sig', newline='') as f:
            writer = csv.writer(f)
            writer.writerow(["ファイル名", "説明文"])
            for img_path in images:
                writer.writerow([os.path.basename(img_path), ""])
        messagebox.showinfo("CSV作成", "説明入力用のCSVを作成しました。記入後、再実行で反映されます。")
    else:
        with open(csv_path, 'r', encoding='utf-8-sig') as f:
            reader = csv.reader(f)
            next(reader)
            for row in reader:
                if len(row) >= 2: descriptions[row[0]] = row[1]

    # 4. 基本タイトルの入力とサイズ
    base_title = simpledialog.askstring("タイトル", "ページ全体のタイトル:", initialvalue=folder_name)
    target_width = simpledialog.askinteger("サイズ", "画像保存幅(px):", initialvalue=1200)
    index_display_width = simpledialog.askinteger("サイズ", "一覧表示の最大幅(px):", initialvalue=400)

    processed_data = []

    # 5. 画像処理と個別HTML生成
    for i, img_path in enumerate(images, 1):
        fname = os.path.basename(img_path)
        base_file_name = os.path.splitext(fname)[0]
        desc_text = descriptions.get(fname, f"{base_title}-{i}")

        try:
            with Image.open(img_path) as img:
                w, h = img.size
                resized = img.resize((target_width, int(h * (target_width / w))), Image.Resampling.LANCZOS)
                resized.save(os.path.join(output_dir, fname))

            single_html = f"""<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <title>{desc_text}</title>
    <style>
        body {{ text-align: center; font-family: sans-serif; background: #eee; padding: 40px; }}
        img {{ width: 100%; max-width: 900px; border: 8px solid #fff; box-shadow: 0 0 10px rgba(0,0,0,0.1); }}
        .desc {{ margin: 20px; font-size: 1.5em; font-weight: bold; }}
        a {{ text-decoration: none; color: #007bff; font-weight: bold; border: 1px solid; padding: 10px 20px; border-radius: 5px; background: #fff; }}
    </style>
</head>
<body>
    <div class="desc">{desc_text}</div>
    <img src="{fname}">
    <div style="margin-top:30px;"><a href="{index_filename}">一覧に戻る</a></div>
</body>
</html>"""
            with open(os.path.join(output_dir, f"{base_file_name}.html"), "w", encoding="utf-8") as f:
                f.write(single_html)
            processed_data.append((fname, base_file_name, desc_text))
        except: pass

    # 6. 一覧HTML生成 (列数に合わせて幅を自動計算)
    col_width = 100 / num_cols
    index_html = f"""<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <title>{base_title}</title>
    <style>
        body {{ font-family: sans-serif; background: #f4f4f4; padding: 20px; }}
        .header {{ text-align: center; margin-bottom: 30px; }}
        .parent-nav {{ margin-bottom: 20px; }}
        .parent-nav a {{ text-decoration: none; color: #666; border: 1px solid #ccc; padding: 5px 15px; background: #fff; }}
        table {{ width: 100%; border-collapse: collapse; background: #fff; }}
        td {{ border: 1px solid #eee; padding: 15px; text-align: center; vertical-align: top; width: {col_width}%; }}
        img {{ width: 100%; max-width: {index_display_width}px; height: auto; }}
        .caption {{ margin-top: 10px; font-size: 13px; font-weight: bold; }}
    </style>
</head>
<body>
    <div class="parent-nav"><a href="{parent_page_url}">← {parent_page_name}</a></div>
    <div class="header"><h1>{base_title}</h1></div>
    <table>"""
    
    # 指定された列数 (num_cols) でループ
    for i in range(0, len(processed_data), num_cols):
        index_html += "<tr>"
        for j in range(num_cols):
            if i + j < len(processed_data):
                f, b, d = processed_data[i+j]
                index_html += f'<td><a href="{b}.html"><img src="{f}"><div class="caption">{d}</div></a></td>'
            else:
                index_html += "<td></td>"
        index_html += "</tr>"

    index_html += "</table></body></html>"

    with open(os.path.join(output_dir, index_filename), "w", encoding="utf-8") as f:
        f.write(index_html)
    messagebox.showinfo("完了", f"{num_cols}列構成で作成しました。")

if __name__ == "__main__":
    create_gallery_final()


← 一覧へ戻る