来源:Node.js

pngquant

pngquant是一个用于(有损)压缩png图像文件的工具

它可以显著减小png文件的大小,同时也能保持图像质量和透明度

通过减小文件大小,可以提高网页加载速度,并节省存储空间

pngquant提供命令行接口和库,可轻松集成到各种应用程序和脚本中

原理

pngquant使用修改过的Median Cut量化算法以及其他技术来实现压缩PNG图像,它的工作原理:

  1. 构建一个直方图,用于统计图像中的颜色分布情况
  2. 选择盒子来代表一组颜色,与传统的Median Cut算法不同,pngquant选择的盒子会最小化盒子中颜色与中位数的差异
  3. 使用感知模型给予图像中噪声较大的区域较少的权重,以建立更准确的直方图
  4. 为了进一步改善颜色,使用类似梯度下降的过程对直方图进行调整,它多次重复Median Cut算法,并在较少出现的颜色上增加权重
  5. 最后,为了生成最佳的调色板,pngquant使用Voronoi迭代(K-means)对颜色进行校正,以确保局部最优
  6. 在重新映射颜色时,pngquant只在多个相邻像素量化为相同颜色、且不是边缘的区域应用误差扩散,这样可以避免在视觉质量较高且不需要抖动的区域添加噪声

Median Cut量化算法

假设一张8x8像素的彩色图像,每个像素由红色、绿色和蓝色通道组成,每个通道的值范围是0到255

  1. 初始化:将图像中的每个像素视为一个颜色点,并将它们放入一个初始的颜色桶

  2. 选择划分桶:在初始的颜色桶中选择一个具有最大范围的颜色通道,假设选择了红色通道

  3. 划分颜色:对于选定的红色通道,将颜色桶中的颜色按照红色通道的值进行排序,并找到中间位置的颜色值作为划分点。假设划分点的红色值为120

    划分前的颜色桶

    • 颜色1:(100, 50, 200)
    • 颜色2:(150, 30, 100)
    • 颜色3:(80, 120, 50)
    • 颜色4:(200, 180, 160)

    划分后的颜色桶

    • 子桶1:
      • 颜色1:(100, 50, 200)
      • 颜色3:(80, 120, 50)
    • 子桶2
      • 颜色2:(150, 30, 100)
      • 颜色4:(200, 180, 160)
  4. 重复划分:继续选择颜色范围最大的通道,假设选择子桶1中的绿色通道,划分点也是120

    划分前的颜色桶(子桶1)

    • 颜色1:(100, 50, 200)
    • 颜色3:(80, 120, 50)

    划分后的颜色桶(子桶1)

    • 子桶1.1
      • 颜色3:(80, 120, 50)
    • 子桶1.2
      • 颜色1:(100, 50, 200)
  5. 颜色映射:将原始图像中的每个像素颜色映射到最接近的颜色桶中的颜色

    • 假设原始图像中的一个像素为(110, 70, 180),将它映射到颜色1(100, 50, 200)
    • 大致公式为 sqrt((110-100)^2 + (70-50)^2 + (180-200)^2) ≈ 31.62

通过Median Cut算法,可以将原始图像中的颜色数目从64个(8x8 像素)减少到4个颜色桶,从而实现了图像的量化

使用

同样可以用exec调用

1
2
const { exec } = require('child_process')
exec('pngquant Russell.png --output test.png --quality=82 --speed=4')

压缩效果显著

而且区别不算大

参数:

  • --output:输出路径
  • --quality:图片质量,取值为0~100,数值越大质量越高
  • --speed=1:输出速度,取值为0~10, 数值越大速度越快,质量则越低