给浏览器拼贴工具加一个“A4”预设时,我以为最难的是排版计算。结果发现,真正的坑在于:“A4”在画布上只是一个形状,而不是一个尺寸。如果不在产品里把这个说清楚,用户往往要到打印店才会发现问题。
问题出在单位换算上。HTML画布(canvas)本质是像素网格,只有宽高像素值,没有物理尺寸概念。纸张用的是毫米。连接两者的桥梁是DPI(每英寸点数),而画布本身对DPI毫无感知。
![]()
所以,当预设写着“A4”时,它真正能保证的只有宽高比——1:1.414,这是所有ISO 216纸张共用的比例。这些像素最终在纸上变成多大,完全取决于你导出了多少像素。
预设导出1414×2000像素,正好是A4比例。换算一下:
- A4 = 210×297毫米 = 8.27×11.69英寸
- 1414像素 ÷ 8.27英寸 =171 DPI
- 2000像素 ÷ 11.69英寸 =171 DPI
171 DPI,不是300。家用或办公打印机用这个分辨率完全没问题——正常观看距离下看不出像素点。但如果是照片冲印店,这个数据连他们预期值的一半都不到。
要达到打印店默认的300 DPI,同样一张A4纸需要:
- 8.27英寸 × 300 =2480像素
- 11.69英寸 × 300 =3508像素
2480×3508比1414×2000多出3.1倍像素。这就是全部权衡所在。
为什么不能直接导出高分辨率?
因为内存,也因为人们大多在手机上使用这类工具。
一个2480×3508的画布是870万像素。浏览器以RGBA格式存储,每像素占4字节,光位图就要约35MB,而且是在你还没画任何东西之前。再加上源照片:一个12张照片的拼贴,每张是1200万像素的手机图片,如果全部以全尺寸解码,又要额外占用576MB。
这就是为什么崩溃总是发生在别人的安卓手机上。
让这个功能变得可用的修复方案,是在导入时、合成前对每张源图做降采样:
const MAX_SOURCE_EDGE = 2400;function fitSource(img) {const longest = Math.max(img.width, img.height);if (longest <= MAX_SOURCE_EDGE) return img;const scale = MAX_SOURCE_EDGE / longest;const c = document.createElement('canvas');c.width = Math.round(img.width * scale);c.height = Math.round(img.height * scale);c.getContext('2d').drawImage(img, 0, 0, c.width, c.height);return c;源图需要的像素,永远不应该超过它在输出画面中占据区域所需的像素。如果一张照片落在1414×2000页面四分之一的区域里,长边超过约1000像素的部分,解码后占着内存,最终也会被缩放器丢弃。把长边限制在2400像素,视觉上没有任何损失,却能消除大部分内存压力。
另外值得留意的是,iOS Safari对画布总面积也有限制(旧设备上历史上约为1670万像素)。超过这个限制,你连异常都不会收到——只会得到一张空白画布。
特别声明:以上内容(如有图片或视频亦包括在内)为自媒体平台“网易号”用户上传并发布,本平台仅提供信息存储服务。
Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.