分析图片主色调并返回合适的按钮颜色

33 阅读1分钟
/**
 * 分析图片主色调并返回合适的按钮颜色
 * @param imageUrl 图片地址
 * @returns 按钮颜色配置 { bg: 背景色, color: 图标颜色 }
 */
const analyzeImageColor = (imageUrl: string): Promise<{ bg: string; color: string; hoverBg: string }> => {
  return new Promise((resolve) => {
    const img = new Image()
    img.crossOrigin = 'Anonymous'
    img.src = imageUrl
    
    img.onload = () => {
      try {
        const canvas = document.createElement('canvas')
        const ctx = canvas.getContext('2d')
        if (!ctx) {
          resolve({ bg: 'rgba(0, 0, 0, 0.3)', color: '#fff', hoverBg: 'rgba(0, 0, 0, 0.6)' })
          return
        }

        // 缩小尺寸以提高性能
        const size = 50
        canvas.width = size
        canvas.height = size
        ctx.drawImage(img, 0, 0, size, size)

        const imageData = ctx.getImageData(0, 0, size, size)
        const data = imageData.data
        
        let r = 0, g = 0, b = 0
        const pixelCount = data.length / 4

        // 计算平均颜色
        for (let i = 0; i < data.length; i += 4) {
          r += data[i]
          g += data[i + 1]
          b += data[i + 2]
        }

        r = Math.floor(r / pixelCount)
        g = Math.floor(g / pixelCount)
        b = Math.floor(b / pixelCount)

        // 计算亮度 (使用感知亮度公式)
        const brightness = (r * 299 + g * 587 + b * 114) / 1000

        // 根据亮度选择对比色
        if (brightness > 128) {
          // 亮色背景,使用深色按钮
          resolve({ 
            bg: 'rgba(0, 0, 0, 0.3)', 
            color: '#fff',
            hoverBg: 'rgba(0, 0, 0, 0.6)'
          })
        } else {
          // 暗色背景,使用亮色按钮
          resolve({ 
            bg: 'rgba(255, 255, 255, 0.3)', 
            color: '#000',
            hoverBg: 'rgba(255, 255, 255, 0.6)'
          })
        }
      } catch (error) {
        // 出错时使用默认深色按钮
        resolve({ bg: 'rgba(0, 0, 0, 0.3)', color: '#fff', hoverBg: 'rgba(0, 0, 0, 0.6)' })
      }
    }

    img.onerror = () => {
      // 加载失败时使用默认深色按钮
      resolve({ bg: 'rgba(0, 0, 0, 0.3)', color: '#fff', hoverBg: 'rgba(0, 0, 0, 0.6)' })
    }
  })
}