在现代Web开发中,动态获取和处理图像数据是一个常见的需求。例如,你可能希望自动提取一张图片的主色调,以便根据这些颜色进行UI主题调整或其他视觉效果的处理。本文将介绍如何在Vue 3项目中,通过一个图片链接获取图片的颜色信息。
适用场景:设置背景色(例如:根据音乐图片设置主题色)
案例地址:(音乐模块的歌词)
天梦星科技官网https://tmxkj.top/#/music案例截图:
1.废话不多说直接上代码(代码已经封装好,直接调用即可)
async function analyzeImageColors(imageUrl) {
try {
const image = new Image();
image.crossOrigin = 'Anonymous'; // This is important for CORS issues
image.src = imageUrl;
await new Promise((resolve, reject) => {
image.onload = () => resolve();
image.onerror = (err) => reject(err);
});
const canvas = document.createElement('canvas');
const context = canvas.getContext('2d');
canvas.width = image.width;
canvas.height = image.height;
context.drawImage(image, 0, 0, image.width, image.height);
const imageData = context.getImageData(0, 0, image.width, image.height).data;
return getColorsFromImageData(imageData, image.width, image.height);
} catch (error) {
console.error('Error analyzing image:', error);
return null;
}
}
/**
* 获取图片颜色
* @param imageData
* @param width
* @param height
* @description 颜色分别是四个角是颜色,中间是颜色,主体颜色,平均颜色,一共七个颜色
* @returns {{
* middleColors: string[]
* average: string,
* corners: (string|null)[],
* dominant: null,
* secondDominant: null
* }}
*/
function getColorsFromImageData(imageData, width, height) {
const colorCount = {};
let r = 0, g = 0, b = 0;
let totalPixels = width * height;
// Initialize corner colors and middle color arrays
const corners = [null, null, null, null];
const middleColors = [];
for (let i = 0; i < imageData.length; i += 4) {
const red = imageData[i];
const green = imageData[i + 1];
const blue = imageData[i + 2];
const alpha = imageData[i + 3];
if (alpha === 0) continue; // Skip transparent pixels
const colorKey = `${red},${green},${blue}`;
if (!colorCount[colorKey]) {
colorCount[colorKey] = 0;
}
colorCount[colorKey]++;
r += red;
g += green;
b += blue;
// Determine if the pixel is a corner or middle pixel
const x = (i / 4) % width;
const y = Math.floor((i / 4) / width);
if (x === 0 && y === 0) {
corners[0] = colorKey;
} else if (x === width - 1 && y === 0) {
corners[1] = colorKey;
} else if (x === 0 && y === height - 1) {
corners[2] = colorKey;
} else if (x === width - 1 && y === height - 1) {
corners[3] = colorKey;
} else if (x === Math.floor(width / 2) && y === Math.floor(height / 2)) {
middleColors.push(colorKey);
}
}
// Find the dominant and second dominant colors
let dominantColor = null;
let secondDominantColor = null;
let maxCount = 0;
let secondMaxCount = 0;
for (const [color, count] of Object.entries(colorCount)) {
if (count > maxCount) {
secondMaxCount = maxCount;
secondDominantColor = dominantColor;
maxCount = count;
dominantColor = `rgba(${color})`;
} else if (count > secondMaxCount) {
secondMaxCount = count;
secondDominantColor = `rgba(${color})`;
}
}
// Calculate average color
const averageColor = `rgba(${Math.round(r / totalPixels)}, ${Math.round(g / totalPixels)}, ${Math.round(b / totalPixels)})`;
return {
corners: corners.map(color => color ? `rgba(${color})` : null),
middleColors: middleColors.map(color => `rgba(${color})`),
dominant: dominantColor,
secondDominant: secondDominantColor,
average: averageColor,
};
}
/**
* 创建渐变色180deg
* @param mainColor 1主色
* @param topRight 2右上角颜色
* @param center 3中心颜色
* @param bottomRight 4右下角颜色
* @param deg 5径向,默认180deg
* @returns {string} 返回渐变色字符串
*/
function createRadialGradient(mainColor,topRight,center,bottomRight,deg=180) {
return `background: ${mainColor};background: linear-gradient(${deg}deg, ${topRight} 0%,${center} 50%, ${bottomRight} 100%);`
}
export {
analyzeImageColors,
createRadialGradient
};
2.调用方法
/**
* 设置背景颜色
* @param url
* @returns {Promise<string|string>}
*/
function setBackgroundColor(url) {
analyzeImageColors(url || 'https://ts3.cn.mm.bing.net/th?id=OIP-C.8tlwbGsJvlNZwGAGL36W8AHaFS&w=295&h=211&c=8&rs=1&qlt=90&o=6&dpr=2&pid=3.1&rm=2').then(res => {
backgroundStyle.value = createRadialGradient(res.dominant, res.corners[1], res.middleColors, res.corners[3]) || '';
})
}