首次提交
This commit is contained in:
164
danding_bot/plugins/chatai/screenshot.py
Normal file
164
danding_bot/plugins/chatai/screenshot.py
Normal file
@@ -0,0 +1,164 @@
|
||||
import asyncio
|
||||
import markdown
|
||||
from pyppeteer import launch
|
||||
|
||||
async def markdown_to_image(markdown_text: str, output_path: str, browser=None):
|
||||
"""将 Markdown 转换为 HTML 并使用 Puppeteer 截图。"""
|
||||
try:
|
||||
# 将 Markdown 转换为 HTML
|
||||
html = markdown.markdown(markdown_text)
|
||||
|
||||
# 使用传入的浏览器实例或创建新的
|
||||
should_close_browser = False
|
||||
if browser is None:
|
||||
browser = await launch(headless=True, args=['--no-sandbox', '--disable-setuid-sandbox'])
|
||||
should_close_browser = True
|
||||
|
||||
page = await browser.newPage()
|
||||
|
||||
# 设置页面样式,使内容更美观
|
||||
await page.setContent(f"""
|
||||
<html>
|
||||
<head>
|
||||
<style>
|
||||
body {{
|
||||
font-family: "PingFang SC", "Microsoft YaHei", sans-serif;
|
||||
line-height: 1.6;
|
||||
padding: 30px;
|
||||
max-width: 800px;
|
||||
margin: 0 auto;
|
||||
background-color: transparent;
|
||||
color: #333;
|
||||
}}
|
||||
.container {{
|
||||
background-color: #ffffff;
|
||||
border-radius: 15px;
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
|
||||
padding: 25px;
|
||||
overflow: hidden;
|
||||
}}
|
||||
p {{
|
||||
margin-bottom: 16px;
|
||||
}}
|
||||
code {{
|
||||
font-family: "SFMono-Regular", Consolas, "Liberation Mono", Menlo, monospace;
|
||||
background-color: #f5f7f9;
|
||||
padding: 2px 6px;
|
||||
border-radius: 4px;
|
||||
font-size: 0.9em;
|
||||
}}
|
||||
pre {{
|
||||
background-color: #f5f7f9;
|
||||
padding: 15px;
|
||||
border-radius: 8px;
|
||||
overflow-x: auto;
|
||||
margin: 20px 0;
|
||||
}}
|
||||
pre code {{
|
||||
background-color: transparent;
|
||||
padding: 0;
|
||||
}}
|
||||
h1, h2, h3, h4, h5, h6 {{
|
||||
margin-top: 24px;
|
||||
margin-bottom: 16px;
|
||||
font-weight: 600;
|
||||
line-height: 1.25;
|
||||
}}
|
||||
h1 {{
|
||||
font-size: 1.8em;
|
||||
border-bottom: 1px solid #eaecef;
|
||||
padding-bottom: 0.3em;
|
||||
}}
|
||||
h2 {{
|
||||
font-size: 1.5em;
|
||||
border-bottom: 1px solid #eaecef;
|
||||
padding-bottom: 0.3em;
|
||||
}}
|
||||
blockquote {{
|
||||
padding: 0 1em;
|
||||
color: #6a737d;
|
||||
border-left: 0.25em solid #dfe2e5;
|
||||
margin: 16px 0;
|
||||
}}
|
||||
ul, ol {{
|
||||
padding-left: 2em;
|
||||
margin-bottom: 16px;
|
||||
}}
|
||||
img {{
|
||||
max-width: 100%;
|
||||
border-radius: 8px;
|
||||
}}
|
||||
a {{
|
||||
color: #0366d6;
|
||||
text-decoration: none;
|
||||
}}
|
||||
a:hover {{
|
||||
text-decoration: underline;
|
||||
}}
|
||||
table {{
|
||||
border-collapse: collapse;
|
||||
width: 100%;
|
||||
margin: 16px 0;
|
||||
}}
|
||||
table th, table td {{
|
||||
padding: 8px 12px;
|
||||
border: 1px solid #dfe2e5;
|
||||
}}
|
||||
table th {{
|
||||
background-color: #f6f8fa;
|
||||
}}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
{html}
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
""")
|
||||
|
||||
# 等待内容渲染完成
|
||||
await asyncio.sleep(0.5)
|
||||
|
||||
# 获取内容尺寸并设置视口
|
||||
dimensions = await page.evaluate('''() => {
|
||||
const container = document.querySelector('.container');
|
||||
return {
|
||||
width: container.offsetWidth + 60, // 加上 body 的 padding
|
||||
height: container.offsetHeight + 60
|
||||
}
|
||||
}''')
|
||||
|
||||
# 设置视口大小
|
||||
await page.setViewport({
|
||||
'width': dimensions['width'],
|
||||
'height': dimensions['height'],
|
||||
'deviceScaleFactor': 2 # 提高图片清晰度
|
||||
})
|
||||
|
||||
# 截图,使用透明背景
|
||||
await page.screenshot({
|
||||
'path': output_path,
|
||||
'omitBackground': True, # 透明背景
|
||||
'clip': {
|
||||
'x': 0,
|
||||
'y': 0,
|
||||
'width': dimensions['width'],
|
||||
'height': dimensions['height']
|
||||
}
|
||||
})
|
||||
|
||||
# 关闭页面
|
||||
await page.close()
|
||||
|
||||
# 如果是我们创建的浏览器实例,则关闭它
|
||||
if should_close_browser:
|
||||
await browser.close()
|
||||
|
||||
except Exception as e:
|
||||
# 确保资源被释放
|
||||
if 'page' in locals() and page is not None:
|
||||
await page.close()
|
||||
if should_close_browser and 'browser' in locals() and browser is not None:
|
||||
await browser.close()
|
||||
raise # 重新抛出异常以便上层处理
|
||||
Reference in New Issue
Block a user