File size: 4,465 Bytes
8f796ba
716d72a
 
8f796ba
d3329bf
e3ae23b
d3329bf
716d72a
 
d3329bf
 
 
 
716d72a
8f796ba
716d72a
94182ca
716d72a
5632e3e
5085139
f1926db
 
5085139
 
f1926db
 
5085139
f1926db
5085139
f1926db
5085139
 
 
f1926db
 
8f796ba
e3ae23b
75b73d9
f1926db
 
 
 
 
 
 
8f796ba
5632e3e
5085139
8f796ba
f1926db
5085139
d3329bf
 
5085139
8f796ba
5085139
 
 
ea494fa
716d72a
 
5e6e8d3
 
716d72a
8f796ba
 
 
 
5085139
8f796ba
716d72a
 
 
 
94182ca
716d72a
8f796ba
 
 
 
716d72a
5085139
 
 
f1926db
8f796ba
f1926db
 
8f796ba
5085139
8f796ba
716d72a
5085139
94182ca
e72a030
f1926db
 
8f796ba
716d72a
 
f1926db
 
 
 
8f796ba
5632e3e
f1926db
 
 
 
e3ae23b
e72a030
e3ae23b
e72a030
5085139
f1926db
e3ae23b
 
 
 
5085139
e3ae23b
 
5085139
e3ae23b
d3329bf
 
94182ca
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
import os, cv2, zipfile, gc, gradio as gr
import numpy as np
import fitz  # PyMuPDF
from PIL import Image

# 設定
OUTPUT_DIR = "output"
ZIP_PATH = os.path.join(OUTPUT_DIR, "results.zip")
BG_PATH = "background.jpg"
TARGET_WIDTH, TARGET_HEIGHT = 2133, 1200
POS1 = (1032, 0)
POS2 = (4666, 0)

def ensure_dir(path):
    os.makedirs(path, exist_ok=True)
    if not os.access(path, os.W_OK):
        raise RuntimeError(f"❌ 無法寫入:{path}")
ensure_dir(OUTPUT_DIR)

# 解析頁碼範圍字串(如 "1-3,5,7")
def parse_page_selection(selection_text):
    if not selection_text.strip():
        return None
    pages = set()
    for part in selection_text.split(','):
        part = part.strip()
        if '-' in part:
            start, end = map(int, part.split('-'))
            pages.update(range(start, end + 1))
        elif part.isdigit():
            pages.add(int(part))
    return sorted(pages)

# PDF轉圖片(np.array 格式,BGR)
def pdf_to_images(pdf_file, page_list=None):
    images = []
    with fitz.open(pdf_file.name) as doc:
        total_pages = len(doc)
        selected = page_list or list(range(1, total_pages + 1))
        for page_num in selected:
            if 1 <= page_num <= total_pages:
                pix = doc[page_num - 1].get_pixmap(matrix=fitz.Matrix(2, 2), colorspace=fitz.csRGB)
                img = np.frombuffer(pix.samples, dtype=np.uint8).reshape((pix.height, pix.width, 3))
                img = cv2.cvtColor(img, cv2.COLOR_RGB2BGR)
                images.append(img)
    return images

# 合成圖片
def overlay_image(bg, fg_img, x, y):
    fg = cv2.resize(fg_img, (TARGET_WIDTH, TARGET_HEIGHT), interpolation=cv2.INTER_AREA)
    bg[y:y+TARGET_HEIGHT, x:x+TARGET_WIDTH] = fg
    return bg

# 處理與合成流程
def process_and_combine(images, prefix):
    bg = cv2.imread(BG_PATH)
    if bg is None:
        raise gr.Error("❌ 無法讀取 background.jpg")

    for f in os.listdir(OUTPUT_DIR):
        if f.endswith(".jpg"):
            os.remove(os.path.join(OUTPUT_DIR, f))

    results = []
    for i, img in enumerate(images, 1):
        combined = overlay_image(bg.copy(), img, *POS1)
        combined = overlay_image(combined, img, *POS2)
        output_path = os.path.join(OUTPUT_DIR, f"{prefix}{i:03d}.jpg")
        cv2.imwrite(output_path, combined)
        results.append((output_path, f"{prefix}{i:03d}"))
        if i % 10 == 0:
            gc.collect()

    if not results:
        raise gr.Error("⚠️ 沒有產生圖片")

    with zipfile.ZipFile(ZIP_PATH, "w", zipfile.ZIP_DEFLATED) as zipf:
        for f in sorted(os.listdir(OUTPUT_DIR)):
            if f.endswith(".jpg"):
                zipf.write(os.path.join(OUTPUT_DIR, f), arcname=f)

    return results, ZIP_PATH, f"✅ 成功合成 {len(results)} 張圖,已打包 ZIP"

# 主邏輯:上傳處理
def process_inputs(files, prefix, page_selection):
    prefix = prefix.strip() or "result_"
    selected_pages = parse_page_selection(page_selection)

    images = []
    for file in files:
        name = file.name.lower()
        if name.endswith(".pdf"):
            images.extend(pdf_to_images(file, selected_pages))
        elif name.endswith((".png", ".jpg", ".jpeg")):
            img = Image.open(file).convert("RGB")
            img = np.array(img)
            img = cv2.cvtColor(img, cv2.COLOR_RGB2BGR)
            images.append(img)
        else:
            raise gr.Error(f"不支援的檔案格式:{name}")

    if not images:
        raise gr.Error("⚠️ 沒有有效圖片可處理,請確認頁碼或檔案內容")

    return process_and_combine(images, prefix)

# Gradio UI 元件定義
page_selection = gr.Textbox(label="選擇頁碼(例如:1,3,5-7)", placeholder="留空代表全部頁面")

# 介面建構
demo = gr.Interface(
    fn=process_inputs,
    inputs=[
        gr.Files(label="📎 上傳 PDF 或圖片", file_types=[".pdf", ".png", ".jpg", ".jpeg"]),
        gr.Textbox(label="檔名前綴(可選)", placeholder="例如:poster_"),
        page_selection
    ],
    outputs=[
        gr.Gallery(label="🖼️ 預覽", columns=3, height="auto"),
        gr.File(label="⬇️ 下載 ZIP"),
        gr.Textbox(label="📄 處理日誌")
    ],
    title="PDF 圖片合成工具",
    description="📄🖼️ 將 PDF 或圖片套用固定背景合成為寬圖,背景為 7872x1200,支援 PDF 選擇頁數與多檔處理。"
)

if __name__ == "__main__":
    demo.launch()