普通采样
const getEdgeColors = (img) => {
const canvas = document.createElement('canvas');
const context = canvas.getContext('2d');
canvas.width = img.width;
canvas.height = img.height;
try {
context.drawImage(img, 0, 0);
// 获取左边缘颜色
const leftPixel = context.getImageData(0, Math.floor(img.height / 2), 1, 1).data;
const leftColor = `rgb(${leftPixel[0]}, ${leftPixel[1]}, ${leftPixel[2]})`;
// 获取右边缘颜色
const rightPixel = context.getImageData(img.width - 1, Math.floor(img.height / 2), 1, 1).data;
const rightColor = `rgb(${rightPixel[0]}, ${rightPixel[1]}, ${rightPixel[2]})`;
console.log('获取图片边缘颜色成功:', leftColor, rightColor);
return { leftColor, rightColor };
} catch (error) {
console.error('获取图片边缘颜色失败:', error);
return { leftColor: '#ffffff', rightColor: '#ffffff' };
}
};
优化:
1)采样多个点而不是只取中间一点,提高颜色准确性;
2)实现边缘区域的平均采样,避免单点采样可能带来的颜色偏差;
3)添加颜色增强处理,使背景色更加美观;
4)优化错误处理机制,确保在各种情况下都能返回合适的颜色值;5)添加颜色平滑过渡效果,使轮播切换时背景色变化更加自然。
// 获取图片边缘颜色 - 优化版本
const getEdgeColors = (img) => {
const canvas = document.createElement('canvas');
const context = canvas.getContext('2d');
canvas.width = img.width;
canvas.height = img.height;
try {
context.drawImage(img, 0, 0);
// 采样点数量和区域大小
const samplePoints = 5; // 垂直方向采样点数量
const sampleWidth = 10; // 水平方向采样宽度
const sampleHeight = Math.floor(img.height / samplePoints); // 每个采样点的高度间隔
// 左边缘颜色采样
let leftR = 0, leftG = 0, leftB = 0;
for (let i = 0; i < samplePoints; i++) {
// 计算当前采样点的垂直位置
const y = Math.floor(sampleHeight * (i + 0.5));
// 获取左边缘区域的平均颜色
const leftData = context.getImageData(0, y, sampleWidth, 1).data;
for (let j = 0; j < sampleWidth * 4; j += 4) {
leftR += leftData[j];
leftG += leftData[j + 1];
leftB += leftData[j + 2];
}
}
// 计算左边缘平均颜色
leftR = Math.floor(leftR / (samplePoints * sampleWidth));
leftG = Math.floor(leftG / (samplePoints * sampleWidth));
leftB = Math.floor(leftB / (samplePoints * sampleWidth));
// 右边缘颜色采样
let rightR = 0, rightG = 0, rightB = 0;
for (let i = 0; i < samplePoints; i++) {
// 计算当前采样点的垂直位置
const y = Math.floor(sampleHeight * (i + 0.5));
// 获取右边缘区域的平均颜色
const rightData = context.getImageData(img.width - sampleWidth, y, sampleWidth, 1).data;
for (let j = 0; j < sampleWidth * 4; j += 4) {
rightR += rightData[j];
rightG += rightData[j + 1];
rightB += rightData[j + 2];
}
}
// 计算右边缘平均颜色
rightR = Math.floor(rightR / (samplePoints * sampleWidth));
rightG = Math.floor(rightG / (samplePoints * sampleWidth));
rightB = Math.floor(rightB / (samplePoints * sampleWidth));
// 颜色增强处理 - 适当提高饱和度
const enhanceColor = (r, g, b) => {
// 计算亮度
const brightness = (r + g + b) / 3;
// 如果颜色太暗或太亮,适当调整
if (brightness < 30) {
// 提亮暗色
return {
r: Math.min(255, r + 30),
g: Math.min(255, g + 30),
b: Math.min(255, b + 30)
};
} else if (brightness > 220) {
// 降低过亮的颜色
return {
r: Math.max(0, r - 20),
g: Math.max(0, g - 20),
b: Math.max(0, b - 20)
};
} else {
// 适当提高饱和度
const max = Math.max(r, g, b);
const min = Math.min(r, g, b);
const delta = max - min;
if (delta > 10) { // 有一定色差才增强饱和度
const saturationFactor = 1.2;
const newR = r + (r - brightness) * saturationFactor;
const newG = g + (g - brightness) * saturationFactor;
const newB = b + (b - brightness) * saturationFactor;
return {
r: Math.min(255, Math.max(0, Math.round(newR))),
g: Math.min(255, Math.max(0, Math.round(newG))),
b: Math.min(255, Math.max(0, Math.round(newB)))
};
}
return { r, g, b };
}
};
// 应用颜色增强
const enhancedLeft = enhanceColor(leftR, leftG, leftB);
const enhancedRight = enhanceColor(rightR, rightG, rightB);
// 生成最终颜色
const leftColor = `rgb(${enhancedLeft.r}, ${enhancedLeft.g}, ${enhancedLeft.b})`;
const rightColor = `rgb(${enhancedRight.r}, ${enhancedRight.g}, ${enhancedRight.b})`;
console.log('获取图片边缘颜色成功:', leftColor, rightColor);
return { leftColor, rightColor };
} catch (error) {
console.error('获取图片边缘颜色失败:', error);
// 返回一个柔和的默认颜色,而不是纯白色
return { leftColor: '#f5f5f5', rightColor: '#f5f5f5' };
}
};
采用切片的方案进行循环填充
// 创建边缘切片的canvas
export const createEdgeSlice = (img: HTMLImageElement, isLeft: boolean): string => {
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
const sliceWidth = 1; // 切片宽度
canvas.width = sliceWidth;
canvas.height = img.height;
if (isLeft) {
if (ctx) {
ctx.drawImage(img, 0, 0, sliceWidth, img.height, 0, 0, sliceWidth, img.height);
} else {
// 如果ctx为null则抛出错误
throw new Error('无法获取canvas上下文');
}
} else {
if (ctx) {
ctx.drawImage(img, img.width - sliceWidth, 0, sliceWidth, img.height, 0, 0, sliceWidth, img.height);
} else {
// 如果ctx为null则抛出错误
throw new Error('无法获取canvas上下文');
}
}
console.log('获取到了边缘切片 base64')
return canvas.toDataURL();
};
采样某个点进行渐变
export const getEdgeColors = (img) => {
const canvas = document.createElement('canvas');
const context = canvas.getContext('2d');
canvas.width = img.width;
canvas.height = img.height;
try {
// 检查 context 是否为 null
if (!context) {
throw new Error('无法获取 canvas context');
}
context.drawImage(img, 0, 0);
// 获取顶部中间位置的左右边缘颜色
const middleX = Math.floor(img.width / 2);
// 使用中间点位即可
const middlePixel = context.getImageData(middleX, 0, 1, 1).data;
// const leftPixel = context.getImageData(0, 0, 1, 1).data;
// const rightPixel = context.getImageData(img.width - 1, 0, 1, 1).data;
const leftPixel = middlePixel;
const rightPixel = middlePixel;
// 创建渐变色字符串
const createGradient = (color, direction) => {
const [r, g, b] = color;
// direction: 渐变方向,可以是'right'或'left'
// r,g,b: RGB颜色值
// 渐变包含6个颜色节点:
// 1. 0%位置: 完全不透明的原始颜色
// 2. 20%位置: 85%透明度
// 3. 40%位置: 60%透明度
// 4. 60%位置: 35%透明度
// 5. 80%位置: 15%透明度
// 6. 100%位置: 完全透明
return `linear-gradient(to ${direction}, rgb(${r}, ${g}, ${b}) 0%, rgba(${r}, ${g}, ${b}, 0.85) 20%, rgba(${r}, ${g}, ${b}, 0.6) 40%, rgba(${r}, ${g}, ${b}, 0.35) 60%, rgba(${r}, ${g}, ${b}, 0.15) 80%, rgba(${r}, ${g}, ${b}, 0) 100%)`;
};
const leftColor = createGradient([leftPixel[0], leftPixel[1], leftPixel[2]], 'right');
const rightColor = createGradient([rightPixel[0], rightPixel[1], rightPixel[2]], 'left');
console.log('获取图片边缘渐变颜色成功:', leftColor, rightColor);
return { leftColor, rightColor };
} catch (error) {
console.error('获取图片边缘颜色失败:', error);
// 返回柔和的默认渐变颜色
const defaultColor = [245, 245, 245]; // #f5f5f5
return {
leftColor: `linear-gradient(to right, rgb(${defaultColor.join(',')}) 0%, rgba(${defaultColor.join(',')}, 0) 100%)`,
rightColor: `linear-gradient(to left, rgb(${defaultColor.join(',')}) 0%, rgba(${defaultColor.join(',')}, 0) 100%)`
};
}
};