STLooo commited on
Commit
5632e3e
·
verified ·
1 Parent(s): 7ec8f02

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +101 -92
app.py CHANGED
@@ -2,14 +2,13 @@ import cv2
2
  import numpy as np
3
  import os
4
  import gradio as gr
5
- import gc
6
  import zipfile
 
 
7
  from pdf2image import convert_from_path
8
  from PIL import Image
9
- import tempfile
10
 
11
- # 常量設定
12
- MAX_PAGES = 250
13
  BG_PATH = "background.jpg"
14
  FG_DIR = "foregrounds"
15
  OUTPUT_DIR = "output"
@@ -18,27 +17,36 @@ TARGET_WIDTH, TARGET_HEIGHT = 2133, 1200
18
  POS1 = (1032, 0)
19
  POS2 = (4666, 0)
20
 
21
- def check_write_permission(path):
22
- if not os.path.exists(path):
23
- os.makedirs(path, exist_ok=True)
24
- elif not os.access(path, os.W_OK):
25
- raise RuntimeError(f"❌ 目錄 '{path}' 存在但無法寫入")
26
-
27
- check_write_permission(FG_DIR)
28
- check_write_permission(OUTPUT_DIR)
29
-
30
- def pdf_to_images(pdf_file, prefix):
31
- with tempfile.NamedTemporaryFile(suffix=".pdf", delete=False) as tmp_pdf:
32
- tmp_pdf.write(pdf_file.read()) # ← 這裡改成 .read(),支援 NamedString
33
- tmp_pdf.flush()
34
- images = convert_from_path(tmp_pdf.name, fmt='jpg')
35
- paths = []
36
- for i, img in enumerate(images, 1):
37
- path = os.path.join(FG_DIR, f"{prefix}page_{i:03d}.jpg")
38
- img.save(path, 'JPEG')
39
- paths.append(path)
40
- return paths
41
-
 
 
 
 
 
 
 
 
 
42
  def overlay_image(bg, fg, x, y):
43
  h, w = fg.shape[:2]
44
  if fg.shape[2] == 4:
@@ -48,81 +56,82 @@ def overlay_image(bg, fg, x, y):
48
  bg[y:y+h, x:x+w] = fg[:, :, :3]
49
  return bg
50
 
51
- def zip_output(prefix):
52
- zip_path = ZIP_PATH.replace("results", prefix.rstrip("_"))
53
- with zipfile.ZipFile(zip_path, "w", zipfile.ZIP_DEFLATED) as zf:
54
- for f in sorted(os.listdir(OUTPUT_DIR)):
55
- if f.endswith(".jpg"):
56
- zf.write(os.path.join(OUTPUT_DIR, f), arcname=f)
57
- return zip_path
58
-
59
- def process_inputs(files, prefix):
60
- progress = gr.Progress()
61
- prefix = prefix.strip() or "results_"
62
- prefix = prefix if prefix.endswith("_") else prefix + "_"
63
-
64
- # 清空輸出
65
- for f in os.listdir(OUTPUT_DIR):
66
- if f.endswith(".jpg"):
 
 
67
  os.remove(os.path.join(OUTPUT_DIR, f))
68
 
69
- # 載入背景圖
70
- bg = cv2.imread(BG_PATH)
71
- if bg is None:
72
- raise gr.Error("❌ 找不到背景圖 background.jpg")
73
-
74
- all_fgs = []
75
-
76
- for file in files:
77
- name = file.name.lower()
78
- if name.endswith(".pdf"):
79
- imgs = pdf_to_images(file, prefix)
80
- all_fgs.extend(imgs)
81
- elif name.endswith((".png", ".jpg", ".jpeg")):
82
- new_path = os.path.join(FG_DIR, f"{prefix}{os.path.basename(name)}")
83
- with open(new_path, "wb") as out:
84
- out.write(file.read_bytes())
85
- all_fgs.append(new_path)
86
-
87
- if not all_fgs:
88
- return [], None, "⚠️ 沒有找到可處理的圖片"
89
-
90
- results = []
91
- for i, fg_path in enumerate(all_fgs, 1):
92
- progress(i / len(all_fgs), f"處理第 {i} 張...")
93
- fg = cv2.imread(fg_path, cv2.IMREAD_UNCHANGED)
94
- if fg is None:
95
- continue
96
- fg = cv2.resize(fg, (TARGET_WIDTH, TARGET_HEIGHT))
97
- result = overlay_image(bg.copy(), fg, *POS1)
98
- result = overlay_image(result, fg, *POS2)
99
- out_path = os.path.join(OUTPUT_DIR, f"{prefix}{i:03d}.jpg")
100
- cv2.imwrite(out_path, result)
101
- results.append((out_path, f"{prefix}{i:03d}"))
102
- if i % 10 == 0:
103
- gc.collect()
104
-
105
- zip_path = zip_output(prefix)
106
- return results, zip_path, f"✅ 成功處理 {len(results)} 張圖,ZIP 已可下載"
107
-
108
- # Gradio UI (相容���版)
109
  with gr.Blocks() as demo:
110
- gr.Markdown("## 🖼️ PDF / 圖片合成工具(搭配背景圖)")
111
- gr.Markdown("背景圖為固定的 `background.jpg`,前景可為 PDF 或圖片。")
112
-
113
- files_input = gr.Files(label="📂 上傳 PDF 或圖片", file_types=[".pdf", ".jpg", ".png", ".jpeg"])
114
- prefix_input = gr.Textbox(label="📎 自訂輸出檔案前綴", placeholder="例如 myproject_")
115
 
116
- run_btn = gr.Button("🚀 開始合成", variant="primary")
 
 
117
 
118
- gallery = gr.Gallery(label="合成預覽", columns=3, height="auto")
119
- zip_file = gr.File(label="📦 下載結果 ZIP 檔")
120
- log_output = gr.Textbox(label="📜 處理日誌", interactive=False)
 
 
121
 
122
  run_btn.click(
123
  fn=process_inputs,
124
- inputs=[files_input, prefix_input],
125
- outputs=[gallery, zip_file, log_output]
 
126
  )
127
 
128
  if __name__ == "__main__":
 
2
  import numpy as np
3
  import os
4
  import gradio as gr
 
5
  import zipfile
6
+ import tempfile
7
+ import gc
8
  from pdf2image import convert_from_path
9
  from PIL import Image
 
10
 
11
+ # 設定常數與目錄
 
12
  BG_PATH = "background.jpg"
13
  FG_DIR = "foregrounds"
14
  OUTPUT_DIR = "output"
 
17
  POS1 = (1032, 0)
18
  POS2 = (4666, 0)
19
 
20
+ # 確保目錄存在
21
+ for d in [FG_DIR, OUTPUT_DIR]:
22
+ os.makedirs(d, exist_ok=True)
23
+
24
+ # PDF 轉圖片
25
+ def pdf_to_images(pdf_file_path, prefix):
26
+ with open(pdf_file_path, "rb") as f:
27
+ with tempfile.NamedTemporaryFile(suffix=".pdf", delete=False) as tmp_pdf:
28
+ tmp_pdf.write(f.read())
29
+ tmp_pdf.flush()
30
+ images = convert_from_path(tmp_pdf.name, fmt='jpg')
31
+
32
+ paths = []
33
+ for i, img in enumerate(images, 1):
34
+ path = os.path.join(FG_DIR, f"{prefix}page_{i:03d}.jpg")
35
+ img.save(path, 'JPEG')
36
+ paths.append(path)
37
+ return paths
38
+
39
+ # 儲存上傳圖片
40
+ def save_uploaded_images(files, prefix):
41
+ paths = []
42
+ for i, file in enumerate(files, 1):
43
+ img = Image.open(file.name).convert("RGB")
44
+ path = os.path.join(FG_DIR, f"{prefix}img_{i:03d}.jpg")
45
+ img.save(path, "JPEG")
46
+ paths.append(path)
47
+ return paths
48
+
49
+ # 合成圖層
50
  def overlay_image(bg, fg, x, y):
51
  h, w = fg.shape[:2]
52
  if fg.shape[2] == 4:
 
56
  bg[y:y+h, x:x+w] = fg[:, :, :3]
57
  return bg
58
 
59
+ # 壓縮輸出成 ZIP
60
+ def zip_output_files():
61
+ with zipfile.ZipFile(ZIP_PATH, "w", zipfile.ZIP_DEFLATED) as zipf:
62
+ for file in sorted(os.listdir(OUTPUT_DIR)):
63
+ if file.endswith(".jpg"):
64
+ zipf.write(os.path.join(OUTPUT_DIR, file), arcname=file)
65
+ return ZIP_PATH
66
+
67
+ # 主處理邏輯
68
+ def process_inputs(pdf_file, image_files, prefix):
69
+ try:
70
+ progress = gr.Progress()
71
+ fg_images = []
72
+
73
+ # 清除舊資料
74
+ for f in os.listdir(FG_DIR):
75
+ os.remove(os.path.join(FG_DIR, f))
76
+ for f in os.listdir(OUTPUT_DIR):
77
  os.remove(os.path.join(OUTPUT_DIR, f))
78
 
79
+ # PDF
80
+ if pdf_file is not None:
81
+ progress(0.1, "轉換 PDF 為圖片...")
82
+ fg_images = pdf_to_images(pdf_file, prefix)
83
+
84
+ # 圖片
85
+ elif image_files is not None:
86
+ progress(0.1, "儲存上傳圖片...")
87
+ fg_images = save_uploaded_images(image_files, prefix)
88
+
89
+ else:
90
+ raise gr.Error("請上傳 PDF 或圖片!")
91
+
92
+ # 背景圖
93
+ bg = cv2.imread(BG_PATH)
94
+ if bg is None:
95
+ raise gr.Error("找不到背景圖 background.jpg")
96
+
97
+ results = []
98
+ for i, img_path in enumerate(fg_images, 1):
99
+ progress(0.2 + 0.7 * i / len(fg_images), f"合成第 {i} 張圖片...")
100
+ fg = cv2.imread(img_path, cv2.IMREAD_UNCHANGED)
101
+ fg = cv2.resize(fg, (TARGET_WIDTH, TARGET_HEIGHT))
102
+ result = overlay_image(bg.copy(), fg, *POS1)
103
+ result = overlay_image(result, fg, *POS2)
104
+ out_path = os.path.join(OUTPUT_DIR, f"{prefix}result_{i:03d}.jpg")
105
+ cv2.imwrite(out_path, result)
106
+ results.append((out_path, f"{prefix}{i:03d}"))
107
+ if i % 10 == 0:
108
+ gc.collect()
109
+
110
+ zip_file = zip_output_files()
111
+ return results, zip_file, f"✅ 成功處理 {len(results)} 張圖片,ZIP 可下載"
112
+
113
+ except Exception as e:
114
+ raise gr.Error(f"處理出錯:{str(e)}")
115
+
116
+ # Gradio UI
 
 
117
  with gr.Blocks() as demo:
118
+ gr.Markdown("## 📄 PDF 圖片合成工具(固定背景圖)")
 
 
 
 
119
 
120
+ with gr.Row():
121
+ pdf_file = gr.File(label="上傳 PDF(選一)", file_types=[".pdf"])
122
+ image_files = gr.Files(label="或上傳圖片(JPG/PNG 多張)", file_types=[".jpg", ".png"])
123
 
124
+ prefix_input = gr.Textbox(label="自定義檔名前綴", value="results_")
125
+ run_btn = gr.Button("開始合成")
126
+ gallery = gr.Gallery(label="預覽", columns=3)
127
+ zip_file = gr.File(label="下載 ZIP")
128
+ log = gr.Textbox(label="處理日誌", interactive=False)
129
 
130
  run_btn.click(
131
  fn=process_inputs,
132
+ inputs=[pdf_file, image_files, prefix_input],
133
+ outputs=[gallery, zip_file, log],
134
+ concurrency_limit=2
135
  )
136
 
137
  if __name__ == "__main__":