javascript实现图片隐写

本文介绍了图片隐写技术,一种将信息隐藏于图片中的方法。包括在图片文件尾部添加信息及利用最低有效位编码技术将信息嵌入像素中。提供了JavaScript实现示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

什么是图片隐写?

图片隐写

发福利了,这是一张图片,这不仅仅是一张图片,如上图将一些信息隐藏在图片中的方式称之为图片隐写,但是有一点既然是隐写,那么肯定是悄悄的写,
图片还是原来的图片,只是里面隐藏了其他的信息。对于上面的图片,保存到本地之后,修改后缀名为.zip,然后用winrar打开,发现这是一个正常的压缩文件,里面包含了我们的福利信息。
这里讨论两种往图片内写入其他信息的方式,一种是在图片文件尾部添加信息,由于每种图片都有自己的文件编码格式,
例如:对于png格式的图片,我们用winHex打开查看,发现文件末尾几个字节的数据总是固定的。
png格式
图片查看器查看图片的时候会忽略掉结束符之后的信息,所以不会影响到图片的显示。如果你用win系统,用copy命令就可以实现。
copy /b 1.png+2.rar 3.png
其中1.png是待写入信息的图片,2.zip是待写入的信息,3.png是最后得到的图片,修改3.png的名字为3.zip即可用压缩软件查看隐藏在图片中的信息。

还有另外一种方式是在人眼不可见的范围之内修改像素信息,将需要写入的信息按照一定的编码方式编码到图片的像素信息内,一种常见的方式就是最低有效位,就是将需要写入的信息
编码到图片像素点的最低有效位。我们知道每个像素都是由三原色红绿蓝三种颜色组成,一个像素点可以由4组8位二进制数表示,红绿蓝以及透明度,这里我们将信息编码到图片的透明度信息中,
透明度分为255级,如果只是修改8位2进制的最后一位,一般人的眼睛是识别不出来。

这里我们用javascript中的canvas来实现编辑图片的像素信息,并将一段文本编码到图片信息中。

function strToUint16Array(str){
    var buf = new ArrayBuffer(str.length * 2);
    var bufView = new Uint16Array(buf);
    for(var i = 0, len = str.length; i < len; i++){
        bufView[i] = str.charCodeAt(i);
    }
    return bufView;
}

var uint16 = strToUint16Array(msg);
var uint16Binary = [];
var msgBinary = uint16.forEach(function(data){
    data = data.toString(2);
    uint16Binary.push(appendStr(data+'', '0', 16));
});

uint16BinaryStr = uint16Binary.join('');

首先我们通过上面的函数将文本串每个字符的unicode码点信息存入到一个Uint16Array对象中,Uint16Array是ES6中一个新的数据类型,对javascript操作二进制数据提供支持。 将Uint16Array中的元素码点都转换为二进制,长度不足16的前缀补0。

var image = new Image();
image.src = event.target.result;

var canvas = document.createElement('canvas');
canvas.height = image.height;
canvas.width = image.width;
document.querySelector('body').appendChild(canvas);
//document.querySelector('body').appendChild(image);
var ctx = canvas.getContext('2d');

ctx.drawImage(image, 0, 0);
var imageData = ctx.getImageData(0, 0, image.width, image.height);

接下来我们通过canvas的getImageData()来获取图片的像素信息。getImageData()方法返回一个ImageData对象,该对象有三个属性ImageData.data, ImageData.height,
ImageData.width,其中ImageData.data类型是Uint8ClampedArray,其中每四个元素表示一个像素点的RGBA信息,接下来遍历像素点信息,写入之前文字编码之后的数据。

for(var i = 0; i < imageData.data.length; i++){
    var piexData = imageData.data[i];
    if(!((i+1) % 4)){
        var hexPiexData = piexData.toString(2);
        var changeValue = uint16BinaryStr.charAt((i+1)/4-1);
        if(changeValue){
            hexPiexData = hexPiexData.substring(0, hexPiexData.length-1) + changeValue;
        }
        imageData.data[i] = parseInt(hexPiexData,2);
    }else{
        imageData.data[i] = piexData;
    }
}

imageData.data的每第四位表示像素点的透明度,也是一个0-255的整数,也就是8位二进制,把文字编码后的二进制字符串每一位,写到代码像素透明度8位2进制的最后一位。
通过canvas的putImageData()方法将imageData写入到canvas中,右键另存为可以把编码之后的图片保存到本地,就得到了一张打上你印记的图片。

上面把信息写到了文件中,人眼不可见,怎么把信息取出来,采用上面的逆序进行操作即可。

var image = new Image();
image.src = event.target.result;

var canvas = document.createElement('canvas');
canvas.height = image.height;
canvas.width = image.width;
document.querySelector('body').appendChild(canvas);
var ctx = canvas.getContext('2d');

ctx.drawImage(image, 0, 0);
var imageData = ctx.getImageData(0, 0, image.width, image.height);

拿到图片的像素信息之后,遍历像素数组,取出每四个元素中的数值并转换为8位进制表示方式,取最后一位即可。

var binarytextInImg='';
imageData.data.forEach(function(item, index){
    if(!((index+1)%4)){    
        var piexData = imageData.data[index].toString(2);      
        var lastIndexStr = piexData.charAt(piexData.length-1);    
        binarytextInImg +=  lastIndexStr               
    }  
});

binarytextInImg变量的每十六位都是一个字符的码点,通过String.fromCharCode即可转换为对应的字符。

function binaryStrToUnit16Array(binaryStr){
    var buf = new ArrayBuffer(parseInt(binaryStr.length / 8));
    var bufView = new Uint16Array(buf);
    var value = '';
    for(var i = 0, len = binaryStr.length; i < len; i++){
        value += binaryStr.charAt(i)
        if(!((i+1)%16)){
            bufView[(i+1)/16-1] = parseInt(value, 2);
            value = '';
        }
    }
    return bufView;
}
var text = uint16ArrayToStr(binaryStrToUnit16Array(binarytextInImg));

得到的text就是隐藏在图片中的文本信息,这个二进制倒腾来倒腾去的好麻烦啊!

写信息戳这里

读信息戳这里

更为详细的图片隐写技术介绍戳这里

没有积分的私聊我 看到消息百分百发给你 1、算法核心: 1、读取图片A,获得其RGB三个通道数据并转换成三个矩阵a1,a2,a3。 2、读取文件B,将其转换成比特流b。 3、遍历b,得到比特b1,b2,b3,b4,b5,b6等等,将b1代替a1第一个元素的最低位,将b2代替a2第一个元素的最低位,将b3代替a3第一个元素的最低位,将b4代替a1第二个元素的最低位,以此类推。 2、具体实现11、使用java ImageIO读取图片,获取其RGB通道信息。 2、使用java NIO读取被嵌入的文件,将其转换为byte数组,需要特别指出的是原生方法得到是byte类型的数组,但是算法实现需要更加精细的操作,所以还需要对得到的byte数组进行进一步的转换封装,将其转换成形如10101的数组。例如,读取文件得到byte数组的第一个元素为63,需将63转换为00111111数组。并且保存好文件的长度。 3、按照算法,遍历形如10101的数组 1、如果遍历到的值为0,将矩阵对应的矩阵元素与0xfe进行与运算,将最低位置为0 2、如果遍历到的值为1,将矩阵对应的矩阵元素与0x01进行或运算,将最低位置为1 4、将步骤3得到的经过经过的矩阵为一张新的图片。 3、读取 1、使用java ImageIO读取图片,获取其RGB通道信息。 2、使用步骤3得到的文件长度,遍历图片的像素矩阵,需要特别指出的是因为后续步骤还需要进行进一步的转化,所以这一步是将得到的“100100......”序列每八位封装为一个数组,最终得到一些数组集合,每个数组包含八位二进制序列。 3、将步骤2得到的数组进行转换,例如00111111应该转换为byte类型数值为63的数字,10111111转换为-63。这一步会得到一个byte类型的数组。 4、将步骤3得到的byte类型数组入文件,需要指出的是入的文件形式应该和模块步骤二中读入的文件形式一致。 3、程序使用方法 1、安装Java8 2、使用命令行进入jar文件所在目录下,使用命令 java -jar 2016115130.jar 3、安装提示输入嵌入和被嵌入的文件名字,注意路径问题
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值