kopia lustrzana https://github.com/dgtlmoon/changedetection.io
105 wiersze
4.1 KiB
Python
105 wiersze
4.1 KiB
Python
|
|
# Pages with a vertical height longer than this will use the 'stitch together' method.
|
|
|
|
# - Many GPUs have a max texture size of 16384x16384px (or lower on older devices).
|
|
# - If a page is taller than ~8000–10000px, it risks exceeding GPU memory limits.
|
|
# - This is especially important on headless Chromium, where Playwright may fail to allocate a massive full-page buffer.
|
|
|
|
|
|
# The size at which we will switch to stitching method
|
|
SCREENSHOT_SIZE_STITCH_THRESHOLD=8000
|
|
|
|
from loguru import logger
|
|
|
|
def capture_stitched_together_full_page(page):
|
|
import io
|
|
import os
|
|
import time
|
|
from PIL import Image, ImageDraw, ImageFont
|
|
|
|
MAX_TOTAL_HEIGHT = SCREENSHOT_SIZE_STITCH_THRESHOLD*4 # Maximum total height for the final image (When in stitch mode)
|
|
MAX_CHUNK_HEIGHT = 4000 # Height per screenshot chunk
|
|
WARNING_TEXT_HEIGHT = 20 # Height of the warning text overlay
|
|
|
|
# Save the original viewport size
|
|
original_viewport = page.viewport_size
|
|
now = time.time()
|
|
|
|
try:
|
|
viewport = page.viewport_size
|
|
page_height = page.evaluate("document.documentElement.scrollHeight")
|
|
|
|
# Limit the total capture height
|
|
capture_height = min(page_height, MAX_TOTAL_HEIGHT)
|
|
|
|
images = []
|
|
total_captured_height = 0
|
|
|
|
for offset in range(0, capture_height, MAX_CHUNK_HEIGHT):
|
|
# Ensure we do not exceed the total height limit
|
|
chunk_height = min(MAX_CHUNK_HEIGHT, MAX_TOTAL_HEIGHT - total_captured_height)
|
|
|
|
# Adjust viewport size for this chunk
|
|
page.set_viewport_size({"width": viewport["width"], "height": chunk_height})
|
|
|
|
# Scroll to the correct position
|
|
page.evaluate(f"window.scrollTo(0, {offset})")
|
|
|
|
# Capture screenshot chunk
|
|
screenshot_bytes = page.screenshot(type='jpeg', quality=int(os.getenv("SCREENSHOT_QUALITY", 30)))
|
|
images.append(Image.open(io.BytesIO(screenshot_bytes)))
|
|
|
|
total_captured_height += chunk_height
|
|
|
|
# Stop if we reached the maximum total height
|
|
if total_captured_height >= MAX_TOTAL_HEIGHT:
|
|
break
|
|
|
|
# Create the final stitched image
|
|
stitched_image = Image.new('RGB', (viewport["width"], total_captured_height))
|
|
y_offset = 0
|
|
|
|
# Stitch the screenshot chunks together
|
|
for img in images:
|
|
stitched_image.paste(img, (0, y_offset))
|
|
y_offset += img.height
|
|
|
|
logger.debug(f"Screenshot stitched together in {time.time()-now:.2f}s")
|
|
|
|
# Overlay warning text if the screenshot was trimmed
|
|
if page_height > MAX_TOTAL_HEIGHT:
|
|
draw = ImageDraw.Draw(stitched_image)
|
|
warning_text = f"WARNING: Screenshot was {page_height}px but trimmed to {MAX_TOTAL_HEIGHT}px because it was too long"
|
|
|
|
# Load font (default system font if Arial is unavailable)
|
|
try:
|
|
font = ImageFont.truetype("arial.ttf", WARNING_TEXT_HEIGHT) # Arial (Windows/Mac)
|
|
except IOError:
|
|
font = ImageFont.load_default() # Default font if Arial not found
|
|
|
|
# Get text bounding box (correct method for newer Pillow versions)
|
|
text_bbox = draw.textbbox((0, 0), warning_text, font=font)
|
|
text_width = text_bbox[2] - text_bbox[0] # Calculate text width
|
|
text_height = text_bbox[3] - text_bbox[1] # Calculate text height
|
|
|
|
# Define background rectangle (top of the image)
|
|
draw.rectangle([(0, 0), (viewport["width"], WARNING_TEXT_HEIGHT)], fill="white")
|
|
|
|
# Center text horizontally within the warning area
|
|
text_x = (viewport["width"] - text_width) // 2
|
|
text_y = (WARNING_TEXT_HEIGHT - text_height) // 2
|
|
|
|
# Draw the warning text in red
|
|
draw.text((text_x, text_y), warning_text, fill="red", font=font)
|
|
|
|
# Save or return the final image
|
|
output = io.BytesIO()
|
|
stitched_image.save(output, format="JPEG", quality=int(os.getenv("SCREENSHOT_QUALITY", 30)))
|
|
screenshot = output.getvalue()
|
|
|
|
finally:
|
|
# Restore the original viewport size
|
|
page.set_viewport_size(original_viewport)
|
|
|
|
return screenshot
|