STLooo commited on
Commit
215cb68
·
verified ·
1 Parent(s): 935c7ab

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +54 -61
app.py CHANGED
@@ -1,36 +1,40 @@
1
- import os
2
  import cv2
3
  import numpy as np
 
4
  import gradio as gr
5
- import zipfile
6
  import gc
7
- from pdf2image import convert_from_bytes
8
-
9
- # ✅ Hugging Face Spaces Docker 可寫目錄
10
- BASE_DIR = "/tmp/myapp"
11
- FG_DIR = os.path.join(BASE_DIR, "foregrounds")
12
- OUTPUT_DIR = os.path.join(BASE_DIR, "output")
13
- ZIP_PATH = os.path.join(BASE_DIR, "results.zip")
14
 
15
- # 背景圖
16
- BG_PATH = "background.jpg"
 
 
 
 
17
  TARGET_WIDTH, TARGET_HEIGHT = 2133, 1200
18
  POS1 = (1032, 0)
19
  POS2 = (4666, 0)
20
 
 
21
  def check_write_permission(path):
22
- os.makedirs(path, exist_ok=True)
23
- if not os.access(path, os.W_OK):
24
- raise RuntimeError(f"❌ 無法寫入資料夾:{path}")
 
 
 
 
25
 
26
  check_write_permission(FG_DIR)
27
  check_write_permission(OUTPUT_DIR)
28
 
 
29
  def overlay_image(bg, fg, x, y):
30
  h, w = fg.shape[:2]
31
  bh, bw = bg.shape[:2]
32
  if x + w > bw or y + h > bh:
33
  raise ValueError(f"前景圖超出背景邊界:({x},{y},{w},{h}) > 背景({bw},{bh})")
 
34
  if fg.shape[2] == 4:
35
  alpha = fg[:, :, 3:] / 255.0
36
  bg[y:y+h, x:x+w] = alpha * fg[:, :, :3] + (1 - alpha) * bg[y:y+h, x:x+w]
@@ -38,20 +42,7 @@ def overlay_image(bg, fg, x, y):
38
  bg[y:y+h, x:x+w] = fg[:, :, :3]
39
  return bg
40
 
41
- def process_pdf_to_images(pdf_file):
42
- with open(pdf_file.name, "rb") as f:
43
- images = convert_from_bytes(f.read(), fmt="jpeg", size=(TARGET_WIDTH, TARGET_HEIGHT))
44
-
45
- fg_arrays = []
46
- for img in images:
47
- np_img = np.array(img.convert("RGB"))
48
- fg = cv2.cvtColor(np_img, cv2.COLOR_RGB2BGR)
49
- fg = cv2.resize(fg, (TARGET_WIDTH, TARGET_HEIGHT))
50
- fg = fg.astype(np.uint8)
51
- fg = np.dstack([fg, np.ones((TARGET_HEIGHT, TARGET_WIDTH), dtype=np.uint8)*255]) # fake alpha
52
- fg_arrays.append(fg)
53
- return fg_arrays
54
-
55
  def zip_output_files():
56
  with zipfile.ZipFile(ZIP_PATH, "w", zipfile.ZIP_DEFLATED) as zipf:
57
  for file in sorted(os.listdir(OUTPUT_DIR)):
@@ -59,63 +50,65 @@ def zip_output_files():
59
  zipf.write(os.path.join(OUTPUT_DIR, file), arcname=file)
60
  return ZIP_PATH
61
 
62
- def process_inputs(fg_files, pdf_file):
 
63
  try:
64
  progress = gr.Progress()
65
  progress(0, desc="準備中...")
66
 
 
 
 
 
 
67
  bg = cv2.imread(BG_PATH)
68
  if bg is None:
69
  raise gr.Error("無法讀取背景圖(請確認 background.jpg 是否存在)")
70
 
 
71
  for f in os.listdir(OUTPUT_DIR):
72
  if f.endswith(".jpg"):
73
  os.remove(os.path.join(OUTPUT_DIR, f))
74
 
75
- fg_images = []
 
 
76
 
77
- if pdf_file is not None:
78
- fg_images = process_pdf_to_images(pdf_file)
79
- elif fg_files:
80
- for file in fg_files:
81
- with open(file.name, 'rb') as f:
82
- data = np.frombuffer(f.read(), np.uint8)
83
- fg = cv2.imdecode(data, cv2.IMREAD_UNCHANGED)
84
  if fg is None:
85
  continue
86
- fg = cv2.resize(fg, (TARGET_WIDTH, TARGET_HEIGHT))
87
- if fg.shape[2] == 3:
88
- fg = np.dstack([fg, np.ones((TARGET_HEIGHT, TARGET_WIDTH), dtype=np.uint8)*255])
89
- fg_images.append(fg)
90
 
91
- if not fg_images:
92
- return [], None, "請上傳 PDF 或 圖片"
93
 
94
- results = []
95
- for i, fg in enumerate(fg_images, 1):
96
- progress(i / len(fg_images), f"處理第 {i} 張圖...")
97
- result = overlay_image(bg.copy(), fg, *POS1)
98
- result = overlay_image(result, fg, *POS2)
99
- out_path = os.path.join(OUTPUT_DIR, f"result_{i:03d}.jpg")
100
- cv2.imwrite(out_path, result)
101
- results.append(out_path)
102
 
103
- if i % 10 == 0:
104
- gc.collect()
 
105
 
 
 
 
 
 
 
 
 
106
  zip_file = zip_output_files()
107
- return results, zip_file, f"成功處理 {len(results)} 張圖片"
108
 
109
  except Exception as e:
110
  raise gr.Error(f"處理出錯:{str(e)}")
111
 
112
- # Gradio UI
113
  with gr.Blocks() as demo:
114
- gr.Markdown("## 🖼️ 寬圖片合成工具(支援 PDF 或前)")
115
 
116
- with gr.Row():
117
- fg_upload = gr.Files(label="上傳前景圖(JPG 或 PNG)", file_types=[".jpg", ".png"])
118
- pdf_upload = gr.File(label="或上傳 PDF(每頁轉圖片)", file_types=[".pdf"])
119
  btn_run = gr.Button("開始合成", variant="primary")
120
 
121
  with gr.Row():
@@ -124,8 +117,8 @@ with gr.Blocks() as demo:
124
  log_output = gr.Textbox(label="日誌", interactive=False)
125
 
126
  btn_run.click(
127
- fn=process_inputs,
128
- inputs=[fg_upload, pdf_upload],
129
  outputs=[gallery, zip_download, log_output],
130
  concurrency_limit=4
131
  )
 
 
1
  import cv2
2
  import numpy as np
3
+ import os
4
  import gradio as gr
 
5
  import gc
6
+ import zipfile
 
 
 
 
 
 
7
 
8
+ # 常量設定
9
+ MAX_FILES = 250
10
+ BG_PATH = "background.jpg" # 預設背景圖,請自行放置
11
+ FG_DIR = "foregrounds"
12
+ OUTPUT_DIR = "output"
13
+ ZIP_PATH = "output/results.zip"
14
  TARGET_WIDTH, TARGET_HEIGHT = 2133, 1200
15
  POS1 = (1032, 0)
16
  POS2 = (4666, 0)
17
 
18
+ # 初始化資料夾與權限檢查
19
  def check_write_permission(path):
20
+ if not os.path.exists(path):
21
+ try:
22
+ os.makedirs(path)
23
+ except Exception as e:
24
+ raise RuntimeError(f"❌ 無法建立目錄 '{path}':{e}")
25
+ elif not os.access(path, os.W_OK):
26
+ raise RuntimeError(f"❌ 目錄 '{path}' 存在,但沒有寫入權限!")
27
 
28
  check_write_permission(FG_DIR)
29
  check_write_permission(OUTPUT_DIR)
30
 
31
+ # 合成圖片
32
  def overlay_image(bg, fg, x, y):
33
  h, w = fg.shape[:2]
34
  bh, bw = bg.shape[:2]
35
  if x + w > bw or y + h > bh:
36
  raise ValueError(f"前景圖超出背景邊界:({x},{y},{w},{h}) > 背景({bw},{bh})")
37
+
38
  if fg.shape[2] == 4:
39
  alpha = fg[:, :, 3:] / 255.0
40
  bg[y:y+h, x:x+w] = alpha * fg[:, :, :3] + (1 - alpha) * bg[y:y+h, x:x+w]
 
42
  bg[y:y+h, x:x+w] = fg[:, :, :3]
43
  return bg
44
 
45
+ # 壓縮成 zip
 
 
 
 
 
 
 
 
 
 
 
 
 
46
  def zip_output_files():
47
  with zipfile.ZipFile(ZIP_PATH, "w", zipfile.ZIP_DEFLATED) as zipf:
48
  for file in sorted(os.listdir(OUTPUT_DIR)):
 
50
  zipf.write(os.path.join(OUTPUT_DIR, file), arcname=file)
51
  return ZIP_PATH
52
 
53
+ # 處理合成流程
54
+ def process_images(fg_files):
55
  try:
56
  progress = gr.Progress()
57
  progress(0, desc="準備中...")
58
 
59
+ if len(fg_files) == 0:
60
+ return [], None, "請至少上傳一張前景圖"
61
+ if len(fg_files) > MAX_FILES:
62
+ raise gr.Error(f"最多支援 {MAX_FILES} 張圖片")
63
+
64
  bg = cv2.imread(BG_PATH)
65
  if bg is None:
66
  raise gr.Error("無法讀取背景圖(請確認 background.jpg 是否存在)")
67
 
68
+ # 清除舊結果
69
  for f in os.listdir(OUTPUT_DIR):
70
  if f.endswith(".jpg"):
71
  os.remove(os.path.join(OUTPUT_DIR, f))
72
 
73
+ results = []
74
+ for i, fg_file in enumerate(fg_files, 1):
75
+ progress(i / len(fg_files), f"合成第 {i} 張圖...")
76
 
77
+ try:
78
+ with open(fg_file.name, 'rb') as f:
79
+ fg_data = np.frombuffer(f.read(), np.uint8)
80
+ fg = cv2.imdecode(fg_data, cv2.IMREAD_UNCHANGED)
 
 
 
81
  if fg is None:
82
  continue
 
 
 
 
83
 
84
+ fg = cv2.resize(fg, (TARGET_WIDTH, TARGET_HEIGHT), interpolation=cv2.INTER_AREA)
 
85
 
86
+ result = overlay_image(bg.copy(), fg, *POS1)
87
+ result = overlay_image(result, fg, *POS2)
 
 
 
 
 
 
88
 
89
+ output_path = f"{OUTPUT_DIR}/result_{i:03d}.jpg"
90
+ cv2.imwrite(output_path, result)
91
+ results.append((output_path, f"Result {i:03d}"))
92
 
93
+ if i % 10 == 0:
94
+ gc.collect()
95
+
96
+ except Exception as e:
97
+ print(f"處理 {fg_file.name} 失敗: {str(e)}")
98
+ continue
99
+
100
+ progress(1, "完成!")
101
  zip_file = zip_output_files()
102
+ return results, zip_file, f"成功處理 {len(results)}/{len(fg_files)} 張圖片,已打包為 ZIP 可下載"
103
 
104
  except Exception as e:
105
  raise gr.Error(f"處理出錯:{str(e)}")
106
 
107
+ # Gradio 介面
108
  with gr.Blocks() as demo:
109
+ gr.Markdown("## 🖼️ 寬圖片合成工具(固定為 7872x1200)")
110
 
111
+ fg_upload = gr.Files(label="上傳前景圖(JPG 或 PNG,自動套用背景)", file_types=[".jpg", ".png"])
 
 
112
  btn_run = gr.Button("開始合成", variant="primary")
113
 
114
  with gr.Row():
 
117
  log_output = gr.Textbox(label="日誌", interactive=False)
118
 
119
  btn_run.click(
120
+ fn=process_images,
121
+ inputs=fg_upload,
122
  outputs=[gallery, zip_download, log_output],
123
  concurrency_limit=4
124
  )