优化一下 markdown_to_image.py
This commit is contained in:
@@ -8,6 +8,38 @@ import asyncio
|
||||
from loguru import logger
|
||||
|
||||
|
||||
async def safe_close_browser(browser, timeout: float = 5.0) -> None:
|
||||
if not browser:
|
||||
return
|
||||
|
||||
# Close contexts first to reduce hanging risk.
|
||||
try:
|
||||
for ctx in browser.contexts:
|
||||
try:
|
||||
await asyncio.wait_for(ctx.close(), timeout=timeout)
|
||||
except Exception:
|
||||
pass
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
# Then close browser with timeout.
|
||||
try:
|
||||
await asyncio.wait_for(browser.close(), timeout=timeout)
|
||||
return
|
||||
except asyncio.TimeoutError:
|
||||
logger.warning("Browser close timed out, killing process")
|
||||
except Exception as e:
|
||||
logger.warning(f"Browser close failed, killing process: {e}")
|
||||
|
||||
# Final fallback: kill underlying process.
|
||||
try:
|
||||
proc = browser.process
|
||||
if proc:
|
||||
proc.kill()
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
|
||||
# ================= 样式与 HTML 处理 =================
|
||||
|
||||
async def md_str_to_html_content(md_content):
|
||||
@@ -99,23 +131,28 @@ async def html_to_image(html_content, output_image):
|
||||
]
|
||||
|
||||
if browser_path:
|
||||
logger.debug(f"Launch chromium with system chrome: {browser_path}")
|
||||
browser = await p.chromium.launch(executable_path=browser_path, args=launch_args)
|
||||
else:
|
||||
logger.debug("Launch chromium with bundled browser")
|
||||
browser = await p.chromium.launch(args=launch_args)
|
||||
|
||||
try:
|
||||
# 使用更高的 device_scale_factor 可以让图片更清晰
|
||||
context = await browser.new_context(device_scale_factor=2)
|
||||
context = await browser.new_context(device_scale_factor=1)
|
||||
page = await context.new_page()
|
||||
|
||||
# 3. 动态调整高度:先探测内容实际高度
|
||||
logger.debug("Measure body height")
|
||||
body_height = await page.evaluate("document.body.scrollHeight")
|
||||
await page.set_viewport_size({"width": 750, "height": body_height})
|
||||
# 2. 【关键】强制等待所有字体和 Emoji 加载完成
|
||||
# 很多时候卡住就是在等字体渲染计算
|
||||
logger.debug("Wait for fonts ready")
|
||||
await page.evaluate("document.fonts.ready")
|
||||
# 【优化核心】:直接设置 HTML 内容,不走 file:// 协议
|
||||
# 这样可以彻底避免文件读取超时
|
||||
logger.debug("Set page content")
|
||||
await page.set_content(html_content, wait_until='load')
|
||||
|
||||
# 稍微等待一下确保 CSS 渲染完成
|
||||
@@ -123,6 +160,7 @@ async def html_to_image(html_content, output_image):
|
||||
|
||||
# 截图(full_page=True 会自动处理高度)
|
||||
# 4. 截图增加超时限制,防止死锁
|
||||
logger.debug(f"Take screenshot: output={output_image}, height={body_height}")
|
||||
await page.screenshot(
|
||||
path=output_image,
|
||||
full_page=True,
|
||||
@@ -133,7 +171,8 @@ async def html_to_image(html_content, output_image):
|
||||
raise RuntimeError(f"截图失败,输出文件不存在: {output_image}")
|
||||
|
||||
finally:
|
||||
await browser.close()
|
||||
logger.debug("Closing browser")
|
||||
await safe_close_browser(browser)
|
||||
|
||||
|
||||
# ================= 主转换函数 =================
|
||||
|
||||
Reference in New Issue
Block a user