import gradio as gr import numpy as np from PIL import Image import io import base64 def calculate_crop_box(image, target_ratio=1170/391): """ 計算保持目標比例的最大裁切框 """ width, height = image.size current_ratio = width / height if current_ratio > target_ratio: # 圖片較寬,需要裁切寬度 new_width = int(height * target_ratio) left = (width - new_width) // 2 top = 0 right = left + new_width bottom = height else: # 圖片較高,需要裁切高度 new_height = int(width / target_ratio) left = 0 top = (height - new_height) // 2 right = width bottom = top + new_height return (left, top, right, bottom) def process_image(image, crop_data=None): """ 處理圖片:裁切並調整為目標尺寸 """ if image is None: return None, "請上傳圖片" # 如果有裁切數據,使用用戶選擇的區域 if crop_data is not None: # Gradio 的 Image 組件在編輯模式下會返回包含裁切信息的數據 # 這裡我們處理裁切後的圖片 processed_image = image else: # 如果沒有裁切數據,自動計算最佳裁切區域 crop_box = calculate_crop_box(image) processed_image = image.crop(crop_box) # 調整為目標尺寸 target_size = (1170, 391) final_image = processed_image.resize(target_size, Image.Resampling.LANCZOS) return final_image, f"圖片已處理完成!尺寸:{final_image.size}" def auto_crop_preview(image): """ 自動裁切預覽 """ if image is None: return None, "請上傳圖片" crop_box = calculate_crop_box(image) cropped = image.crop(crop_box) # 創建預覽圖片,顯示裁切區域 preview = image.copy() from PIL import ImageDraw draw = ImageDraw.Draw(preview) # 繪製裁切框 draw.rectangle(crop_box, outline="red", width=3) return preview, f"建議裁切區域:{crop_box}" # 創建 Gradio 界面 with gr.Blocks(title="圖片裁切工具", theme=gr.themes.Soft()) as demo: gr.Markdown("# 🖼️ 圖片裁切工具") gr.Markdown("### 將任意尺寸的圖片按 1170:391 比例裁切並調整為目標尺寸") with gr.Row(): with gr.Column(scale=1): # 圖片上傳區域 input_image = gr.Image( label="上傳圖片", type="pil", height=400 ) # 按鈕區域 with gr.Row(): preview_btn = gr.Button("🔍 預覽裁切區域", variant="secondary") process_btn = gr.Button("✂️ 裁切並處理", variant="primary") with gr.Column(scale=1): # 輸出區域 output_image = gr.Image( label="處理後圖片", type="pil", height=400 ) # 狀態信息 status_text = gr.Textbox( label="狀態", value="等待圖片上傳...", interactive=False ) # 預覽功能 with gr.Row(): preview_image = gr.Image( label="裁切區域預覽(紅框顯示建議裁切區域)", type="pil", height=300, visible=False ) # 進階設置 with gr.Accordion("🔧 進階設置", open=False): gr.Markdown("### 目標尺寸設置") with gr.Row(): target_width = gr.Number( label="目標寬度", value=1170, precision=0 ) target_height = gr.Number( label="目標高度", value=391, precision=0 ) quality_slider = gr.Slider( label="輸出品質", minimum=1, maximum=100, value=95, step=1 ) # 使用說明 with gr.Accordion("📖 使用說明", open=False): gr.Markdown(""" ### 如何使用: 1. **上傳圖片**:點擊上傳區域選擇您的圖片 2. **預覽裁切**:點擊「預覽裁切區域」查看建議的裁切區域 3. **手動編輯**:在上傳的圖片上直接拖拽選擇裁切區域 4. **處理圖片**:點擊「裁切並處理」生成最終圖片 5. **下載結果**:右鍵點擊處理後的圖片選擇「另存為」 ### 功能特色: - ✨ 自動計算最佳裁切比例 - 🎯 支援手動選擇裁切區域 - 📏 保持 1170:391 的精確比例 - 🖼️ 高品質圖片輸出 - 💾 簡單的下載流程 """) # 事件綁定 preview_btn.click( fn=auto_crop_preview, inputs=[input_image], outputs=[preview_image, status_text] ).then( fn=lambda: gr.update(visible=True), outputs=[preview_image] ) process_btn.click( fn=process_image, inputs=[input_image], outputs=[output_image, status_text] ) # 當圖片上傳時自動更新狀態 input_image.change( fn=lambda img: "圖片已上傳,可以開始處理!" if img is not None else "請上傳圖片", inputs=[input_image], outputs=[status_text] ) # 啟動應用程式 if __name__ == "__main__": demo.launch( server_name="0.0.0.0", server_port=7860, share=True )