File size: 4,367 Bytes
b26e489
 
e0538f9
 
 
 
b26e489
 
e0538f9
 
 
b26e489
e170610
600cc03
e170610
 
600cc03
 
e170610
b26e489
 
 
 
e0538f9
e170610
e0538f9
e170610
 
 
 
e0538f9
b26e489
 
e170610
fbe2dc1
b26e489
e0538f9
e170610
e0538f9
 
 
e170610
 
 
 
 
 
 
 
 
600cc03
 
e170610
 
 
ee6f0ce
e170610
 
 
ee6f0ce
e170610
 
 
 
 
600cc03
e170610
 
 
fbe2dc1
e170610
 
 
 
 
e0538f9
e170610
 
 
 
ee6f0ce
e170610
 
 
 
e0538f9
 
e170610
e0538f9
 
b26e489
 
 
 
e0538f9
e170610
b26e489
fbe2dc1
b26e489
fbe2dc1
b26e489
e170610
 
 
 
 
 
b26e489
 
 
 
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
import gradio as gr
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from PIL import Image
from io import BytesIO
import tempfile
import time
import os

def render_fullpage_screenshot(html_code):
    """
    ページを少しずつスクロールしながら複数回のスクリーンショットを撮影し、
    それらを縦方向に結合して1枚の長い画像にする。
    """

    # 1) HTMLコードを一時ファイルに保存
    tmp_file = tempfile.NamedTemporaryFile(suffix=".html", delete=False)
    tmp_path = tmp_file.name
    tmp_file.write(html_code.encode('utf-8'))
    tmp_file.close()

    # 2) ヘッドレスChrome(Chromium)起動オプション設定
    options = Options()
    options.add_argument("--headless")               # ヘッドレスモード
    options.add_argument("--no-sandbox")             # コンテナ環境でのサンドボックス無効化
    options.add_argument("--disable-dev-shm-usage")  # /dev/shmを使わない
    options.add_argument("--force-device-scale-factor=1")  # DPI/スケール固定

    try:
        driver = webdriver.Chrome(options=options)
        # 適当な初期ウィンドウサイズに設定してページを読み込む
        driver.set_window_size(1200, 800)
        driver.get("file://" + tmp_path)

        # 3) ページロード完了を待機
        WebDriverWait(driver, 10).until(
            EC.presence_of_element_located((By.TAG_NAME, "body"))
        )
        # さらにフォントや外部リソースを読み込み終わるまで少し待つ
        time.sleep(2)

        # ---- スクロールバーを非表示にしたい場合 ----
        # (ただし一部ページでレイアウトが変化する可能性があるので要注意)
        driver.execute_script(
            "document.documentElement.style.overflow = 'hidden';"
            "document.body.style.overflow = 'hidden';"
        )
        time.sleep(1)

        # 4) 画面のビューポート高・ページ全体の高さを取得
        viewport_height = driver.execute_script("return window.innerHeight")
        scroll_height = driver.execute_script("return document.body.scrollHeight")

        # スクロール+キャプチャを繰り返す
        images = []
        current_position = 0

        while True:
            # 現在の画面をスクリーンショット
            png = driver.get_screenshot_as_png()
            img = Image.open(BytesIO(png))
            images.append(img)

            # もし次のスクロールでページ末尾を超えるなら、ループを抜ける
            if current_position + viewport_height >= scroll_height:
                break

            # 次のスクロール位置へ移動
            current_position += viewport_height
            driver.execute_script(f"window.scrollTo(0, {current_position})")
            # スクロール後の描画待ち
            time.sleep(1)

        # 5) 取得した複数画像を縦方向に結合
        total_width = max(img.width for img in images)
        total_height = sum(img.height for img in images)
        full_screenshot = Image.new('RGB', (total_width, total_height))

        current_y = 0
        for img in images:
            full_screenshot.paste(img, (0, current_y))
            current_y += img.height

    except Exception as e:
        # 何らかのエラーが発生した場合、1x1の黒画像を返す
        return Image.new('RGB', (1, 1), color=(0, 0, 0))

    finally:
        driver.quit()
        if os.path.exists(tmp_path):
            os.remove(tmp_path)

    return full_screenshot

# Gradioインターフェース
iface = gr.Interface(
    fn=render_fullpage_screenshot,
    inputs=gr.Textbox(lines=15, label="HTMLコード入力"),
    outputs=gr.Image(type="pil", label="フルページスクリーンショット"),
    title="Full Page Screenshot with Scrolling",
    description=(
        "ページを少しずつスクロールしながら複数回キャプチャを撮影し、"
        "最終的に縦に結合して1枚の長い画像を生成します。"
    )
)

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