本文为本站原创,未经允许请勿随意转载,谢谢!
脚本下载:https://www.bilitools.top/t/script/genshinLaunch.user.js
完整Demo下载:http://down.bilitools.top/f/16563450-924029847-91288a
先简单说一说吧,由于目前网页端截屏技术上是很受限的,没有什么好的解决方案。这个脚本里用到的canvas2html.js遇到复杂点的网页就不行了,尤其是dom节点多的、vue等框架的(比例B站),所以建议配合简单点的页面或者demo使用,仅供图一乐,效果没有那么好
尽管如此,更重要的是实现思路(其实也没啥)和经验分享。
下面的代码中的注释简单说明了一下
let canvas = document.createElement("canvas");
let ctx = null;
let lastGray = null;
document.body.appendChild(canvas);
const clock = setInterval(async () => {
// 由html2canvas.js将网页DOM节点转为canvas
await html2canvas(document.body).then(c => {
// 由于需要将canvas节点插入到body中,但我们也不希望它显示出来
c.style.display = "none";
document.body.replaceChild(c, canvas);
canvas = c;
});
ctx = canvas.getContext("2d", {
alpha: false,
willReadFrequently: true
}); // 优化读取速度,但是目前好像不起作用,有大佬知道问题所在的可以在评论区回复一下,谢谢了!
// html2canvas.js截取的是一整个body画面,所以需要计算出用户实际的视窗坐标和大小来截取出当前视窗的画面
// 下面这里用了两种方法获取视窗坐标,后者其实已经被淘汰了,这里是为了兼容部分浏览器
let x = window.scrollX || window.pageXOffset; // 视窗左上角x
let y = window.scrollY || window.pageYOffset; // 视窗左上角y
let w = Math.min(document.body.clientWidth, canvas.width); // 视窗宽度
let h = Math.min(document.body.clientHeight, canvas.height); // 视窗高度
// 从canvas内容获取一个ImageData对象,注意这里进行了截取操作
const img = ctx.getImageData(x, y, w, h);
const data = img.data;
// 这里根据用户的配置计算合适的采样点密度,我的策略是采样点之间上下左右间隔相等
const span = (w >= h) ? Math.floor(w / num) : Math.floor(h / num); // 采样点距离
const x_num = Math.floor(w / span);
const y_num = Math.floor(h / span);
// 下面这里采用位运算,提高效率,下面还有几处同理
const x_offset = Math.floor((w - (x_num - 1) * span) >> 1);
const y_offset = Math.floor((h - (y_num - 1) * span) >> 1);
const cnt = x_num * y_num;
// 用于求平均颜色的累加和
let _r = 0;
let _g = 0;
let _b = 0;
let offset = 0;
// 遍历采样点的rgb值累加
for (let i = 0; i < y_num; i++) {
for (let j = 0; j < x_num; j++) {
offset = (w * (y_offset + i * span) + (x_offset + j * span)) << 2;
_r += data[offset];
_g += data[offset + 1];
_b += data[offset + 2];
}
}
const r = Math.floor(_r / cnt);
const g = Math.floor(_g / cnt);
const b = Math.floor(_b / cnt);
// 这里是人的肉眼灰度感知计算公式,小数有所化简以提高效率
const gray = r * 0.3 + g * 0.59 + b * 0.11;
if (developer) {
// 开发者模式开启后,以下内容将在控制台输出
console.log(`%c rgb(${r},${g},${b}) `, `background-color:rgb(${r},${g},${b})`);
console.log(`gray:${gray}`);
}
if (lastGray && gray >= lastGray + 10 && gray >= 245) {
// 判断前后两次画面灰度变化大不大、是否够“亮”
clearInterval(clock);
genshinLaunch();
} else if (gray <= 235) {
lastGray = gray;
}
}, rate * 1000);