File size: 5,664 Bytes
4616fe0
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
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
    )