加密信息

1
2
3
4
var textData
ctx.font='30px Microsoft Yahei'
ctx.fillText('日升于东', 60, 130)
textData = ctx.getImageData(0,0, ctx.canvas.width, ctx.canvas.height).data

图片信息

1
2
3
4
5
6
7
8
var img = new Image()
var originalData
img.onload = function(){
ctx.drawImage(img, 0, 0)
originalData = ctx.getImageData(0,0, ctx.canvas.width, ctx.canvas.height)
mergeData(textData, 'R')
}
img.src='/images/me.jpg'

合并信息

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

var mergeData = function(newData, color){
var oData = originalData.data // 原始图片信息
var bit, offset
var bit_offset = {
R: { bit:0, offset: 3},
G: { bit:1, offset: 2},
B: { bit:2, offset: 1}
}
let {bit,offset} = bit_offset[color]
for(let i = 0; i < oData.length; i++){
if(i % 4 == bit){
if(newData[i + offset] === 0 && (oData[i] % 2 === 1)){
// 没有信息的像素,该通道最低位置0,但不要越界
if(oData[i] === 255){
oData[i]--;
} else {
oData[i]++;
}
} else if (newData[i + offset] !== 0 && (oData[i] % 2 === 0)){
// 信息的像素,该通道最低位置1
oData[i]++;
}
}
}
ctx.putImageData(originalData, 0, 0)
}

解码

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

var processData = function(originalData){
var data = originalData.data
for(var i = 0; i < data.length; i++){
if(i % 4 == 0){
// 红色分量
if(data[i] % 2 == 0){
data[i] = 0
} else {
data[i] = 255
}
} else if(i % 4 == 3){
// alpha通道不做处理
// continue
data[i] = 136
} else {
// 关闭其他分量,不关闭也不影响答案,甚至更美观
// data[i] = 0
}
}
// 将结果绘制到画布
ctxTransform.putImageData(originalData, 0, 0)
}

var img = new Image()
var originalData
img.onload = function(){
ctxTransform.drawImage(img, 0, 0)
originalData = ctxTransform.getImageData(0,0, ctx.canvas.width, ctx.canvas.height)

processData(originalData)
}
img.src='/images/mesercet.png'

MutationObserver

元素异动监控

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

const MutationObserver = window.MutationObserver || window.WebKitMutationObserver || window.MozMutationObserver;

export const observer = (callback) => {
if (!MutationObserver) return false
let bodyObserver = new MutationObserver(
mutationsList => mutationsList.forEach(mutation =>
mutation.removedNodes.forEach(
_target => _target.id === _id && callback()
)
)
)
bodyObserver.observe(document.body, {childList: true});
const target = document.getElementById(_id);
let observer = new MutationObserver(callback);
observer.observe(target, {characterData: true, attributes: true, childList: true, subtree: true});
return {bodyObserver, observer};
}

参考资料
水印破解