javascript
复制代码
image: {
/**
* 获取图片主色调的 HEX 值
* @param {string} imageUrl - 图片URL(需注意跨域问题)
* @param {number} sampleStep - 采样步长(值越大速度越快,精度越低,默认10)
* @returns {Promise<string>} 主色调的HEX值(如 #ff0000)
* @returns {widthPercent} 采用图片的百分比宽度(小数表示识别图片的范围)
* @returns {heightPercent} 采用图片的百分比高度(小数表示识别图片的范围)
*/
getImageMainColorHex(imageUrl, { sampleStep = 10, widthPercent = 1, heightPercent = 1 } = {}) {
return new Promise((resolve, reject) => {
// 1. 创建图片对象
const img = new Image();
// 解决跨域问题(需服务器配合允许跨域)
img.crossOrigin = 'Anonymous';
img.onload = function () {
try {
// 2. 创建Canvas并绘制图片
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
// 设置Canvas尺寸与图片一致
canvas.width = img.width;
canvas.height = img.height;
ctx.drawImage(img, 0, 0);
// 3. 获取像素数据(Uint8ClampedArray,每4个值代表一个像素的RGBA)
const imageData = ctx.getImageData(0, 0, canvas.width * widthPercent, canvas.height * heightPercent);
const data = imageData.data;
const colorCount = {}; // 存储颜色出现次数 { "r,g,b": count }
// 4. 采样像素(跳过部分像素提升性能)
for (let i = 0; i < data.length; i += 4 * sampleStep) {
const r = data[i]; // 红色通道 (0-255)
const g = data[i + 1]; // 绿色通道 (0-255)
const b = data[i + 2]; // 蓝色通道 (0-255)
const a = data[i + 3]; // 透明度通道 (0-255,透明像素跳过)
// 跳过透明像素
if (a < 128) continue;
// 用 "r,g,b" 作为键统计次数
const colorKey = `${r},${g},${b}`;
colorCount[colorKey] = (colorCount[colorKey] || 0) + 1;
}
// 5. 找到出现次数最多的颜色
let maxCount = 0;
let mainColorKey = '255,255,255'; // 默认白色
for (const [key, count] of Object.entries(colorCount)) {
if (count > maxCount) {
maxCount = count;
mainColorKey = key;
}
}
// 6. 将 RGB 转换为 HEX 格式
const [r, g, b] = mainColorKey.split(',').map(Number);
const hex = `#${((1 << 24) + (r << 16) + (g << 8) + b).toString(16).slice(1)}`;
resolve(hex);
} catch (error) {
reject(new Error(`获取主色调失败:${error.message}`));
}
};
img.onerror = function () {
reject(new Error('图片加载失败(可能是跨域、URL错误或网络问题)'));
};
// 7. 加载图片(最后执行,避免onload未绑定完成)
img.src = imageUrl;
});
},
/**
* 将 Hex 色值转换为 RGB 对象
* @param {string} hex - 支持 #fff、#ffffff、fff 等格式
* @returns {object} { r: number, g: number, b: number }
*/
hexToRgb(hex) {
// 移除 # 号(如果有)
const cleanHex = hex.replace(/^#/, '');
// 处理 3 位简写的 Hex 色值(如 #fff → #ffffff)
const fullHex = cleanHex.length === 3
? cleanHex.split('').map(char => char + char).join('')
: cleanHex;
// 验证 Hex 格式是否正确
if (!/^[0-9A-Fa-f]{6}$/.test(fullHex)) {
throw new Error('无效的 Hex 色值格式,请检查输入');
}
// 转换为 RGB 数值
return {
r: parseInt(fullHex.substring(0, 2), 16),
g: parseInt(fullHex.substring(2, 4), 16),
b: parseInt(fullHex.substring(4, 6), 16)
};
},
/**
* 计算颜色的相对亮度(WCAG 公式)
* @param {object} rgb - { r: number, g: number, b: number }
* @returns {number} 亮度值(0-1 之间)
*/
getRelativeLuminance(rgb) {
// 将 RGB 值转换为 0-1 范围,并进行伽马校正
const normalize = (value) => {
const v = value / 255;
return v <= 0.03928 ? v / 12.92 : Math.pow((v + 0.055) / 1.055, 2.4);
};
const r = normalize(rgb.r);
const g = normalize(rgb.g);
const b = normalize(rgb.b);
// 计算相对亮度
return 0.2126 * r + 0.7152 * g + 0.0722 * b;
},
/**
* 生成高对比度的对比色(符合 WCAG 标准)
* @param {string} hex - Hex 色值
* @param {object} [options] - 可选配置
* @param {string} [options.lightColor='#ffffff'] - 亮色背景的对比色
* @param {string} [options.darkColor='#000000'] - 暗色背景的对比色
* @returns {string} 对比色的 Hex 值
*/
getContrastColor(hex, options = {}) {
const {
lightColor = '#ffffff',
darkColor = '#000000'
} = options;
try {
const rgb = this.hexToRgb(hex);
const luminance = this.getRelativeLuminance(rgb);
// 亮度阈值 0.5(可调整,0.4-0.6 之间都合理)
return luminance > 0.5 ? darkColor : lightColor;
} catch (error) {
console.error('生成对比色失败:', error.message);
return '#000000'; // 默认返回黑色
}
},
/**
* 生成 Hex 色值的反向色(反色)
* @param {string} hex - Hex 色值
* @returns {string} 反向色的 Hex 值
*/
getInverseColor(hex) {
try {
const rgb = this.hexToRgb(hex);
// 计算反色:255 - 原数值
const r = 255 - rgb.r;
const g = 255 - rgb.g;
const b = 255 - rgb.b;
// 转换回 Hex 格式
const toHex = (value) => value.toString(16).padStart(2, '0');
return `#${toHex(r)}${toHex(g)}${toHex(b)}`;
} catch (error) {
console.error('生成反向色失败:', error.message);
return '#ffffff'; // 默认返回白色
}
},
// -------------------------------------
}
html
复制代码
<template>
<div :class="$options.name" style="background-color: lightgray">
<h1>
图片主色调:<span :style="{ color: hex }">{{ hex }}</span>
</h1>
<h1>
图片主色调的对比度HEX值:<span :style="{ color: contrastColor }">{{ contrastColor }}</span>
</h1>
<h1>
图片主色调的反色HEX值:<span :style="{ color: inverseColor }">{{ inverseColor }}</span>
</h1>
</div>
</template>
<script>
export default {
data() {
return {
hex: null,
contrastColor: null,
inverseColor:null,
};
},
created() {
// ------------------- 测试使用示例 -------------------
// 注意:图片URL需满足跨域要求(同域/配置CORS/Base64)
let testImageUrl =
"https://pss.bdstatic.com/static/superman/img/logo/logo_white-d0c9fe2af5.png"; // 替换为实际图片URL
testImageUrl = `~@/../static/img/bg/activeDetail/1.jpg`;
testImageUrl = `~@/../static/demo/testimg.jpg`;
this.$g.image
.getImageMainColorHex(testImageUrl, { heightPercent: 0.15 })
.then((hex) => {
this.hex = hex;
this.contrastColor = this.$g.image.getContrastColor(this.hex);
this.inverseColor = this.$g.image.getInverseColor(this.hex);
console.log(`图片主色调的对比度HEX值:`, this.contrastColor);
console.log(`图片主色调的反色HEX值:`, this.inverseColor);
})
.catch((error) => {
console.error(`错误:${error.message}`);
});
},
};
</script>