<< 2024-08-26 | 2024-08-28 >> DailyNote データ拡張ツールがあんまり落ちてないので、とりあえず回転だけさせるツールを作った。 import streamlit as st import os import zipfile from PIL import Image import tempfile import io import base64 def rotate_image(image, angle): width, height = image.size new_size = int(((width ** 2 + height ** 2) ** 0.5)) result = Image.new('RGBA', (new_size, new_size), (0, 0, 0, 0)) paste_x = (new_size - width) // 2 paste_y = (new_size - height) // 2 result.paste(image, (paste_x, paste_y)) result = result.rotate(angle, expand=True) bbox = result.getbbox() result = result.crop(bbox) return result def process_images(uploaded_files, rotation_steps): processed_images = [] total_files = len(uploaded_files) progress_bar = st.progress(0) status_text = st.empty() with tempfile.TemporaryDirectory() as temp_dir: for i, uploaded_file in enumerate(uploaded_files): status_text.text(f"ファイル {i + 1}/{total_files} を処理中...") if uploaded_file.name.endswith('.zip'): with zipfile.ZipFile(uploaded_file, 'r') as zip_ref: zip_ref.extractall(temp_dir) else: img = Image.open(uploaded_file) img.save(os.path.join(temp_dir, uploaded_file.name)) progress_bar.progress((i + 1) / total_files) with tempfile.TemporaryDirectory() as output_dir: total_images = len( [f for f in os.listdir(temp_dir) if f.lower().endswith(('.png', '.jpg', '.jpeg', '.gif', '.bmp'))]) for i, filename in enumerate(os.listdir(temp_dir)): if filename.lower().endswith(('.png', '.jpg', '.jpeg', '.gif', '.bmp')): status_text.text(f"画像 {i + 1}/{total_images} を回転中...") img_path = os.path.join(temp_dir, filename) img = Image.open(img_path) if img.mode != 'RGBA': img = img.convert('RGBA') for step in rotation_steps: angle = step * 22.5 rotated_img = rotate_image(img, angle) save_filename = f"rotated_{step}_{os.path.splitext(filename)[0]}.png" save_path = os.path.join(output_dir, save_filename) rotated_img.save(save_path, "PNG") thumbnail = rotated_img.copy() thumbnail.thumbnail((100, 100)) processed_images.append((save_filename, thumbnail)) progress_bar.progress((i + 1) / total_images) status_text.text("ZIPファイルを作成中...") output_zip = "processed_images.zip" with zipfile.ZipFile(output_zip, 'w') as zipf: for root, dirs, files in os.walk(output_dir): for file in files: zipf.write(os.path.join(root, file), file) status_text.text("処理完了!") progress_bar.progress(1.0) return output_zip, processed_images st.set_page_config(layout="wide") st.title("画像回転ツール (1/16回転)") # サイドバーに回転設定を配置 with st.sidebar: st.header("回転設定") all_steps = list(range(16)) rotation_steps = st.multiselect( "回転ステップを選択してください", options=all_steps, default=[4], format_func=lambda x: f"{x}/16回転 ({x * 22.5}度)" ) uploaded_files = st.file_uploader("画像またはZIPファイルをアップロードしてください", accept_multiple_files=True) if st.button("処理開始"): if uploaded_files and rotation_steps: output_zip, processed_images = process_images(uploaded_files, rotation_steps) with open(output_zip, "rb") as file: st.download_button( label="処理済み画像をダウンロード", data=file, file_name="processed_images.zip", mime="application/zip" ) # st.header("処理済み画像のプレビュー") # # # サムネイルを3列で表示 # cols = st.columns(3) # for idx, (filename, thumbnail) in enumerate(processed_images): # with cols[idx % 3]: # # サムネイルの背景を設定 # st.markdown( # f""" # <div style=" # background-color: #f0f0f0; # border: 1px solid #ddd; # border-radius: 5px; # padding: 10px; # margin-bottom: 10px; # text-align: center; # "> # <img src="data:image/png;base64,{base64.b64encode(thumbnail.tobytes()).decode()}" style="max-width: 100%; height: auto;"> # <p style="margin-top: 5px; font-size: 12px;">{filename}</p> # </div> # """, # unsafe_allow_html=True # ) os.remove(output_zip) else: st.warning("ファイルをアップロードし、少なくとも1つの回転ステップを選択してください。")