Files
jiazi-gala-poster-demo/scripts/export_pdf.py
T
rogerwang2008 b9ed01d91b feat: 放大标题并调整标题框
- 标题框左右各留 2 格,高度改为 4 行
- 标题字号 1.6em 放大到 1.8em
- PDF 默认输出恢复为 dist/封面demo.pdf,移除根目录旧 PDF
2026-11-10 21:52:05 +08:00

152 lines
4.4 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
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.
"""将 index.html 导出为 PDF,画面四边各留恰好 1em。
页面为 28 × 44 格文字画,1em 即一个汉字格。导出页尺寸为 30em × 46em,
场景四周各留 1em;底色铺满整页。
用法:
uv run python scripts/export_pdf.py
uv run python scripts/export_pdf.py --em 16 -o dist/封面demo-16.pdf
"""
from __future__ import annotations
import argparse
import pathlib
from playwright.sync_api import sync_playwright
ROOT = pathlib.Path(__file__).resolve().parents[1]
HTML = ROOT / "index.html"
COLS = 28
ROWS = 44
MARGIN_EM = 1
def export_css(em: float) -> tuple[str, float, float]:
page_w = (COLS + MARGIN_EM * 2) * em
page_h = (ROWS + MARGIN_EM * 2) * em
css = f"""
@page {{ size: {page_w:g}px {page_h:g}px; margin: 0; }}
html, body {{
width: {page_w:g}px !important;
height: {page_h:g}px !important;
min-height: 0 !important;
margin: 0 !important;
display: block !important;
overflow: hidden !important;
background: #000 !important;
}}
body {{ padding: {em:g}px !important; }}
.scene {{
font-size: {em:g}px !important;
width: {COLS}em !important;
height: {ROWS}em !important;
margin: 0 !important;
}}
* {{
-webkit-print-color-adjust: exact;
print-color-adjust: exact;
}}
"""
return css, page_w, page_h
def launch_browser(pw):
for name, kwargs in (
("Microsoft Edge", {"channel": "msedge"}),
("Google Chrome", {"channel": "chrome"}),
("Playwright Chromium", {}),
):
try:
return pw.chromium.launch(**kwargs), name
except Exception:
continue
raise SystemExit(
"未找到可用浏览器。请先运行:uv run playwright install chromium"
)
def export(em: float, out: pathlib.Path) -> None:
css, page_w, page_h = export_css(em)
with sync_playwright() as pw:
browser, browser_name = launch_browser(pw)
page = browser.new_page(
viewport={"width": round(page_w), "height": round(page_h)},
device_scale_factor=1,
)
page.goto(HTML.as_uri(), wait_until="load")
page.evaluate("() => document.fonts.ready")
if not page.evaluate("document.fonts.check('16px Zpix')"):
raise SystemExit("Zpix 字体未加载,无法导出。")
page.add_style_tag(content=css)
page.wait_for_timeout(200)
metrics = page.evaluate(
"""() => {
const scene = document.querySelector('.scene').getBoundingClientRect();
const body = getComputedStyle(document.body);
return {
x: scene.x, y: scene.y, w: scene.width, h: scene.height,
pad: [body.paddingTop, body.paddingRight, body.paddingBottom, body.paddingLeft],
};
}"""
)
expected_pad = f"{em:g}px"
if (
abs(metrics["x"] - em) > 0.5
or abs(metrics["y"] - em) > 0.5
or abs(metrics["w"] - COLS * em) > 0.5
or abs(metrics["h"] - ROWS * em) > 0.5
or any(v != expected_pad for v in metrics["pad"])
):
raise SystemExit(f"导出布局校验失败:{metrics}")
out.parent.mkdir(parents=True, exist_ok=True)
page.pdf(
path=str(out),
width=f"{page_w:g}px",
height=f"{page_h:g}px",
margin={"top": "0", "right": "0", "bottom": "0", "left": "0"},
print_background=True,
prefer_css_page_size=True,
)
browser.close()
mm_w = page_w / 96 * 25.4
mm_h = page_h / 96 * 25.4
print(f"浏览器:{browser_name}")
print(f"页面:{page_w:g} × {page_h:g}px(约 {mm_w:.0f} × {mm_h:.0f} mm),四边各 {em:g}px(1em)")
print(f"已导出:{out.relative_to(ROOT)}")
def main() -> None:
parser = argparse.ArgumentParser(description="将文字画页面导出为 PDF(四周各留 1em)")
parser.add_argument(
"--em",
type=float,
default=24,
help="导出时 1em(一个汉字格)的像素大小,默认 24",
)
parser.add_argument(
"-o",
"--out",
type=pathlib.Path,
default=ROOT / "dist" / "封面demo.pdf",
help="输出文件路径,默认 dist/封面demo.pdf",
)
args = parser.parse_args()
if args.em <= 0:
parser.error("--em 必须大于 0")
export(args.em, args.out.resolve())
if __name__ == "__main__":
main()