给浏览器拼贴工具加一个"A4预设"时,我以为最难的是布局计算。结果发现,真正的坑在于:画布上的A4只是一个形状,不是尺寸。如果不把这个说清楚,用户会在打印店才发现问题。
这里记录一下我踩过的坑,以及真正重要的数字。
![]()
画布没有物理尺寸
HTML画布是一个像素网格,只有宽高像素值,没有别的。纸张用毫米计量,连接两者的桥梁是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,同一页面需要:
- 8.27英寸 × 300 =2480像素
- 11.69英寸 × 300 =3508像素
2480×3508比1414×2000多出3.1倍像素。这就是整个取舍的核心。
为什么不直接按300 DPI导出?
因为内存,也因为用户实际上多在手机上操作。
一个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.