Nodejs 第十九章(pngquant)

什么是pngquant?

pngquant 是一个用于压缩 PNG 图像文件的工具。它可以显著减小 PNG 文件的大小,同时保持图像质量和透明度。通过减小文件大小,可以提高网页加载速度,并节省存储空间。pngquant 提供命令行接口和库,可轻松集成到各种应用程序和脚本中。

pngquant.com/

原理是什么?

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

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

通过这些步骤,pngquant 能够在保持图像质量的同时,将 PNG 图像的文件大小减小到最低限度。

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中的绿色通道。

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

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

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

    • 子桶1.1:

      • 颜色3: (80, 120, 50)
    • 子桶1.2:

      • 颜色1: (100, 50, 200)

    子桶2中只有两个颜色,不需要再进行划分。

  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 个颜色桶,从而实现了图像的量化

Nodejs 中 调用pngquant

我们同样还是可以用exec命令调用

js 复制代码
import { exec } from 'child_process'
exec('pngquant 73kb.png --output test.png')

73kb 压缩完 之后 22kb

js 复制代码
import { exec } from 'child_process'
exec('pngquant 73kb.png --quality=82 --output test.png')

quality表示图片质量0-100值越大图片越大效果越好

js 复制代码
import { exec } from 'child_process'
exec('pngquant 73kb.png --speed=1 --quality=82 --output test.png')
  • --speed=1: 最慢的速度,产生最高质量的输出图像。

  • --speed=10: 最快的速度,但可能导致输出图像质量稍微降低。

相关推荐
腾讯TNTWeb前端团队3 小时前
helux v5 发布了,像pinia一样优雅地管理你的react状态吧
前端·javascript·react.js
范文杰6 小时前
AI 时代如何更高效开发前端组件?21st.dev 给了一种答案
前端·ai编程
拉不动的猪6 小时前
刷刷题50(常见的js数据通信与渲染问题)
前端·javascript·面试
拉不动的猪7 小时前
JS多线程Webworks中的几种实战场景演示
前端·javascript·面试
FreeCultureBoy7 小时前
macOS 命令行 原生挂载 webdav 方法
前端
uhakadotcom8 小时前
Astro 框架:快速构建内容驱动型网站的利器
前端·javascript·面试
uhakadotcom8 小时前
了解Nest.js和Next.js:如何选择合适的框架
前端·javascript·面试
uhakadotcom8 小时前
React与Next.js:基础知识及应用场景
前端·面试·github
uhakadotcom8 小时前
Remix 框架:性能与易用性的完美结合
前端·javascript·面试
uhakadotcom8 小时前
Node.js 包管理器:npm vs pnpm
前端·javascript·面试