在 Windows 的设置里有个主题色,可以根据壁纸的颜色,设置窗口标题栏和边框、"开始"按钮或任务栏的颜色。在 Twitter 点击图片进入大图模式时,背景颜色会变成当前图片的主色调,切换图片时,背景色也会跟着变换,看起来颇为灵动,遂想动手自己实现一下这个效果。

实现思路

Canvas提供了getImageData()的方法,能获取到图片每个像素点的rgba数据,利用拿到的数据加以计算,就可以计算出整张图片的主色调了。流程如下:

  1. 读取图片数据,将其转换为 Canvas 对象
  2. 在 Canvas 上绘制图片
  3. 使用 getImageData 方法获取图像数据
  4. 遍历图像数据中的像素,计算颜色出现次数
  5. 找到出现次数最多的颜色,即为图片的主色调

把以上流程转化成代码:


const img = new Image();
img.src = 'example.jpg';
img.onload = () => {
  const canvas = document.createElement('canvas');
  canvas.width = img.width;
  canvas.height = img.height;
  const ctx = canvas.getContext('2d');
  ctx.drawImage(img, 0, 0);
  const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
  const pixelData = imageData.data;
  const colorCounts = {};
  let maxCount = 0;
  let dominantColor = [0, 0, 0];
  for (let i = 0; i < pixelData.length; i += 4) {
    const r = pixelData[i];
    const g = pixelData[i + 1];
    const b = pixelData[i + 2];
    const key = `${r}, ${g}, ${b}`;
    if (colorCounts[key]) {
      colorCounts[key]++;
    } else {
      colorCounts[key] = 1;
    }
    if (colorCounts[key] > maxCount) {
      maxCount = colorCounts[key];
      dominantColor = [r, g, b];
    }
  }
  console.log(`Dominant color: rgb(${dominantColor[0]}, ${dominantColor[1]}, ${dominantColor[2]})`);
};

这种方法只能提取一种主色调,想要获取多种主色调,就要使用类似K-Means算法的颜色聚类方法了。