本文主要是介绍显性水印和不可见数字水印,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
显性水印和不可见数字水印
显性水印(代码见最后)
-
获取要绘制的画布所在元素
-
获取浏览器的dpr(devicePixelRatio),将画布的宽度和高度乘以dpr, 否则绘制出来的画布会变得模糊
-
创建Image元素开始绘制原始图片
-
绘制显性水印, 设置水印的样式, 水印位置设置在图片右下角
不可见数字水印
function getBitOffset(color):
获取RGB中某一分量对应的位和偏移量
图片编码
function encodeImg(src):
-
获取画布元素的Context
-
画布宽高乘以dpr(devicePixelRatio)
-
绘制水印, 使用getImageData()方法获得水印的像素信息
-
绘制图片, 使用getImageData()方法获得图片的像素信息
-
调用mergeData()方法合并像素信息
function mergeData(ctx, newData, color, originalData):
1. 合并原始图片数据和数字水印的rgb数据.
2. 对于规定的某一个RGB分量,
采用将把没有水印信息的像素通过自增方式全改成偶数,
把有水印信息的像素自增全改成奇数这种编码的方式编码图片
- 绘制合并后的图片
图片解码
function decodeImg(src,color):
- 同encodeImg()方法一样, 使用getImageData()方法获得图片的RGB信息
- 调用processData()方法
function processData(ctx, originalData,color):
- 解码的方式与编码的方式相反
- 将非指定的RGB分量的所有信息置0(像素点置黑)
- 对于指定的RGB分量, 将偶数部分(非水印信息)的信息置0, 其他信息置为255
- 对于alpha通道的信息不处理
结果如图
代码
未解决跨域问题, 不可从外部直接打开html, 需从IDE打开
<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><title>watermark</title></head>
<style>html{margin:0;padding: 0;}.app{display: flex;justify-content: space-around;flex-wrap: wrap;}.canvas{height: 200px;width: 540px;margin-top: 50px;}img{height: 200px;width: 540px;margin-top: 50px;}</style>
<body>
<div class="app"><img src="../images/1.jpg"><canvas class="canvas" id="canvas-mark"></canvas><canvas class="canvas" id="encode-mark"></canvas><canvas class="canvas" id="encode-image"></canvas></div>
<script>//绘制显性水印var canvas_mark=document.getElementById("canvas-mark")var dpr = (scale = window.devicePixelRatio || 1);var rect = canvas_mark.getBoundingClientRect();canvas_mark.width = rect.width * dpr;canvas_mark.height = rect.height * dpr;canvas_mark.style.width = rect.width + "px";canvas_mark.style.height = rect.height + "px";let ctx=canvas_mark.getContext('2d');let img = new Image();img.onload = function () {ctx.drawImage(img, 0, 0, canvas_mark.width, canvas_mark.height);const txt = '@ ChenYin';ctx.fillStyle = '#fff';ctx.globalAlpha = 1;ctx.font = `12px 微软雅黑 light`;ctx.textAlign = 'right';ctx.fillText(txt, canvas_mark.width - 10, canvas_mark.height - 10);}img.src="../images/1.jpg"//绘制数字水印和数字水印结果图//获取RGB中某一分量对应的位和偏移量function getBitOffset(color) {let bit, offset;switch (color) {case 'R':bit = 0;offset = 3;break;case 'G':bit = 1;offset = 2;break;case 'B':bit = 2;offset = 1;break;}return [bit,offset];}//图片编码//合并原始图片数据和数字水印的rgb数据, 采用将把没有信息的像素全改成偶数, 把有信息的像素全改成奇数这种编码的方式function mergeData(ctx, newData, color, originalData) {let oData = originalData.data;let [bit,offset]=getBitOffset(color);for (var 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)) {// // 有信息的像素,该通道最低位置1,可以想想上面的斑点效果是怎么实现的oData[i]++;}}}ctx.putImageData(originalData, 0, 0);}function encodeImg(src) {var textData;var can=document.getElementById('encode-mark');var dpr = (scale = window.devicePixelRatio || 1);var rect = canvas_mark.getBoundingClientRect();can.width = rect.width * dpr;can.height = rect.height * dpr;can.style.width = rect.width + "px";can.style.height = rect.height + "px";var ctx = can.getContext('2d');ctx.font = '30px Microsoft Yahei';ctx.fillText('ChenYin', 200, 120);textData = ctx.getImageData(0, 0, ctx.canvas.width, ctx.canvas.height).data;var img = new Image();// img.crossOrigin = '';var originalData;img.onload = function () {// 获取指定区域的canvas像素信息ctx.drawImage(img, 0, 0,can.width,can.height);originalData = ctx.getImageData(0, 0, ctx.canvas.width, ctx.canvas.height);mergeData(ctx, textData, 'G', originalData)};img.src = src;}//图片解码function processData(ctx, originalData,color) {let data = originalData.data;let [bit,offset]=getBitOffset(color);for (var i = 0; i < data.length; i++) {if (i % 4 == bit) {if (data[i] % 2 == 0) {data[i] = 0;} else {data[i] = 255;}} else if (i % 4 == 3) {continue;//alpha通道不处理} else {data[i] = 0;}}// 将结果绘制到画布ctx.putImageData(originalData, 0, 0);}function decodeImg(src,color) {var encode_image = document.getElementById('encode-image')var dpr = (scale = window.devicePixelRatio || 1);var rect = canvas_mark.getBoundingClientRect();encode_image.width = rect.width * dpr;encode_image.height = rect.height * dpr;encode_image.style.width = rect.width + "px";encode_image.style.height = rect.height + "px";var ctx=encode_image.getContext('2d');var img = new Image();var originalData;img.onload = function () {// 获取指定区域的canvas像素信息ctx.drawImage(img, 0, 0);originalData = ctx.getImageData(0, 0, ctx.canvas.width, ctx.canvas.height);console.log(originalData)processData(ctx, originalData,color)};img.src = src;}encodeImg('../images/1.jpg');decodeImg('../images/1-encode.png','G');</script>
</body></html>
这篇关于显性水印和不可见数字水印的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!