显性水印和不可见数字水印

显性水印和不可见数字水印

显性水印(代码见最后)
  1. 获取要绘制的画布所在元素

  2. 获取浏览器的dpr(devicePixelRatio),将画布的宽度和高度乘以dpr, 否则绘制出来的画布会变得模糊

  3. 创建Image元素开始绘制原始图片

  4. 绘制显性水印, 设置水印的样式, 水印位置设置在图片右下角

不可见数字水印
function getBitOffset(color):

获取RGB中某一分量对应的位和偏移量

图片编码
function encodeImg(src):
  1. 获取画布元素的Context

  2. 画布宽高乘以dpr(devicePixelRatio)

  3. 绘制水印, 使用getImageData()方法获得水印的像素信息

  4. 绘制图片, 使用getImageData()方法获得图片的像素信息

  5. 调用mergeData()方法合并像素信息

function mergeData(ctx, newData, color, originalData):

​ 1. 合并原始图片数据和数字水印的rgb数据.

​ 2. 对于规定的某一个RGB分量,

​ 采用将把没有水印信息的像素通过自增方式全改成偶数,

​ 把有水印信息的像素自增全改成奇数这种编码的方式编码图片

  1. 绘制合并后的图片
图片解码
function decodeImg(src,color):
  1. 同encodeImg()方法一样, 使用getImageData()方法获得图片的RGB信息
  2. 调用processData()方法
function processData(ctx, originalData,color):
  1. 解码的方式与编码的方式相反
  2. 将非指定的RGB分量的所有信息置0(像素点置黑)
  3. 对于指定的RGB分量, 将偶数部分(非水印信息)的信息置0, 其他信息置为255
  4. 对于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>
  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
要在 Windows 屏幕上显示水印,你可以使用 C++ 编写一个程序,并利用 Windows API 函数来实现这一功能。下面是一个简单的示例代码: ```c++ #include <windows.h> // 水印文本 const wchar_t* watermarkText = L"这是一个水印"; // 水印文本颜色 const COLORREF watermarkColor = RGB(255, 0, 0); // 水印文本字体 const wchar_t* watermarkFontName = L"Arial"; const int watermarkFontSize = 16; int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { // 获取屏幕尺寸 int screenWidth = GetSystemMetrics(SM_CXSCREEN); int screenHeight = GetSystemMetrics(SM_CYSCREEN); // 创建设备上下文 HDC hdcScreen = GetDC(NULL); HDC hdcMem = CreateCompatibleDC(hdcScreen); HBITMAP hBitmap = CreateCompatibleBitmap(hdcScreen, screenWidth, screenHeight); HBITMAP hBitmapOld = (HBITMAP)SelectObject(hdcMem, hBitmap); // 绘制水印文本 HFONT hFont = CreateFont(watermarkFontSize, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH | FF_SWISS, watermarkFontName); HFONT hFontOld = (HFONT)SelectObject(hdcMem, hFont); SetTextColor(hdcMem, watermarkColor); SetBkMode(hdcMem, TRANSPARENT); TextOut(hdcMem, screenWidth / 2, screenHeight / 2, watermarkText, wcslen(watermarkText)); SelectObject(hdcMem, hFontOld); DeleteObject(hFont); // 将设备上下文中的位图绘制到屏幕上 BitBlt(hdcScreen, 0, 0, screenWidth, screenHeight, hdcMem, 0, 0, SRCCOPY); // 清理资源 SelectObject(hdcMem, hBitmapOld); DeleteObject(hBitmap); DeleteDC(hdcMem); ReleaseDC(NULL, hdcScreen); return 0; } ``` 这个示例程序会在屏幕中央绘制一个红色的 Arial 16 号字体的文本“这是一个水印”。你可以根据自己的需要修改水印文本、颜色和字体等参数。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值