1. 实现原理
提取图片主色调的核心步骤:
- 使用
canvas绘制图片 - 通过
getImageData获取像素点的 RGBA 数据 - 遍历像素数据,统计颜色出现频率
- 找到出现次数最多的颜色作为主色调
2. 基础实现
function getMainColor(img, step = 5) {
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
canvas.width = img.width;
canvas.height = img.height;
ctx.drawImage(img, 0, 0);
try {
const { data } = ctx.getImageData(0, 0, canvas.width, canvas.height);
const colorCount = {};
let maxColor = '';
let maxCount = 0;
for (let i = 0; i < data.length; i += 4 * step) {
const r = data[i];
const g = data[i + 1];
const b = data[i + 2];
const color = `${r},${g},${b}`;
colorCount[color] = (colorCount[color] || 0) + 1;
if (colorCount[color] > maxCount) {
maxCount = colorCount[color];
maxColor = color;
}
}
return `rgb(${maxColor})`;
} catch (err) {
console.error('图片跨域或读取失败:', err);
return null;
}
}
// 用法示例
const img = new Image();
img.crossOrigin = 'anonymous';
img.src = 'https://picsum.photos/300';
img.onload = () => {
const color = getMainColor(img, 10);
document.body.style.backgroundColor = color;
};
2.2 step 参数说明
step表示像素采样的间隔step越小 → 采样越密集,颜色统计越精确,但计算量越大step越大 → 采样越稀疏,计算更快,但精度下降
示例:
step = 1→ 计算量最大,最精准step = 10→ 只取部分像素,速度快
3. 性能优化:使用 Web Worker
当图片像素较大,或 step 较小导致计算量很大时,直接在主线程计算会阻塞 UI。
可以将颜色计算任务交给 Web Worker,让其在独立线程中运行。
3.1 创建 colorWorker.js
self.onmessage = function (e) {
const { data, step } = e.data;
const colorCount = {};
let maxColor = '';
let maxCount = 0;
for (let i = 0; i < data.length; i += 4 * step) {
const r = data[i];
const g = data[i + 1];
const b = data[i + 2];
const color = `${r},${g},${b}`;
colorCount[color] = (colorCount[color] || 0) + 1;
if (colorCount[color] > maxCount) {
maxCount = colorCount[color];
maxColor = color;
}
}
self.postMessage(`rgb(${maxColor})`);
};
3.2 主线程使用
function getMainColorWithWorker(img, step = 5) {
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
canvas.width = img.width;
canvas.height = img.height;
ctx.drawImage(img, 0, 0);
try {
const { data } = ctx.getImageData(0, 0, canvas.width, canvas.height);
const worker = new Worker('colorWorker.js');
worker.postMessage({ data, step });
worker.onmessage = function (e) {
const color = e.data;
document.body.style.backgroundColor = color;
};
} catch (err) {
console.error('图片跨域或读取失败:', err);
}
}
const img = new Image();
img.crossOrigin = 'anonymous';
img.src = 'https://picsum.photos/300';
img.onload = () => {
getMainColorWithWorker(img, 10);
};
4. 使用 Vibrant.js 提取主色调(推荐)
虽然原生实现可行,但 Vibrant.js 提供了更智能的调色算法,可以提取多种代表性颜色(如 Vibrant、Muted 等),并且使用简单。
安装
npm install node-vibrant
或直接使用 CDN:
<script src="https://cdn.jsdelivr.net/npm/node-vibrant/dist/vibrant.min.js"></script>
用法示例
const img = new Image();
img.crossOrigin = 'anonymous';
img.src = 'https://picsum.photos/400/300';
img.onload = () => {
Vibrant.from(img)
.getPalette()
.then((palette) => {
console.log('Vibrant:', palette.Vibrant.getHex());
console.log('Muted:', palette.Muted.getHex());
document.body.style.backgroundColor = palette.Vibrant.getHex();
});
};
Vibrant.js 提取的颜色类型
- Vibrant:鲜艳主色
- Muted:柔和主色
- DarkVibrant:深色鲜艳
- DarkMuted:深色柔和
- LightVibrant:浅色鲜艳
5. 注意事项
-
跨域问题
- 如果图片跨域且服务器未返回
Access-Control-Allow-Origin,getImageData会报错 - 解决方法:
- 确保服务器允许跨域访问
- 使用同源图片或后端代理
- 如果图片跨域且服务器未返回
-
性能建议
- 小图可以直接主线程计算
- 大图或精度要求高时建议使用 Web Worker
- 根据场景合理调整
step参数

6741

被折叠的 条评论
为什么被折叠?



