"""Playwright 渲染器:将报告 HTML 渲染为图片字节。 签名对应原插件 html_render(html, data, return_url, options)。 """ from __future__ import annotations from typing import Any from .core.utils.logger import logger _SCALE_MAP = { "ultra": 3, "high": 2, "normal": 1, "low": 0.5, } async def html_render( html_content: str, data: dict | None = None, return_url: bool = False, options: dict | None = None, ) -> bytes | str: """渲染 HTML 为图片。返回 bytes(PNG/JPEG)。""" options = options or {} viewport_width = int(options.get("viewport_width", 1440)) viewport_height = int(options.get("viewport_height", 900)) full_page = bool(options.get("full_page", True)) img_type = str(options.get("type", "png")).lower() if img_type in ("jpg", "jpeg"): img_type = "jpeg" quality = int(options.get("quality", 90)) timeout = int(options.get("timeout", 30000)) scale_level = str(options.get("device_scale_factor_level", "normal")).lower() scale = _SCALE_MAP.get(scale_level, 1) try: from playwright.async_api import async_playwright except Exception as e: logger.error(f"[T2I] 无法导入 playwright: {e}") return "" try: async with async_playwright() as p: browser = await p.chromium.launch() page = await browser.new_page( viewport={"width": viewport_width, "height": viewport_height}, device_scale_factor=scale, ) await page.set_content(html_content, wait_until="networkidle", timeout=timeout) shot = await page.screenshot( type=img_type, quality=quality if img_type == "jpeg" else None, full_page=full_page, ) await browser.close() return shot except Exception as e: logger.error(f"[T2I] Playwright 渲染失败: {e}", exc_info=True) return ""