前端给页面增加暗水印的方法
上一篇文章讲到了在页面上增加明水印的办法,然而明水印比拟好革除,而且对于一些没做解决的图片,当用户间接保留的时候,是没有水印的,这时候信息泄露问题仍然存在。为了解决这样的问题,咱们须要用到暗水印。
实现思路
咱们晓得图片是由多个像素点组成的,通过canvas的getImageData办法,咱们能够失去画布指定矩形的像素数据
getImageData() 办法返回 ImageData 对象,该对象拷贝了画布指定矩形的像素数据。
对于 ImageData 对象中的每个像素,都存在着四方面的信息,即 RGBA 值:
- R - 红色 (0-255)
- G - 绿色 (0-255)
- B - 蓝色 (0-255)
- A - alpha 通道 (0-255; 0 是通明的,255 是齐全可见的)
值得注意的是:RGB 重量值的小量变动,是肉眼无奈分辨的,不影响对图片的辨认。这是咱们在图片上增加暗水印的基石
color/alpha 以数组模式存在,并存储于 ImageData 对象的data属性中。
以下代码可取得被返回的 ImageData 对象中第一个像素的 color/alpha 信息:
red=imgData.data[0];green=imgData.data[1];blue=imgData.data[2];alpha=imgData.data[3];
感兴趣的同学能够打印看一下成果
function createBackgroundImage(content, proportion, tiltAngle) { const can = document.createElement('canvas') can.width = document.body.clientWidth / proportion can.height = document.body.clientHeight / proportion const context = can.getContext('2d') context.rotate(-25 * Math.PI / 180); context.font = "800 30px Microsoft JhengHei"; context.fillStyle = "#000"; context.textAlign = 'center'; context.textBaseline = 'Middle'; context.fillText(content, 100, 100) console.log(context.getImageData(0, 0, can.width, can.height)) return can.toDataURL("image/png")}const div = document.getElementById('content') console.log('div', div) div.style.backgroundImage = `url(${createBackgroundImage('伯约同学', 6, 10)})`
如下所示,给出了对应图片的ImageData后果,它有以下几个属性
- data: Uint8ClampedArray(52752) [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, …]
- colorSpace: "srgb"
- height: 42
- width: 314
Uint8ClampedArray则是对应的像素点,每四个表征一个像素点,而后从左往右,从上往下的程序进行排列。
上面进行一个简略的加密:把加密图案放到原图中,如果原图中对应的重叠像素点有内容,则最低位为1,否则为0
function mergeData(rawImageSrc, watermarkImageSrc) { return new Promise((resolve, reject) => { const img = new Image() img.onload = function () { const myCanvas = document.createElement("canvas"); myCanvas.width = img.width; myCanvas.height = img.height; const ctx = myCanvas.getContext("2d") const bit = 0 const offset = 3 const oImageData = getImageData(rawImageSrc) const oData = oImageData.data const newData = getImageData(watermarkImageSrc).data for (let i = 0; i < oData.length; i++) { if (i % 4 === bit) { // 只批改指标通道 if (newData[i + offset] === 0 && (oData[i] % 2 === 1)) { // 没有信息的像素,将指标通道的奇数像素改为偶数 if (oData[i] === 255) { oData[i]-- } else { oData[i]++ } } else if (newData[i + offset] !== 0 && (oData[i] % 2 === 0)) { // 有信息的像素 oData[i]++ } } } ctx.putImageData(oImageData, 0, 0) resolve(myCanvas.toDataURL("image/png")) } img.src = rawImageSrc }) function getImageData(image) { const img = new Image() img.src = image const myCanvas = document.createElement("canvas"); myCanvas.width = img.width; myCanvas.height = img.height; const myContext = myCanvas.getContext("2d") myContext.drawImage(img, 0, 0); return myContext.getImageData(0, 0, myCanvas.width, myCanvas.height) }
对应的解密办法
function decrypt(watermarkImage) { return new Promise((resolve, reject) => { const img = new Image() img.onload = function () { const myCanvas = document.createElement("canvas"); myCanvas.width = img.width; myCanvas.height = img.height; const ctx = myCanvas.getContext("2d") const imageData = getImageData(watermarkImage) var data = imageData.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; } else { // 敞开其余重量,不敞开也不影响答案,甚至更好看 o(^▽^)o data[i] = 0; } } ctx.putImageData(imageData, 0, 0) resolve(myCanvas.toDataURL("image/png")) } img.src = watermarkImage })}
外围示例代码
const image1 = createBackgroundImage('伯约', 3, 10) const image2 = createBackgroundImage('学', 3, 10) mergeData(image1, image2).then(res => { console.log('res', res) decrypt(image2).then(res => { console.log('finalImage', res) }) })
展现下面的res和finallImage并进行比照大仙,一张是两个字:伯约 另一张只有一个字:学
诚然,下面这个办法并不普适,毕竟加密解密办法都写成固定的了,不过思路是对立的,那就是都在原图的根底上批改像素点。
对于更多内容
具体能够看一下参考文章
1、https://cloud.tencent.com/dev...
2、https://www.cnblogs.com/deepr...
3、https://blog.csdn.net/qq_4419...