STLooo commited on
Commit
8f796ba
·
verified ·
1 Parent(s): e48a3be

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +57 -84
app.py CHANGED
@@ -1,13 +1,10 @@
1
- import os
2
- import cv2
3
- import gradio as gr
4
  import numpy as np
5
- import zipfile
6
  import fitz # PyMuPDF
7
- import gc
 
8
 
9
- # 數設定
10
- FG_DIR = "foregrounds"
11
  OUTPUT_DIR = "output"
12
  ZIP_PATH = os.path.join(OUTPUT_DIR, "results.zip")
13
  BG_PATH = "background.jpg"
@@ -15,119 +12,95 @@ TARGET_WIDTH, TARGET_HEIGHT = 2133, 1200
15
  POS1 = (1032, 0)
16
  POS2 = (4666, 0)
17
 
18
- # 建立資料夾
19
  def ensure_dir(path):
20
- if not os.path.exists(path):
21
- os.makedirs(path)
22
  if not os.access(path, os.W_OK):
23
- raise RuntimeError(f"❌ 沒有寫入權限:{path}")
24
-
25
- ensure_dir(FG_DIR)
26
  ensure_dir(OUTPUT_DIR)
27
 
28
- # PDF 每頁
29
  def pdf_to_images(pdf_file):
30
- doc = fitz.open(pdf_file.name)
31
- paths = []
32
- for i, page in enumerate(doc, start=1):
33
- pix = page.get_pixmap(matrix=fitz.Matrix(2, 2))
34
- img_path = os.path.join(FG_DIR, f"page_{i:03d}.jpg")
35
- pix.save(img_path)
36
- paths.append(img_path)
37
- return paths
38
 
39
  # 圖像合成功能
40
- def overlay_image(bg, fg, x, y):
41
- h, w = fg.shape[:2]
42
  if fg.shape[2] == 4:
43
- alpha = fg[:, :, 3:] / 255.0
44
- bg[y:y+h, x:x+w] = alpha * fg[:, :, :3] + (1 - alpha) * bg[y:y+h, x:x+w]
 
 
 
45
  else:
46
- bg[y:y+h, x:x+w] = fg
47
  return bg
48
 
49
- # 壓縮 ZIP
50
- def zip_results():
51
- with zipfile.ZipFile(ZIP_PATH, "w", zipfile.ZIP_DEFLATED) as z:
52
- for f in sorted(os.listdir(OUTPUT_DIR)):
53
- if f.endswith(".jpg"):
54
- z.write(os.path.join(OUTPUT_DIR, f), arcname=f)
55
- return ZIP_PATH
56
-
57
- # 合成流程
58
- def process_and_combine(fg_paths, prefix):
59
  bg = cv2.imread(BG_PATH)
60
  if bg is None:
61
  raise gr.Error("❌ 無法讀取 background.jpg")
62
-
63
- # 清空舊檔
64
  for f in os.listdir(OUTPUT_DIR):
65
  if f.endswith(".jpg"):
66
  os.remove(os.path.join(OUTPUT_DIR, f))
67
 
68
  results = []
69
- for i, path in enumerate(fg_paths, 1):
70
- fg = cv2.imread(path, cv2.IMREAD_UNCHANGED)
71
- if fg is None:
72
- continue
73
- fg = cv2.resize(fg, (TARGET_WIDTH, TARGET_HEIGHT))
74
- result = overlay_image(bg.copy(), fg, *POS1)
75
- result = overlay_image(result, fg, *POS2)
76
-
77
- out_path = os.path.join(OUTPUT_DIR, f"{prefix}{i:03d}.jpg")
78
- cv2.imwrite(out_path, result)
79
- results.append((out_path, f"{prefix}{i:03d}"))
80
-
81
  if i % 10 == 0:
82
  gc.collect()
83
 
84
  if not results:
85
- raise gr.Error("⚠️ 沒有生成任何圖片")
86
 
87
- zip_file = zip_results()
88
- return results, zip_file, f"✅ 成功合成 {len(results)} 張圖片"
 
 
 
89
 
90
- # 主入口:支援圖片或 PDF 混合上傳
91
  def process_inputs(files, prefix):
92
- if not prefix.strip():
93
- prefix = "result_"
94
-
95
- fg_paths = []
96
- for f in files:
97
- name = f.name.lower()
98
  if name.endswith(".pdf"):
99
- fg_paths.extend(pdf_to_images(f))
100
  elif name.endswith((".png", ".jpg", ".jpeg")):
101
- fg_paths.append(f.name)
 
102
  else:
103
  raise gr.Error(f"不支援的檔案格式:{name}")
 
104
 
105
- return process_and_combine(fg_paths, prefix)
106
-
107
- # Gradio 介面
108
- with gr.Blocks() as demo:
109
- gr.Markdown("## 📄🖼️ PDF 或圖片合成工具(背景為 7872x1200)")
110
-
111
- with gr.Row():
112
- upload_files = gr.Files(label="上傳 PDF 或圖片", file_types=[".pdf", ".png", ".jpg", ".jpeg"])
113
- gallery = gr.Gallery(label="預覽", columns=3)
114
-
115
 
116
  with gr.Row():
117
- prefix_input = gr.Textbox(label="輸出檔案前綴 (選填)", placeholder="例如:project_")
118
- zip_file = gr.File(label="下載 ZIP")
119
-
120
 
121
  with gr.Row():
122
- btn_run = gr.Button("開始合成", variant="primary")
123
- log_output = gr.Textbox(label="處理日誌", interactive=False)
124
-
125
 
126
- btn_run.click(
127
- fn=process_inputs,
128
- inputs=[upload_files, prefix_input],
129
- outputs=[gallery, zip_file, log_output]
130
- )
131
 
132
  if __name__ == "__main__":
133
  demo.launch()
 
1
+ import os, cv2, zipfile, gc, gradio as gr
 
 
2
  import numpy as np
 
3
  import fitz # PyMuPDF
4
+ from PIL import Image
5
+ from io import BytesIO
6
 
7
+ # 數設定
 
8
  OUTPUT_DIR = "output"
9
  ZIP_PATH = os.path.join(OUTPUT_DIR, "results.zip")
10
  BG_PATH = "background.jpg"
 
12
  POS1 = (1032, 0)
13
  POS2 = (4666, 0)
14
 
15
+ # 檢查資料夾權限
16
  def ensure_dir(path):
17
+ os.makedirs(path, exist_ok=True)
 
18
  if not os.access(path, os.W_OK):
19
+ raise RuntimeError(f"❌ 無法寫入:{path}")
 
 
20
  ensure_dir(OUTPUT_DIR)
21
 
22
+ # PDF 轉圖像(記憶體內處理)
23
  def pdf_to_images(pdf_file):
24
+ images = []
25
+ with fitz.open(stream=pdf_file.read(), filetype="pdf") as doc:
26
+ for page in doc:
27
+ pix = page.get_pixmap(matrix=fitz.Matrix(2, 2))
28
+ img = Image.frombytes("RGB", [pix.width, pix.height], pix.samples)
29
+ images.append(img)
30
+ return images
 
31
 
32
  # 圖像合成功能
33
+ def overlay_image(bg, fg_img, x, y):
34
+ fg = np.array(fg_img.resize((TARGET_WIDTH, TARGET_HEIGHT)))
35
  if fg.shape[2] == 4:
36
+ alpha = fg[:, :, 3] / 255.0
37
+ for c in range(3):
38
+ bg[y:y+TARGET_HEIGHT, x:x+TARGET_WIDTH, c] = (
39
+ alpha * fg[:, :, c] + (1 - alpha) * bg[y:y+TARGET_HEIGHT, x:x+TARGET_WIDTH, c]
40
+ )
41
  else:
42
+ bg[y:y+TARGET_HEIGHT, x:x+TARGET_WIDTH] = fg
43
  return bg
44
 
45
+ # 合成 + 輸出 ZIP
46
+ def process_and_combine(images, prefix):
 
 
 
 
 
 
 
 
47
  bg = cv2.imread(BG_PATH)
48
  if bg is None:
49
  raise gr.Error("❌ 無法讀取 background.jpg")
50
+
 
51
  for f in os.listdir(OUTPUT_DIR):
52
  if f.endswith(".jpg"):
53
  os.remove(os.path.join(OUTPUT_DIR, f))
54
 
55
  results = []
56
+ for i, img in enumerate(images, 1):
57
+ combined = overlay_image(bg.copy(), img, *POS1)
58
+ combined = overlay_image(combined, img, *POS2)
59
+ output_path = os.path.join(OUTPUT_DIR, f"{prefix}{i:03d}.jpg")
60
+ cv2.imwrite(output_path, combined)
61
+ results.append((output_path, f"{prefix}{i:03d}"))
 
 
 
 
 
 
62
  if i % 10 == 0:
63
  gc.collect()
64
 
65
  if not results:
66
+ raise gr.Error("⚠️ 沒有生圖片")
67
 
68
+ with zipfile.ZipFile(ZIP_PATH, "w", zipfile.ZIP_DEFLATED) as zipf:
69
+ for f in sorted(os.listdir(OUTPUT_DIR)):
70
+ if f.endswith(".jpg"):
71
+ zipf.write(os.path.join(OUTPUT_DIR, f), arcname=f)
72
+ return results, ZIP_PATH, f"✅ 共合成 {len(results)} 張圖,已打包 ZIP"
73
 
74
+ # 主流程
75
  def process_inputs(files, prefix):
76
+ prefix = prefix.strip() or "result_"
77
+ images = []
78
+ for file in files:
79
+ name = file.name.lower()
 
 
80
  if name.endswith(".pdf"):
81
+ images.extend(pdf_to_images(file))
82
  elif name.endswith((".png", ".jpg", ".jpeg")):
83
+ img = Image.open(file).convert("RGBA")
84
+ images.append(img)
85
  else:
86
  raise gr.Error(f"不支援的檔案格式:{name}")
87
+ return process_and_combine(images, prefix)
88
 
89
+ # Gradio UI
90
+ with gr.Blocks(title="PDF合成工具") as demo:
91
+ gr.Markdown("### 📄🖼️ PDF / 圖片雙輸入合成工具(背景固定為 7872x1200)")
 
 
 
 
 
 
 
92
 
93
  with gr.Row():
94
+ files = gr.Files(label="📎 上傳 PDF 或圖片", file_types=[".pdf", ".png", ".jpg", ".jpeg"])
95
+ prefix = gr.Textbox(label="檔名前綴(可選)", placeholder="例如:poster_")
96
+ run_btn = gr.Button("🚀 開始合成", variant="primary")
97
 
98
  with gr.Row():
99
+ gallery = gr.Gallery(label="🖼️ 預覽", columns=3, height="auto")
100
+ zip_file = gr.File(label="⬇️ 下載 ZIP")
101
+ log = gr.Textbox(label="📄 日誌", interactive=False)
102
 
103
+ run_btn.click(fn=process_inputs, inputs=[files, prefix], outputs=[gallery, zip_file, log])
 
 
 
 
104
 
105
  if __name__ == "__main__":
106
  demo.launch()