博客魔改教程:通过RGB提取主题色实现深色模式背景效果
对于这个功能个人感觉也是非常香,不过我后来参照heo方式,改为腾讯云API方式获取RGB了,目前把通过rgbaster和腾讯API方式都分享出来
效果预览
对于提取主题色,看过生成封面图片主色来作为文章封面顶图的文章,无意中看到了一篇帖子是关于这个的,于是便根据这个,加上Heo的教程,便解决了这个问题。
魔改步骤
- 使用regster方案
- [新建]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
/js/rgbaster.min.js
- 使用
对于使用,就是调用这个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()
由于此代码是根据本人博客结构实现的,不一定在您的博客上可以生效,如果有什么问题,相信您可以自行调试成功解决。
空空如也!