图片传输信息
不想被人看见的信息,通过图片传输
项目介绍
为了方便起见,将代码直接写在html中方便查阅。 encode.html,介绍了是如何将数据信息藏在一张图片中 decode.html,介绍了是如何从一张拥有隐藏信息的图片中,把数据给解读出来.
# encode.html加密
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>test image save</title>
<script src="https://code.jquery.com/jquery-3.2.1.min.js"></script>
</head>
<body>
<img id="testImg" src="" alt="">
<div id="container"></div>
<script>
// 想要藏起来的数据
var data = {
author: 'ifredom',
data: ["2018-01-04", "cool! boy"]
}
// 将JSON对象转换为字节数组
var strData = JSON.stringify(data)
var encoder = new TextEncoder('utf-8')
var unit8array = encoder.encode(strData)
var charset = encoder.encoding
var dataSize = Math.ceil(Math.sqrt(unit8array.length / 3))
// 将字节数组转换为图像数据
// canvas使用的ImageData对象,需要的是Uint8ClampedArray,目前已有一个 uint8array ,所以需要做一下转化
// 由于我需要无损格式来存储我的图像数据,因此我选择PNG图片作为输出格式。这也意味着不是将数据存储为RGB,而是将其存储为RGBA。
// 这里不得不编写代码,将我的3元组字节数组 unit8array 转换为4元组数组 paddedData ,第4个(alpha)组件设置为完全不透明度(255)。
// 每个像素有一个额外的Alpha通道,因此需要额外的字节。但是经过一些实验后,当alpha通道设置为零时,我遇到了一个与RGB损坏有关的问题,所以直接将Alpha设置为255,完全不透明
var paddedData = new Uint8ClampedArray(dataSize * dataSize * 4);
var idx = 0;
for (var i = 0; i < unit8array.length; i += 3) {
var subArray = unit8array.subarray(i, i + 3);
paddedData.set(subArray, idx);
paddedData.set([255], idx + 3);
idx += 4;
}
console.log(paddedData);
// 终于得到想要的数据,Uint8ClampedArray字节数组,可以构造我的ImageData对象了。
var imageData = new ImageData(paddedData, dataSize, dataSize);
// 绘制图形,将ImageData装入canvas图像中
var imgSize = 256;
var canvas = document.createElement('canvas');
canvas.height = canvas.width = imgSize
var ctx = canvas.getContext('2d')
ctx.fillStyle = '#AA0000'
ctx.fillRect(0, 0, imgSize, imgSize)
ctx.fillStyle = 'rgb(' + dataSize + ',0,0)';
ctx.fillRect(0, 0, 1, 1);
// 将数据填充到图形中
ctx.putImageData(imageData, 0, 1);
// 来吧,把图片的下载加上,OK
var container = document.getElementById('container')
container.innerHTML =
`<a id="hiddenLink" href="${canvas.toDataURL()}" download="${canvas.toDataURL()}">下载加密后的文件</a>`
var img = document.getElementById('testImg').setAttribute('src', canvas.toDataURL())
// ==============================================
</script>
</body>
</html>
# decode.html揭秘
<!DOCTYPE html>
<html lang="cn-ZH">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>Document</title>
</head>
<body>
// Uncaught DOMException: Failed to execute 'getImageData' on 'CanvasRenderingContext2D': The canvas has been tainted
by cross-origin data.
<script>
// 这里必须开启一个服务才可以,参考readme~~
initImg()
// am.png是一张藏有数据的图片,现在把它夹在进来.
function initImg() {
var img = new Image();
img.onload = function () {
renderImg(img);
};
img.crossOrigin = 'anonymous';
img.src = 'am.png';
}
function renderImg(img) {
// 创建canvas用来处理图片数据
var imgSize = img.width;
var canvas = document.createElement('canvas');
canvas.width = canvas.height = imgSize;
var ctx = canvas.getContext('2d');
// 将图片信息装入canvas
ctx.drawImage(img, 0, 0);
// 将像素转换为字节数组
// 只需读取第一个像素值的数据并抓取第一个字节以获取数据大小
var headerData = ctx.getImageData(0, 0, 1, 1)
var dataSize = headerData.data[0]
// 创建一个足以容纳RGB数据的uint8array,其中RGBA像素的alpha值始终设置为255
var imageData = ctx.getImageData(0, 1, dataSize, dataSize)
var paddedData = imageData.data
var uint8array = new Uint8Array(paddedData.length / 4 * 3)
// 每4个字节,提取其中前3个字节的值复制到新数组,第四个用来填充的当然是抛弃啦
var idx = 0
for (let index = 0; index < paddedData.length - 1; index += 4) {
var subArray = paddedData.slice(index, index + 3)
uint8array.set(subArray, idx)
idx += 3
}
// 数组uint8array,其中包含我们所有的数据以及最后的大量使用零填充的数据,零填充数据也需要过滤掉。
// 因为我们要填充的数据不太多,而数组的长度是固定的,所以要把最后面的零去掉
// 因此我们需要找到数组中这个零填充结束的位置,从结尾开始遍历数组,直到我们达到第一个非零字节
var includeBytes = uint8array.length
for (let j = uint8array.length - 1; j > 0; j--) {
if (uint8array[j] == 0) {
includeBytes--
} else {
break
}
}
// 解码字节数组
var data = uint8array.slice(0, includeBytes);
var result = (new TextDecoder('utf-8')).decode(data);
console.log(result);
}
</script>
</body>
</html>
源码以及详细介绍
github: !https://github.com/ifredom/node-blog/tree/master/project/picture_encryption