优化一下 markdown_to_image.py

This commit is contained in:
liuwei
2026-02-27 10:02:24 +08:00
parent 2eba88ac95
commit 55ded6a2c2

View File

@@ -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)
# ================= 主转换函数 =================