获取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
),参考十分钟搞清字符集和字符编码。