Files
abot/utils/markdown_to_image.py
2025-03-24 16:14:55 +08:00

256 lines
8.7 KiB
Python
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import markdown
from playwright.sync_api import sync_playwright
import os
# 将 Markdown 字符串转换为 HTML
def md_str_to_html(md_content, output_html):
"""
将 Markdown 字符串转换为 HTML 文件,并添加支持中文和 Emoji 的样式。
:param md_content: 输入的 Markdown 字符串
:param output_html: 输出的 HTML 文件路径
"""
# 转换 Markdown 为 HTML启用额外功能如表格、代码高亮
html_content = markdown.markdown(md_content, extensions=['extra', 'codehilite'])
# 添加基本的 HTML 结构和样式,支持中文和 Emoji
css = """
<style>
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', 'Noto Sans CJK SC', 'Microsoft YaHei', sans-serif;
padding: 25px 30px;
line-height: 1.7;
max-width: 700px;
margin: 0 auto;
background-color: #f9f9f9;
color: #333;
border: 1px solid #f0f0f0;
}
h1, h2, h3, h4, h5, h6 {
color: #222;
margin-top: 20px;
margin-bottom: 15px;
font-weight: 600;
line-height: 1.4;
}
h1 {
font-size: 1.8em;
padding-bottom: 10px;
border-bottom: 1px solid #eee;
text-align: center;
margin-bottom: 20px;
}
h2 {
font-size: 1.5em;
padding-bottom: 8px;
margin-top: 25px;
border-bottom: 1px solid #eee;
}
h3 {
font-size: 1.3em;
margin-top: 20px;
padding-left: 10px;
border-left: 3px solid #ddd;
}
pre, code {
background-color: #f5f5f5;
padding: 10px;
border-radius: 3px;
font-family: 'Courier New', Courier, monospace;
font-size: 0.9em;
border: 1px solid #eee;
}
table {
border-collapse: collapse;
width: 100%;
margin: 15px 0;
background-color: white;
}
th, td {
border: 1px solid #eee;
padding: 8px 10px;
text-align: left;
}
th {
background-color: #fafafa;
font-weight: 600;
}
/* 确保 Emoji 正确渲染 */
span, p, li {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', 'Noto Sans CJK SC', 'Microsoft YaHei', sans-serif;
}
p {
margin: 12px 0;
color: #333;
line-height: 1.8;
}
ul, ol {
padding-left: 22px;
margin: 15px 0;
}
li {
margin: 5px 0;
line-height: 1.7;
}
blockquote {
margin: 15px 0;
padding: 10px 15px;
background-color: #f8f8f8;
border-left: 4px solid #ddd;
color: #666;
font-size: 0.95em;
}
/* 强调样式 */
strong {
color: #333;
font-weight: 600;
}
/* 链接样式 */
a {
color: #576b95;
text-decoration: none;
}
a:hover {
text-decoration: underline;
}
/* 星级评分样式 */
h3 em {
color: #fa8c16;
font-style: normal;
}
/* 时间和标签样式 */
.time, .tag {
color: #888;
font-size: 0.9em;
}
/* 底部署名样式 */
.signature {
margin-top: 30px;
text-align: right;
color: #888;
font-size: 0.9em;
font-style: italic;
}
</style>
"""
# 写入 HTML 文件
with open(output_html, 'w', encoding='utf-8') as f:
f.write('<html><head>')
f.write('<meta charset="UTF-8">') # 确保 UTF-8 编码
f.write(css)
f.write('</head><body>')
f.write(html_content)
f.write('</body></html>')
# 使用 Playwright 将 HTML 渲染并截图
def html_to_image(html_file, output_image):
"""
使用 Playwright 加载 HTML 文件并截图。
:param html_file: 输入的 HTML 文件路径
:param output_image: 输出的图片文件路径
"""
with sync_playwright() as p:
# TODO 这里使用的比较呆的固定路径,后期优化
browser = p.chromium.launch(executable_path=r"C:\Users\Liu-OPEN\AppData\Local\Google\Chrome\Application\chrome.exe")
page = browser.new_page()
# 加载本地的 HTML 文件
page.goto(f'file://{os.path.abspath(html_file)}')
# 设置 viewport可选根据需要调整
page.set_viewport_size({"width": 750, "height": 700})
# 截图
page.screenshot(path=output_image, full_page=True)
browser.close()
# 主函数:从字符串转换 Markdown 到图片
def convert_md_str_to_image(md_content, output_image):
"""
将 Markdown 字符串转换为图片。
:param md_content: 输入的 Markdown 字符串
:param output_image: 输出的图片文件路径
"""
# 中间生成的 HTML 文件
temp_html = 'temp_output.html'
# 第一步:将 Markdown 字符串转换为 HTML
md_str_to_html(md_content, temp_html)
# 第二步:将 HTML 渲染为图片
html_to_image(temp_html, output_image)
# 可选:删除临时的 HTML 文件
os.remove(temp_html)
print(f"图片已生成:{output_image}")
return os.path.abspath(output_image)
# 示例使用
if __name__ == "__main__":
# 示例 Markdown 字符串(包含中文和 Emoji
md_content = """
# 🌟「极浪先锋体验官群 - 2023年3月24日 总结」🌟
## 📊 今日数据快报
- **总消息数**:📩 200 条
- **最活跃时段**:🔥 09:00 - 10:00 (📈 30 条/小时)
- **聊天时段**:🕒 06:52 - 15:29
## 🌌 话题总结
### 1⃣ 【汽车与驾驶经验分享】 ⭐⭐⭐⭐⭐
🕒 **聊天时段**09:00 - 09:30 (👥 6 人参与)
🔍 **话题回顾**
讨论围绕 **汽车驾驶技巧**及**车主经验**展开,参与者分享了各自驾驶中的趣事与技巧。
- [郑晓杰] 提到 **“空挡溜车”**的经历,引发众人对安全驾驶的讨论。
- [BlackBear] 讲述了被大哥质问的搞笑瞬间,增加了话题热度。
> **金句回顾**"破财免灾,大吉大利。" —— [@BlackBear]
### 2⃣ 【群内轻松话题】 ⭐⭐⭐⭐
🕒 **聊天时段**09:45 - 10:15 (👥 8 人参与)
🔍 **高能讨论**
群友们开始轻松调侃,涉及 **食物与地方特产**,特别是关于[普宁豆酱]和[绿豆饼]的分享。
- [Jiojio] 提到自己带的特产,唤起了大家的食欲。
- [寸头男孩] 要求带些地方小吃,气氛轻松愉快。
📌 **实用干货**:推荐了 **地方特产和美食**,引发食物讨论的热潮。
### 3⃣ 【生活琐事与幽默分享】 ⭐⭐⭐⭐
🕒 **聊天时段**10:20 - 11:00 (👥 7 人参与)
🔍 **讨论亮点**
大家分享生活中的小趣事和笑话,增加了群内的亲密感。
- [别吃,很胖了] 提到自己的幽默日常,且引发众人的共鸣。
- [郑晓杰] 也分享了自己的搞笑经历,让大家捧腹大笑。
> **精华总结**"我只知道一个轻推的习惯。" —— [@郑晓杰]
### 4⃣ 【求姻缘与生活感悟】 ⭐⭐⭐
🕒 **聊天时段**12:30 - 13:00 (👥 5 人参与)
🔍 **精彩瞬间**
群友们开始讨论 **求姻缘的经历**,分享了不同的见解与感悟。
- [别吃,很胖了] 替朋友祈福的经历引起了共鸣,大家讨论了姻缘与生活的连接。
- 参与者们分享了自己的求姻缘故事,增加了互动。
### 5⃣ 【汽车品牌及车型讨论】 ⭐⭐⭐
🕒 **聊天时段**14:00 - 15:00 (👥 6 人参与)
🔍 **讨论小结**
群友们热烈讨论了 **汽车品牌与车型**,特别是极氪与特斯拉的比较。
- [Ailian] 表达了对特斯拉的看法,同时引发了对其他品牌的讨论。
- [BlackBear] 和其他成员对各自的车型进行了幽默的调侃。
## 🎖️ 今日荣誉榜
🏆 **群聊 MVP**[@BlackBear]
👑 **获奖理由**
✅ 发起 3 个热门话题
✅ 贡献 5 个幽默段子
✅ **创新贡献**"破财免灾"的智慧分享,让大家倍感轻松。
✨ *本总结由 AI 自动生成,快来看看你今天是不是最靓的崽!🔥*
"""
spath = convert_md_str_to_image(md_content, "output.png")
print(spath)