打印出的图比屏幕小一圈,96 与 72 DPI 混用了
屏幕上刚好铺满 A4 的地图,打印出来只占左上角四分之三,比例尺也对不上。
现象
地图容器设置为 width: 794px; height: 1123px(按 96 DPI 算的 A4)。
浏览器截图导出 PNG,再插入 A4 PDF 打印:
地图只占页面的 75%,比例尺标注的 1 公里量出来是 0.75 公里,
右下角留出大片空白。
原因
存在两套换算:
| 场景 | DPI | A4 像素尺寸 |
|---|---|---|
| CSS / 屏幕 | 96 | 794 × 1123 |
| 传统印刷 | 72 | 595 × 842 |
| 打印输出 | 300 | 2480 × 3508 |
截图是 794 像素宽的位图,按 72 DPI 解释,物理宽度变成
794 / 72 = 11.03 英寸,而 A4 只有 8.27 英寸,
图像被整体缩放到 8.27 / 11.03 = 75%。
反过来,如果导出服务按 96 DPI 写入 PDF 元数据,打印就会正好铺满。 问题不在浏览器截图,而在插入 PDF 时声明的分辨率。
排查过程
- 看导出的位图实际像素尺寸,与 A4 在 96 DPI 下的 794×1123 比较。
- 用图像工具查看位图的 DPI 元数据,是否为 72。
- 在 PDF 里量地图占页面的比例,与
72/96的比值对照。 - 检查 puppeteer 的
deviceScaleFactor与viewport设置。
# 查看图片 DPI 元数据
magick identify -verbose map.png | Select-String -Pattern "Resolution"
# 794 px 在 72 DPI 下 = 11.03 in,A4 宽 8.27 in -> 缩放到 75%
解决方案
导出时明确指定 DPI,并按目标 DPI 计算像素尺寸。
打印 300 DPI 的 A4,需要 8.27 × 300 = 2481 像素宽。
// puppeteer:按 300 DPI 导出 A4
const A4_W = 8.27, A4_H = 11.69, DPI = 300;
await page.setViewport({
width: Math.round(A4_W * 96), // 794,CSS 布局仍按 96
height: Math.round(A4_H * 96),
deviceScaleFactor: DPI / 96 // 3.125,位图放大到 2481×3509
});
await page.screenshot({
path: 'map-a4.png',
clip: { x: 0, y: 0, width: 794, height: 1123 },
type: 'png'
});
# 插入 PDF 时声明正确的 DPI
magick map-a4.png -units PixelsPerInch -density 300 map-a4-300dpi.png
# 或者直接把 DPI 写进位图
magick map.png -density 96 -units PixelsPerInch map-96dpi.png
屏幕上的地图要配合打印,比例尺控件必须用
L.control.scale({ imperial: false, metric: true }),
并在导出前按 DPI 换算一次。
// 比例尺显示的是屏幕像素,导出前需按 DPI 修正
const dpi = 300, cssDpi = 96;
const scale = dpi / cssDpi; // 3.125
// 图上 1 厘米对应实地 = 100 / (scale × 每厘米像素) ...
// 实际做法:让比例尺文字随导出倍率一起缩放
map.getContainer().style.transform = `scale(${1 / scale})`;
验证
导出的 PNG 为 2481×3509,插入 A4 PDF 后铺满整页; 用尺子量图中比例尺的 1 公里段,与 PDF 上标注的长度一致。
console.assert(Math.round(8.27 * 300) === 2481, '像素宽不符');
// 打印后比例尺校验:图上 1 km 应为 8.27 * (1000 / 地图实地宽度) 英寸
适用版本
| 工具 | 版本 | 说明 |
|---|---|---|
| CSS 规范 | — | 96 px = 1 in |
| puppeteer | 21 及以上 | deviceScaleFactor 控制位图倍率 |
| ImageMagick | 7.x | -density 写入 DPI 元数据 |
| Leaflet | 1.9.x | L.control.scale 基于屏幕像素 |
经纬志(2026)。《打印出的图比屏幕小一圈,96 与 72 DPI 混用了》。https://www.jingweizhi.com/cookbook/print-dpi-misalign.html(访问日期 2026-11-03)。