满心记 我在人间混日子

通过RGB提取主题色

对于这个功能个人感觉也是非常香,不过我后来参照heo方式,改为腾讯云API方式获取RGB了,目前把通过rgbaster和腾讯API方式都分享出来

对于提取主题色,看过生成封面图片主色来作为文章封面顶图的文章,无意中看到了一篇帖子是关于这个的,于是便根据这个,加上Heo的教程,便解决了这个问题。

  • [新建]themes/butterfly/source/js/rgbaster.min.js

    !function(n){"use strict";var t=function(){return document.createElement("canvas").getContext("2d")},e=function(n,e){var a=new Image,o=n.src||n;"data:"!==o.substring(0,5)&&(a.crossOrigin="Anonymous"),a.onload=function(){var n=t("2d");n.drawImage(a,0,0);var o=n.getImageData(0,0,a.width,a.height);e&&e(o.data)},a.src=o},a=function(n){return["rgb(",n,")"].join("")},o=function(n){return n.map(function(n){return a(n.name)})},r=5,i=10,c={};c.colors=function(n,t){t=t||{};var c=t.exclude||[],u=t.paletteSize||i;e(n,function(e){for(var i=n.width*n.height||e.length,m={},s="",d=[],f={dominant:{name:"",count:0},palette:Array.apply(null,new Array(u)).map(Boolean).map(function(){return{name:"0,0,0",count:0}})},l=0;i>l;){if(d[0]=e[l],d[1]=e[l+1],d[2]=e[l+2],s=d.join(","),m[s]=s in m?m[s]+1:1,-1===c.indexOf(a(s))){var g=m[s];g>f.dominant.count?(f.dominant.name=s,f.dominant.count=g):f.palette.some(function(n){return g>n.count?(n.name=s,n.count=g,!0):void 0})}l+=4*r}if(t.success){var p=o(f.palette);t.success({dominant:a(f.dominant.name),secondary:p[0],palette:p})}})},n.RGBaster=n.RGBaster||c}(window);
  • 引入js

    inject:
    head:
      <link rel="stylesheet" href="">
    
    bottom:
      <script src="/js/rgbaster.min.js"></script>
  • 使用
    对于使用,就是调用这个js,然后根据提取出来的图片设置博客的主题色就可以了,但是由于图片提取出来的颜色可能会太浅等原因,需要特殊处理下。对于里面的addRule设置变量颜色需要自行去修改。

引入如下自定义js,你可以选择新建一个自定义的js文件,也可以在自己原本的自定义文件中使用。对于引入的文件需要保证在引入上述文件之后引入

// 封面纯色
function coverColor() {
    var path = document.getElementById("post-cover")?.src;
    if (path !== undefined) {
        RGBaster.colors(path, {
            paletteSize: 30,
            exclude: ["rgb(255,255,255)", "rgb(0,0,0)", "rgb(254,254,254)"],
            success: function (t) {
                if (t.dominant != 'rgb(66,90,239)') {
                    const c = t.dominant.match(/\d+/g);
                    var value = `rgb(${c[0]},${c[1]},${c[2]})`;
                    if (getContrastYIQ(colorHex(value)) == "light") {
                        value = LightenDarkenColor(colorHex(value), -40)
                    }
                    document.styleSheets[0].addRule(':root', '--Jay-main:' + value + '!important');
                    document.styleSheets[0].addRule(':root', '--Jay-main-op:' + value + '23!important');
                    document.styleSheets[0].addRule(':root', '--Jay-main-op-deep:' + value + 'dd!important');
                    document.styleSheets[0].addRule(':root', '--Jay-main-none:' + value + '00!important');
                    Jay.initThemeColor()
                    document.getElementById("coverdiv").classList.add("loaded");
                }
            }
        });

    } else {
        document.styleSheets[0].addRule(':root', '--Jay-main: var(--Jay-theme)!important');
        document.styleSheets[0].addRule(':root', '--Jay-main-op: var(--Jay-theme-op)!important');
        document.styleSheets[0].addRule(':root', '--Jay-main-op-deep:var(--Jay-theme-op-deep)!important');
        document.styleSheets[0].addRule(':root', '--Jay-main-none: var(--Jay-theme-none)!important');
        Jay.initThemeColor()
    }
}

// RGB颜色转化为16进制颜色
function colorHex(str) {
    var reg = /^#([0-9a-fA-f]{3}|[0-9a-fA-f]{6})$/;
    var that = str;
    if (/^(rgb|RGB)/.test(that)) {
        var aColor = that.replace(/(?:\(|\)|rgb|RGB)*/g, "").split(",");
        var strHex = "#";
        for (var i = 0; i < aColor.length; i++) {
            var hex = Number(aColor[i]).toString(16);
            if (hex === "0") {
                hex += hex;
            }
            strHex += hex;
        }
        if (strHex.length !== 7) {
            strHex = that;
        }
        return strHex;
    } else if (reg.test(that)) {
        var aNum = that.replace(/#/, "").split("");
        if (aNum.length === 6) {
            return that;
        } else if (aNum.length === 3) {
            var numHex = "#";
            for (var i = 0; i < aNum.length; i += 1) {
                numHex += (aNum[i] + aNum[i]);
            }
            return numHex;
        }
    } else {
        return that;
    }
}

// 16进制颜色转化为RGB颜色
function colorRgb(str) {
    var reg = /^#([0-9a-fA-f]{3}|[0-9a-fA-f]{6})$/;
    var sColor = str.toLowerCase();
    if (sColor && reg.test(sColor)) {
        if (sColor.length === 4) {
            var sColorNew = "#";
            for (var i = 1; i < 4; i += 1) {
                sColorNew += sColor.slice(i, i + 1).concat(sColor.slice(i, i + 1));
            }
            sColor = sColorNew;
        }
        // 处理六位的颜色值
        var sColorChange = [];
        for (var i = 1; i < 7; i += 2) {
            sColorChange.push(parseInt("0x" + sColor.slice(i, i + 2)));
        }
        return "rgb(" + sColorChange.join(",") + ")";
    } else {
        return sColor;
    }
}

// 变暗变亮主方法
function LightenDarkenColor(col, amt) {
    var usePound = false;

    if (col[0] == "#") {
        col = col.slice(1);
        usePound = true;
    }

    var num = parseInt(col, 16);

    var r = (num >> 16) + amt;

    if (r > 255) r = 255;
    else if (r < 0) r = 0;

    var b = ((num >> 8) & 0x00FF) + amt;

    if (b > 255) b = 255;
    else if (b < 0) b = 0;

    var g = (num & 0x0000FF) + amt;

    if (g > 255) g = 255;
    else if (g < 0) g = 0;


    return (usePound ? "#" : "") + String("000000" + (g | (b << 8) | (r << 16)).toString(16)).slice(-6);
}

// 判断是否为亮色
function getContrastYIQ(hexcolor) {
    var colorrgb = colorRgb(hexcolor);
    var colors = colorrgb.match(/^rgb\((\d+),\s*(\d+),\s*(\d+)\)$/);
    var red = colors[1];
    var green = colors[2];
    var blue = colors[3];
    var brightness;
    brightness = (red * 299) + (green * 587) + (blue * 114);
    brightness = brightness / 255000;
    if (brightness >= 0.5) {
        return "light";
    } else {
        return "dark";
    }
}
coverColor()

由于我使用的是腾讯云COS,正好也提供了这个API,果断使用上,当然像七牛云也有,实现方式大同小异

function coverColor () {
  var path = document.getElementById("post-cover") ?.src;
  // console.log(path); 
  if (path !== undefined) {
    var httpRequest = new XMLHttpRequest(); //第一步:建立所需的对象
    httpRequest.open('GET', path + '?imageAve', true); //第二步:打开连接  将请求参数写在url中  ps:"./Ptest.php?name=test&nameone=testone"
    httpRequest.send(); //第三步:发送请求  将请求参数写在URL中
    /**
     * 获取数据后的处理程序
     */
    httpRequest.onreadystatechange = function () {
      if (httpRequest.readyState == 4 && httpRequest.status == 200) {
        var json = httpRequest.responseText; //获取到json字符串,还需解析
        var obj = eval('(' + json + ')');
        var value = obj.RGB;
        value = "#" + value.slice(2)
        // console.log(value);
        if (getContrastYIQ(value) == "light") {
          value = LightenDarkenColor(colorHex(value), -50)
        }

        document.styleSheets[0].addRule(':root', '--Jay-main:' + value + '!important');
        document.styleSheets[0].addRule(':root', '--Jay-main-op:' + value + '23!important');
        document.styleSheets[0].addRule(':root', '--Jay-main-op-deep:' + value + 'dd!important');
        document.styleSheets[0].addRule(':root', '--Jay-main-none:' + value + '00!important');
        Jay.initThemeColor()
        document.getElementById("coverdiv").classList.add("loaded");
      }
    };
  } else {
    document.styleSheets[0].addRule(':root', '--Jay-main: var(--Jay-theme)!important');
    document.styleSheets[0].addRule(':root', '--Jay-main-op: var(--Jay-theme-op)!important');
    document.styleSheets[0].addRule(':root', '--Jay-main-op-deep:var(--Jay-theme-op-deep)!important');
    document.styleSheets[0].addRule(':root', '--Jay-main-none: var(--Jay-theme-none)!important');
    Jay.initThemeColor()
  }
}
// RGB颜色转化为16进制颜色
function colorHex (str) {
  var reg = /^#([0-9a-fA-f]{3}|[0-9a-fA-f]{6})$/;
  var that = str;
  if (/^(rgb|RGB)/.test(that)) {
    var aColor = that.replace(/(?:\(|\)|rgb|RGB)*/g, "").split(",");
    var strHex = "#";
    for (var i = 0; i < aColor.length; i++) {
      var hex = Number(aColor[i]).toString(16);
      if (hex === "0") {
        hex += hex;
      }
      strHex += hex;
    }
    if (strHex.length !== 7) {
      strHex = that;
    }
    return strHex;
  } else if (reg.test(that)) {
    var aNum = that.replace(/#/, "").split("");
    if (aNum.length === 6) {
      return that;
    } else if (aNum.length === 3) {
      var numHex = "#";
      for (var i = 0; i < aNum.length; i += 1) {
        numHex += (aNum[i] + aNum[i]);
      }
      return numHex;
    }
  } else {
    return that;
  }
}

// 16进制颜色转化为RGB颜色
function colorRgb (str) {
  var reg = /^#([0-9a-fA-f]{3}|[0-9a-fA-f]{6})$/;
  var sColor = str.toLowerCase();
  if (sColor && reg.test(sColor)) {
    if (sColor.length === 4) {
      var sColorNew = "#";
      for (var i = 1; i < 4; i += 1) {
        sColorNew += sColor.slice(i, i + 1).concat(sColor.slice(i, i + 1));
      }
      sColor = sColorNew;
    }
    // 处理六位的颜色值
    var sColorChange = [];
    for (var i = 1; i < 7; i += 2) {
      sColorChange.push(parseInt("0x" + sColor.slice(i, i + 2)));
    }
    return "rgb(" + sColorChange.join(",") + ")";
  } else {
    return sColor;
  }
}

// 变暗变亮主方法
function LightenDarkenColor (col, amt) {
  var usePound = false;

  if (col[0] == "#") {
    col = col.slice(1);
    usePound = true;
  }

  var num = parseInt(col, 16);

  var r = (num >> 16) + amt;

  if (r > 255) r = 255;
  else if (r < 0) r = 0;

  var b = ((num >> 8) & 0x00FF) + amt;

  if (b > 255) b = 255;
  else if (b < 0) b = 0;

  var g = (num & 0x0000FF) + amt;

  if (g > 255) g = 255;
  else if (g < 0) g = 0;


  return (usePound ? "#" : "") + String("000000" + (g | (b << 8) | (r << 16)).toString(16)).slice(-6);
}

// 判断是否为亮色
function getContrastYIQ (hexcolor) {
  var colorrgb = colorRgb(hexcolor);
  var colors = colorrgb.match(/^rgb\((\d+),\s*(\d+),\s*(\d+)\)$/);
  var red = colors[1];
  var green = colors[2];
  var blue = colors[3];
  var brightness;
  brightness = (red * 299) + (green * 587) + (blue * 114);
  brightness = brightness / 255000;
  if (brightness >= 0.5) {
    return "light";
  } else {
    return "dark";
  }
}
coverColor()

由于此代码是根据本人博客结构实现的,不一定在您的博客上可以生效,如果有什么问题,相信您可以自行调试成功解决。

参考:JayHrnHeo

发表评论

提交评论