获取PNG中的“分辨率”
前言
换了公司,做的第一个需求:水印预览。
完成功能后,发现有的图片和C艹内核渲染尺寸不一致。分析后发现,C++处理PNG图片时,除了考虑基本像素外,还会按照PNG的分辨率加以缩放。(eg:win下课通过查看图片,水平(或垂直)分辨率:xxx dpi得到值)
dpi、ppi或px等的关系,详见CSS像素、物理像素、逻辑像素、设备像素比、PPI、Viewport 。
获取pHYs
因不是WEB的通用属性,在JS的Img对象中不存在。只能读取图片的二进制提取。
参考W3C上的PNG的描述,PNG由头部描述 + 若干Chunk构成。头部仅包含Width、Height等属性。而我们所需要的分辨率,在某个Chunk中。

通过观(yi)察(yin),发现某个Chunk的名称为pHYs(Physical pixel dimensions:物理像素密度)。死马当活马医,假设就是他了。
- 首先,扒开他的外衣(读取二进制数据
ArrayBuffer)。
// 假设通过<Input>获取了file |
- 而后做一下热身运动(参(chao)考(xi)解析
ArrayBuffer的方法)。
// 通过offset读取buffer数据 |
- 最后,在
ArrayBuffer身上摸来摸去,手法如下:ArrayBuffer是数据原始二进制缓冲区,可通过new Int8Array(buffer.slice(4))切割。TypeArray是处理二进制的数据结构。- PNG的每个Chunk,开始的数据会声明
长度和名称。通过长度,可推断下一个Chunk的位置,类同索引。 - 图片结束时,会有
IEND标志,假若出现了IEND也没有发现pHYs属性,证明此PNG图片无pHYs属性。
完整代码如下:
function read_pHYs(buffer) { |
运行,得到结果:

其他
pHYs包含水平像素点,垂直像素点,以及单位标记位;当单位标记位为1时,代表单位像素/米,当为0时,则代表未知单位。iconfont的png图标,当标记位为0时,单位是像素/英尺;UPNG类库提供了解析PNG更多属性的方法。上文解析Chunk方法出自此处。
关于PNG的更详细信息科参考:png的故事:获取图片信息和像素内容
题外话:Emoji字体(
utf8mb4),参考十分钟搞清字符集和字符编码。