SVG / HTML → 高清 PNG(系统 Chrome headless)
为什么走这条路
Python 侧的 SVG 光栅化方案在 Windows 上普遍难装:
cairosvg依赖cairocffi,需要系统级 cairo DLL,pip 装完仍可能 import 失败。svglib+reportlab是纯 Python,但对 CSS、dominant-baseline、marker 等支持不全,常渲染错。- ImageMagick / Inkscape 不保证存在。
而 Chrome 和 Edge 在 Windows 上几乎总是存在,无头截图质量高、支持完整 SVG 与 CSS。 先探测浏览器,再决定是否退回 Python 方案。
步骤
1. 探测浏览器路径
import os
cands = [
r"C:\Program Files\Google\Chrome\Application\chrome.exe",
r"C:\Program Files (x86)\Google\Chrome\Application\chrome.exe",
r"C:\Program Files (x86)\Microsoft\Edge\Application\msedge.exe",
r"C:\Program Files\Microsoft\Edge\Application\msedge.exe",
]
print([p for p in cands if os.path.exists(p)])
macOS 用 /Applications/Google Chrome.app/Contents/MacOS/Google Chrome,
Linux 用 google-chrome / chromium。
2. 准备 SVG(三个硬约束)
- 根
<svg>必须带width和height属性,不能只有viewBox——否则浏览器给的尺寸不确定。 惯例:viewBox="0 0 680 400"同时写width="1360" height="800"(2 倍输出)。 - 如果要白底图片,在 SVG 里显式画一个覆盖全幅的
<rect>,不要依赖浏览器背景色。 - 不要依赖外部字体 CSS 文件;用系统字体族,渲染时由浏览器解析。
3. 渲染
# 直接渲染 SVG 文件
chrome --headless=new --disable-gpu --hide-scrollbars \
--force-device-scale-factor=2 \
--screenshot="out.png" \
--window-size=1360,800 \
"file:///D:/path/to/fig.svg"
Windows PowerShell 版:
$chrome = "C:\Program Files\Google\Chrome\Application\chrome.exe"
& $chrome --headless=new --disable-gpu --hide-scrollbars `
--force-device-scale-factor=2 `
--screenshot="D:\out\fig.png" `
--window-size=1360,800 `
"file:///D:/path/to/fig.svg" 2>&1 | Out-String
参数说明:
| 参数 | 作用 |
|---|---|
| --headless=new | 新版无头模式(老版 --headless 在部分版本已弃用) |
| --force-device-scale-factor=2 | 出 2 倍图,插进 PDF / 打印时更清晰 |
| --window-size=W,H | 必须与 SVG 的 width/height 一致,否则留白或裁切 |
| --hide-scrollbars | 避免边缘出现滚动条 |
| --default-background-color=00000000 | 要透明背景时加这个(ARGB,8 位十六进制) |
4. 验证(不可省)
渲染完一定要用 Read 工具把 PNG 读出来看一眼,检查:
- 边缘有没有元素被裁掉(
--window-size给小了) - 四周有没有多余留白(
--window-size给大了) - 中文有没有变成方块(字体族没落上)
只看文件大小或“命令返回 0”是不够的——截图失败也可能生成一个空白 PNG。
已知限制
--screenshot只截视口,不截整页。 渲染 HTML 且高度不确定时,先估算一个足够大的--window-size,或者用playwright的fullPage: true(需要pip install playwright && playwright install chromium,较重,非必要不用)。- 批量渲染要逐个调用,每次一个
--screenshot,不要试图一次渲染多个文件。 - 首次启动 Chrome 可能较慢(初始化 profile),属正常;连续调用第二次会快很多。
- 渲染含外部资源的 HTML 时,如果页面用
fetch/ XHR 拉数据,截图时机可能早于数据到达。 这种情况改用--virtual-time-budget=5000给页面留出执行时间。
从 markdown 文档生成图片的配套做法
如果图是从 markdown 渲染出来的预览页(例如用 marked),常见两个坑:
- 相对路径的本地图片在别处打不开:把
<img src="figures/x.png">转成data:image/png;base64,...内联,页面才自包含。 - marked v12 不给标题生成 id:页内目录锚点会点不动,需要自己按 GitHub 的 slug 规则补 id
(小写、去标点、空格转
-)。
微信扫一扫