跳到主要内容

打印与PDF导出

打印要的是 矢量仍在矢量。先把整页转 PNG 再打印,再抱怨发糊,是自己把文档投影成了不够的像素。世界单位用 mm/pt 或「CSS px at 96dpi 再换算」;相机是这一页的 viewBox,不是屏幕上的漫游相机。

1. 场景怎么切

文档:与编辑器同一棵树(已剥 chrome)
页面:@page 尺寸 + 每页 viewBox(世界裁切矩形)
打印层:CSS print,直接印 inline SVG
PDF 层:矢量写入(自己生成 PDF 操作符,或打印到系统 PDF)
光栅例外:照片、已烘焙滤镜、必须位图的签名

必须是节点:线稿、图标、文字(若 PDF 要可选中,还要嵌入字体或改走 PDF text 对象)。图表坐标轴、流程图节点同理。

可以光栅:位图照片、阴影/滤镜的确认稿、超复杂重复图案。光栅按 物理 dpi 算像素,不要按屏幕 DPR 偷懒。

export interface PrintPage {
/** 世界坐标下这一页看到的矩形 */
view: { minX: number; minY: number; width: number; height: number };
/** 纸面 mm */
paper: { widthMm: number; heightMm: number };
}

export function pageViewBox(page: PrintPage): string {
const { minX, minY, width, height } = page.view;
return `${minX} ${minY} ${width} ${height}`;
}

export function pngPixelsForPrint(widthMm: number, dpi: number): number {
return Math.max(1, Math.round((widthMm / 25.4) * dpi));
}

屏幕预览可以 96dpi;送印 300dpi。同一 viewBox,backing store 变大。不要把屏幕上那张 2x PNG 拿去印刷。

打印相机按页 meet 进纸面,不要沿用画布漫游 viewBox。preserveAspectRatio响应式。chrome(手柄、网格)必须在克隆里剥掉,与 编辑器 同一条 serialize 纪律。

2. 路径

路径适用
window.print() + print CSS内部工具、浏览器里看一眼;字体和分页靠 CSS
生成 PDF(矢量 path + 嵌入字体)要稳定分页、可发客户、可归档
SVG → PNG → PDF仅当整页已是照片或法律要求位图;默认不要

foreignObject 里的 HTML 打印引擎差异大,见 SMIL / foreignObject。能不用就不用:文字回 SVG text 或 PDF 文本。

多页:每页一个 viewBox 裁切矩形,或打印时把大图拆成多张 <svg>。不要指望一张无限画布 viewBox 自动分页。

导出 PDF 时颜色:屏幕 sRGB 与印刷 CMYK 不是一回事。产品若承诺色准,不要假装 SVG fill="#f00" 就是专红。

@media print 里隐藏 DOM chrome,只留文档 SVG。不要靠用户「系统打印时自己别选页眉」。

3. 不适用

  • 用屏幕相机直接打印:用户正盯着画布角落,纸上会裁成那一块。打印相机按页重新 fit。
  • 为了「清晰」先 4k PNG:矢量文字变像素,文件暴涨,缩放仍糊。
  • 依赖 SMIL / CSS 动画出现在纸上:打印取的是某一静态帧,要先把状态写进属性。

4. 失败形态

症状原因
纸上发糊先转了低分辨率 PNG
左右被裁viewBox 与纸比例不同且 slice,或没设 preserveAspectRatio
缺字 / 方框系统 PDF 没嵌入字体;或文字在 DOM overlay 打印时被 display:none
只有图没有线线在 chrome 层被剥错,或在 canvas 预览没写回
颜色和屏幕差一截当了 sRGB 印刷,没有转换策略

权威资料

核对日期:2026-08-26