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

效果预览

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

魔改步骤
  1. [新建]themes/butterfly/source/js/rgbaster.min.js

    1
    !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);
  2. 引入js

    1
    2
    3
    4
    5
    6
    inject:
    head:
    # - <link rel="stylesheet" href="">

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

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
// 封面纯色
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,果断使用上,当然像七牛云也有,实现方式大同小异

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
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