dseditor commited on
Commit
34acaea
·
verified ·
1 Parent(s): 4616fe0

Upload app.py

Browse files
Files changed (1) hide show
  1. app.py +107 -17
app.py CHANGED
@@ -3,6 +3,8 @@ import numpy as np
3
  from PIL import Image
4
  import io
5
  import base64
 
 
6
 
7
  def calculate_crop_box(image, target_ratio=1170/391):
8
  """
@@ -30,7 +32,7 @@ def calculate_crop_box(image, target_ratio=1170/391):
30
 
31
  def process_image(image, crop_data=None):
32
  """
33
- 處理圖片:裁切並調整為目標尺寸
34
  """
35
  if image is None:
36
  return None, "請上傳圖片"
@@ -49,7 +51,21 @@ def process_image(image, crop_data=None):
49
  target_size = (1170, 391)
50
  final_image = processed_image.resize(target_size, Image.Resampling.LANCZOS)
51
 
52
- return final_image, f"圖片已處理完成!尺寸:{final_image.size}"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
53
 
54
  def auto_crop_preview(image):
55
  """
@@ -71,6 +87,28 @@ def auto_crop_preview(image):
71
 
72
  return preview, f"建議裁切區域:{crop_box}"
73
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
74
  # 創建 Gradio 界面
75
  with gr.Blocks(title="圖片裁切工具", theme=gr.themes.Soft()) as demo:
76
  gr.Markdown("# 🖼️ 圖片裁切工具")
@@ -78,24 +116,46 @@ with gr.Blocks(title="圖片裁切工具", theme=gr.themes.Soft()) as demo:
78
 
79
  with gr.Row():
80
  with gr.Column(scale=1):
81
- # 圖片上傳區域
82
  input_image = gr.Image(
83
- label="上傳圖片",
84
  type="pil",
85
- height=400
 
 
 
 
 
 
 
 
 
 
 
 
86
  )
87
 
88
  # 按鈕區域
89
  with gr.Row():
90
- preview_btn = gr.Button("🔍 預覽裁切區域", variant="secondary")
 
91
  process_btn = gr.Button("✂️ 裁切並處理", variant="primary")
 
92
 
93
  with gr.Column(scale=1):
94
  # 輸出區域
95
  output_image = gr.Image(
96
- label="處理後圖片",
97
- type="pil",
98
- height=400
 
 
 
 
 
 
 
 
99
  )
100
 
101
  # 狀態信息
@@ -142,18 +202,20 @@ with gr.Blocks(title="圖片裁切工具", theme=gr.themes.Soft()) as demo:
142
  gr.Markdown("""
143
  ### 如何使用:
144
  1. **上傳圖片**:點擊上傳區域選擇您的圖片
145
- 2. **預覽裁切**:點擊「預覽裁切區域」查看建議的裁切區域
146
- 3. **手動編輯**:在上傳的圖片上直接拖拽選擇裁切區域
147
- 4. **處理圖片**:點擊「裁切並處理」生成最終圖片
148
- 5. **下載結果**:右鍵點擊處理後的圖片選擇「另存為」
149
 
150
  ### 功能特色:
151
  - ✨ 自動計算最佳裁切比例
152
- - 🎯 支援手動選擇裁切區域
153
  - 📏 保持 1170:391 的精確比例
154
- - 🖼️ 高品質圖片輸出
155
- - 💾 簡單的下載流程
 
156
  """)
 
157
 
158
  # 事件綁定
159
  preview_btn.click(
@@ -165,9 +227,37 @@ with gr.Blocks(title="圖片裁切工具", theme=gr.themes.Soft()) as demo:
165
  outputs=[preview_image]
166
  )
167
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
168
  process_btn.click(
169
- fn=process_image,
170
  inputs=[input_image],
 
 
 
 
 
 
 
171
  outputs=[output_image, status_text]
172
  )
173
 
 
3
  from PIL import Image
4
  import io
5
  import base64
6
+ import tempfile
7
+ import os
8
 
9
  def calculate_crop_box(image, target_ratio=1170/391):
10
  """
 
32
 
33
  def process_image(image, crop_data=None):
34
  """
35
+ 處理圖片:裁切並調整為目標尺寸,並保存為 JPG 格式
36
  """
37
  if image is None:
38
  return None, "請上傳圖片"
 
51
  target_size = (1170, 391)
52
  final_image = processed_image.resize(target_size, Image.Resampling.LANCZOS)
53
 
54
+ # 轉換為 RGB 模式以確保 JPG 格式輸出
55
+ if final_image.mode in ('RGBA', 'LA', 'P'):
56
+ # 創建白色背景
57
+ rgb_image = Image.new('RGB', final_image.size, (255, 255, 255))
58
+ if final_image.mode == 'P':
59
+ final_image = final_image.convert('RGBA')
60
+ rgb_image.paste(final_image, mask=final_image.split()[-1] if final_image.mode == 'RGBA' else None)
61
+ final_image = rgb_image
62
+
63
+ # 保存為 JPG 格式的臨時檔案
64
+ temp_file = tempfile.NamedTemporaryFile(delete=False, suffix='.jpg')
65
+ final_image.save(temp_file.name, format='JPEG', quality=95, optimize=True)
66
+ temp_file.close()
67
+
68
+ return temp_file.name, f"圖片已處理完成!尺寸:{final_image.size},格式:JPG"
69
 
70
  def auto_crop_preview(image):
71
  """
 
87
 
88
  return preview, f"建議裁切區域:{crop_box}"
89
 
90
+ def manual_crop_image(image, crop_coords):
91
+ """
92
+ 手動裁切圖片
93
+ """
94
+ if image is None:
95
+ return None, "請上傳圖片"
96
+
97
+ if crop_coords is None:
98
+ return auto_crop_preview(image)
99
+
100
+ # 解析裁切座標
101
+ x, y, width, height = crop_coords
102
+
103
+ # 執行裁切
104
+ cropped = image.crop((x, y, x + width, y + height))
105
+
106
+ # 調整為目標尺寸
107
+ target_size = (1170, 391)
108
+ final_image = cropped.resize(target_size, Image.Resampling.LANCZOS)
109
+
110
+ return final_image, f"手動裁切完成!裁切區域:({x}, {y}, {width}, {height})"
111
+
112
  # 創建 Gradio 界面
113
  with gr.Blocks(title="圖片裁切工具", theme=gr.themes.Soft()) as demo:
114
  gr.Markdown("# 🖼️ 圖片裁切工具")
 
116
 
117
  with gr.Row():
118
  with gr.Column(scale=1):
119
+ # 圖片上傳區域(支援裁切編輯)
120
  input_image = gr.Image(
121
+ label="上傳圖片(可直接在圖片上拖拽選擇裁切區域)",
122
  type="pil",
123
+ height=400,
124
+ crop_size="1170:391",
125
+ interactive=True
126
+ )
127
+
128
+ # 手動裁切圖片區域
129
+ crop_image = gr.Image(
130
+ label="手動裁切區域(拖拽選擇後點擊下方按鈕)",
131
+ type="pil",
132
+ height=400,
133
+ tool="select",
134
+ interactive=True,
135
+ visible=False
136
  )
137
 
138
  # 按鈕區域
139
  with gr.Row():
140
+ preview_btn = gr.Button("🔍 預覽建議區域", variant="secondary")
141
+ edit_btn = gr.Button("✏️ 手動編輯", variant="secondary")
142
  process_btn = gr.Button("✂️ 裁切並處理", variant="primary")
143
+ reset_btn = gr.Button("🔄 重置", variant="secondary")
144
 
145
  with gr.Column(scale=1):
146
  # 輸出區域
147
  output_image = gr.Image(
148
+ label="處理後圖片 (JPG格式)",
149
+ type="filepath",
150
+ height=400,
151
+ interactive=False
152
+ )
153
+
154
+ # 下載按鈕
155
+ download_btn = gr.DownloadButton(
156
+ label="📥 下載 JPG 圖片",
157
+ variant="primary",
158
+ visible=False
159
  )
160
 
161
  # 狀態信息
 
202
  gr.Markdown("""
203
  ### 如何使用:
204
  1. **上傳圖片**:點擊上傳區域選擇您的圖片
205
+ 2. **自動裁切**:點擊��預覽建議區域」查看系統建議的裁切區域
206
+ 3. **手動裁切**:點擊「手動編輯」後在圖片上拖拽選擇想要的區域
207
+ 4. **處理圖片**:點擊「裁切並處理」生成 JPG 格式的最終圖片
208
+ 5. **下載結果**:點擊「下載 JPG 圖片」按鈕下載處理後的圖片
209
 
210
  ### 功能特色:
211
  - ✨ 自動計算最佳裁切比例
212
+ - 🎯 支援手動拖拽選擇裁切區域
213
  - 📏 保持 1170:391 的精確比例
214
+ - 🖼️ 輸出高品質 JPG 格式圖片
215
+ - 💾 簡單的一鍵下載功能
216
+ - 🔄 重置功能方便重新開始
217
  """)
218
+
219
 
220
  # 事件綁定
221
  preview_btn.click(
 
227
  outputs=[preview_image]
228
  )
229
 
230
+ edit_btn.click(
231
+ fn=lambda img: (gr.update(visible=True, value=img), gr.update(visible=False)),
232
+ inputs=[input_image],
233
+ outputs=[crop_image, input_image]
234
+ )
235
+
236
+ reset_btn.click(
237
+ fn=lambda: (gr.update(visible=True, value=None), gr.update(visible=False, value=None), gr.update(visible=False), None, "請上傳圖片"),
238
+ outputs=[input_image, crop_image, preview_image, output_image, status_text]
239
+ )
240
+
241
+ def process_and_download(image):
242
+ if image is None:
243
+ return None, "請上傳圖片", gr.update(visible=False)
244
+
245
+ result_path, status = process_image(image)
246
+ if result_path:
247
+ return result_path, status, gr.update(visible=True, value=result_path)
248
+ else:
249
+ return None, status, gr.update(visible=False)
250
+
251
  process_btn.click(
252
+ fn=process_and_download,
253
  inputs=[input_image],
254
+ outputs=[output_image, status_text, download_btn]
255
+ )
256
+
257
+ # 裁切圖片處理
258
+ crop_image.select(
259
+ fn=manual_crop_image,
260
+ inputs=[crop_image, crop_image.select],
261
  outputs=[output_image, status_text]
262
  )
263