参考自:https://github.com/oakes/PixelJihad
千里码:隐写术-1
canvas文档:https://developer.mozilla.org/zh-CN/docs/Web/API/HTMLCanvasElement

藏有信息的lenna

lenna.png

读取隐藏信息


前言

这里说一下我的心路历程。
最开始做千里码的时候就看到这个题了,觉得很有意思,但是一直不太理解最低有效位是个什么东西,也没有深究,觉得很神秘的样子。后来慢慢偶尔看到隐写术多看两眼,就了解到了。
这里我想说的是啊,针对我这种白痴的blog还是太少,对图片处理稍微不了解或者没听说过一些没解释的名词就看不懂了,很难受。

原理

图片基本单位?
每一个像素,就是屏幕上最小的一个点,就是图片最基本的一个单位了。
一个像素点在canvas中可以获取哪些信息?
类似于css中一种取色方法rbga,这四个字母分别代表红绿蓝以及透明度,这四个值在canvas中可以以数组形式读取。
获取图片的数据数组?
F12打开浏览器控制台执行下面的代码,就可以看到我lenna图片的数据,推荐使用chrome浏览器或chrome内核。

var canvas = document.createElement('canvas');
var img = new Image();
var ctx = canvas.getContext('2d');
img.onload = function(){
    ctx.canvas.width = img.width;
    ctx.canvas.height = img.height;
    ctx.drawImage(img, 0, 0);
}
img.src = 'https://m00zik.com/usr/uploads/2017/12/3001927610.png';
console.log(ctx.getImageData(0, 0, 256, 256));

我本人是比较喜欢这种比较直接的展示形式,大白话说半天真不如试一下。

执行了上面的代码后,会看到返回了一个 ImageData对象,里面的 data就是图片的数据了。
里面每4个数字,就代表了一个像素点,分别是红、绿、蓝、透明度。
信息就隐藏在这些数字里。
最低有效位是什么?
把数字转换成二进制,最后那一位就是最低有效位英文 least significant bit,简称就是 LSB
常见的数据隐藏方式?
在图片整体上对某个颜色的最低有效位进行批量更改,就可以获得基于图片大小的二进制存储空间,当然会损失图片质量,但是肉眼无法辨别,要眼神特别好而且显示器特别好才行。
千里码隐藏信息的方法不是把文字文本藏进二进制里,而是用最低有效位在原图上写了字,那就直接读取某个颜色的最低有效位,然后1代表有数据,0代表没数据,有数据的给赋值上颜色,没数据的给涂黑了,数据就能以图片的形式展示出来了。

解题过程

去千里码页面下载藏有信息的lenna照片,然后放到下面的小工具里就可以看到隐藏的信息了。

本文代码

window.onload = function () {
    document.getElementById("file").addEventListener("change", importImage);
}

var img = new Image();
img.onload = function () {
    var ctx = document.getElementById('canvas').getContext('2d');
    ctx.canvas.width = img.width;
    ctx.canvas.height = img.height;
    ctx.drawImage(img, 0, 0);
}

var importImage = function (e) {
    var reader = new FileReader();
    reader.onload = function (event) {
        img.src = event.target.result;
    };
    reader.readAsDataURL(e.target.files[0]);
};

var step1 = function (color) {
    img.onload();
    var ctx = document.getElementById("canvas").getContext('2d');
    var imgData = ctx.getImageData(0, 0, ctx.canvas.width, ctx.canvas.height);
    var delpos1, delpos2;
    if (color === 'red') {
        delpos1 = 1;
        delpos2 = 2;
    }
    if (color === 'green') {
        delpos1 = 0;
        delpos2 = 2;
    }
    if (color === 'blue') {
        delpos1 = 0;
        delpos2 = 1;
    }
    for (var i = 0; i < imgData.data.length; i += 4) {
        imgData.data[i + delpos1] = 0;
        imgData.data[i + delpos2] = 0;
    }
    ctx.putImageData(imgData, 0, 0);
};

var step2 = function (color) {
    img.onload();
    var ctx = document.getElementById("canvas").getContext('2d');
    var imgData = ctx.getImageData(0, 0, ctx.canvas.width, ctx.canvas.height);
    var datapos;
    if (color === 'red') {
        datapos = 0;
    }
    if (color === 'green') {
        datapos = 1;
    }
    if (color === 'blue') {
        datapos = 2;
    }
    for (var i = 0; i < imgData.data.length; i += 4) {
        if ((imgData.data[i + datapos]).toString(2).substr(-1) !== '1') {
            imgData.data[i + 0] = 0;
            imgData.data[i + 1] = 0;
            imgData.data[i + 2] = 0;
        } else {
            imgData.data[i + 0] = 0;
            imgData.data[i + 1] = 0;
            imgData.data[i + 2] = 0;
            imgData.data[i + datapos] = 255;
        }
    }
    ctx.putImageData(imgData, 0, 0);
}
最后修改:2024 年 07 月 01 日
如果觉得我的文章对你有用,请随意赞赏