不能说的秘密——前端也能玩的图片隐写术

分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友 微信微信
查看查看127 回复回复1 收藏收藏 分享淘帖 转播转播 分享分享 微信
查看: 127|回复: 1
收起左侧

不能说的秘密——前端也能玩的图片隐写术

[复制链接]
瑶池 发表于 2016-6-15 00:58:18 | 显示全部楼层 |阅读模式
快来登录
获取最新的苹果动态资讯
收藏热门的iOS等技术干货
拷贝下载Swift Demo源代码

上个月在刷题的时候,碰到了比较有意思的一道题——隐写术。既然感觉有意思,又很久没有玩过canvas,所以今天结合这两块内容带大家探索一下。

隐写术算是一种加密技术,权威的wiki说法是

隐写术是一门关于信息隐藏的技巧与科学,所谓信息隐藏指的是不让除预期的接收者之外的任何人知晓信息的传递事件或者信息的内容。


这看似高大上的定义,并不是近代新诞生的技术,早在13世纪末德国人Trithemius就写出了《隐写术》的著作,学过密码学的同学可能知道。

好了,说了这么多,隐写术到底是什么技术,让我们看一个例子。

下面是一张看似普通的图片,但其中却藏有另一个肉眼无法识别的图像哦。

不能说的秘密——前端也能玩的图片隐写术 1

不能说的秘密——前端也能玩的图片隐写术 - 敏捷大拇指 - 不能说的秘密——前端也能玩的图片隐写术 1


这是如果把上图每个色彩空间和数字3进行逻辑与运算,再把亮度增强85倍,可以得到下图。

不能说的秘密——前端也能玩的图片隐写术 2

不能说的秘密——前端也能玩的图片隐写术 - 敏捷大拇指 - 不能说的秘密——前端也能玩的图片隐写术 2


简单的说,上述的处理过程可以理解为对图片像素的处理,也就是说,加密的信息散布在每个像素点上。可是,13世纪还没有“像素”这个概念吧?!没错,上面这个例子只是隐写术的一个现代技术实现,隐藏信息的手段有很多,我们日常的钞票防伪也算是隐写术的一种,所以标题上也限定了我们的讨论范围——图片隐写术。

不能说的秘密——前端也能玩的图片隐写术 3

不能说的秘密——前端也能玩的图片隐写术 - 敏捷大拇指 - 不能说的秘密——前端也能玩的图片隐写术 3

(电子水印与隐写术有一些共通点)

聚焦到载体为图片的隐写术,一起来从前端角度分析其技术原理。

我们知道图片的像素信息里存储着RGB的色值,R、G、B分别为该像素的红、绿、蓝通道,每个通道的分量值范围在0~255,16进制则是00~FF。在CSS中经常使用其16进制形式,比如指定博客头部背景色为#A9D5F4。其中R(红色)的16进制值为A9,换算成十进制为169。这时候,对R分量的值+1,即为170,整个像素RGB值为#AAD5F4,别说你看不出差别,就连火眼金金的“像素眼”设计师都察觉不出来呢。于此同时,修改G、B的分量值,也是我们无法察觉的。因此可以得出重要结论:RGB分量值的小量变动,是肉眼无法分辨的,不影响对图片的识别。

有了这个结论,那就给我们了利用空间,常用手段的就是对二进制最低位进行操作,下面就用canvas来演示一下。




1、解开图中的秘密

这是一张我们当家美女小兰师姐的照片,为了让例子足够简单,里面的R通道分量被我加入了文本信息,想知道其中的信息,可以跟我用canvas代码来解开。

首先在页面加入一个canvas标签,并获取到其上下文。

[HTML] 纯文本查看 复制代码
<canvas id="canvas" width="256" height="256"></canvas>


[JavaScript] 纯文本查看 复制代码
var ctx = document.getElementById('canvas').getContext('2d');


接着将图片先绘制在画布上,然后获取其像素数据。

[JavaScript] 纯文本查看 复制代码
var img = new Image();
var originalData;
img.onload = function() {
    ctx.drawImage(img, 0, 0);
    // 获取指定区域的canvas像素信息
    originalData = ctx.getImageData(0, 0, ctx.canvas.width, ctx.canvas.height);
    console.log(originalData);
};
img.src = 'xiaolan.png';


打印出数据,会看到有一个非常大的数组。

不能说的秘密——前端也能玩的图片隐写术 5

不能说的秘密——前端也能玩的图片隐写术 - 敏捷大拇指 - 不能说的秘密——前端也能玩的图片隐写术 5


这个一维数组存储了所有的像素信息,一共有 256 * 256 * 4 = 262144个值。其中4个值一组,为什么呢?在浏览器中解析图片,除了RGB值外,每组第4个值为透明度值,即像素信息实际为大家熟知的rgba值。

这里的解密规则是对R通道进行处理,R的分量最低位为1则该像素设为红色,R的分量最低位为0则该像素设为黑色,直接看代码实现,完成后我们再绘制到canvas,即可看到结果。

[JavaScript] 纯文本查看 复制代码
var processData = function(originalData){
    var data = originalData.data;
    for(var i = 0; i < data.length; i++){
        if(i % 4 == 0){
            // 红色分量
            if(data[i] % 2 == 0){
                data[i] = 0;
            } else {
                data[i] = 255;
            }
        } else if(i % 4 == 3){
            // alpha通道不做处理
            continue;
        } else {
            // 关闭其他分量,不关闭也不影响答案,甚至更美观 o(^▽^)o
            data[i] = 0;
        }
    }
    // 将结果绘制到画布
    ctx.putImageData(originalData, 0, 0);
}


在img onload事件中调用processData方法,就可以看到结果啦。

得到的结果可能是这个样子的:

不能说的秘密——前端也能玩的图片隐写术 6

不能说的秘密——前端也能玩的图片隐写术 - 敏捷大拇指 - 不能说的秘密——前端也能玩的图片隐写术 6





2、在图片中隐藏信息

讲了基础的解密过程,再来反向说说加密过程。

既然要在图片中加入文字信息,那么首先要获取文字的像素信息,这里我先用canvas在画布上打印文字,获取像素信息。

[JavaScript] 纯文本查看 复制代码
var textData;
// 这些canvas API,好久没用,需要查API文档了T_T
ctx.font = '30px Microsoft Yahei';
ctx.fillText('广告位招租u', 60, 130);
textData = ctx.getImageData(0, 0, ctx.canvas.width, ctx.canvas.height).data;


先保存文字的像素信息,接着加载图片获取其像素信息,然后对两组像素进行处理,我在这里抽离了一个公共方法。

[JavaScript] 纯文本查看 复制代码
var mergeData = function(newData, color){
    var oData = originalData.data;
    var bit, offset;  // offset的作用是找到alpha通道值,这里需要大家自己动动脑筋
 
    switch(color){
        case 'R':
            bit = 0;
            offset = 3;
            break;
        case 'G':
            bit = 1;
            offset = 2;
            break;
        case 'B':
            bit = 2;
            offset = 1;
            break;
    }
 
    for(var i = 0; i < oData.length; i++){
        if(i % 4 == bit){
            // 只处理目标通道
            if(newData[i + offset] === 0 && (oData[i] % 2 === 1)){
                // 没有信息的像素,该通道最低位置0,但不要越界
                if(oData[i] === 255){
                    oData[i]--;
                } else {
                    oData[i]++;
                }
            } else if (newData[i + offset] !== 0 && (oData[i] % 2 === 0)){
                // // 有信息的像素,该通道最低位置1,可以想想上面的斑点效果是怎么实现的
                if(oData[i] === 255){
                    oData[i]--;
                } else {
                    oData[i]++;
                }
            }
        }
    }
    ctx.putImageData(originalData, 0, 0);
}


上述代码做的是,接受要隐藏的数据以及隐藏的颜色通道,然后对原图进行操作,修改图片该通道分量的最低位,如果有文字信息,则最低位置为1,否则为0。从最文章开头的结论知道,RGB的三个通道可以分别隐藏不同信息。

在img.onload中调用mergeData(textData, 'R'),处理好图像后,只要在浏览器中的canvas上右键保存图片即可。

这里的例子比较简单,只展示了基本的最低位隐藏文本信息,像二维码这些简单图形也可以这么处理。现实中隐藏画中画则需要更专业的图像处理算法,这里就不再展开了。




3、应用价值

图片隐写术的应用价值很广泛,比如程序员之间的表白(不限男女),不失为一种浪漫的方式~

上面的案例中我没有放出师姐的原片,这意味着如果盗用上面的图片,我是有办法识别出来的,起到了简单的一种签名作用。当然你也有办法消除掉里面的信息,而前提是你需要知道我的加密方式,可是实际应用中绝不会这么简单哦。有个成功案例就是大众点评通过这种方式,成功证明食神app对其图片的盗用,为自己的合法权益进行了有效维护。


好的,感谢阅读到最后,作为回报,我将福利隐藏在了师姐的图片中,敏捷大拇指上的各位IT工程师,请自行发现吧~




转自:AlloyTeam

更多图片 小图 大图
组图打开中,请稍候......

都看到这里了,就把这篇资料推荐给您的好朋友吧,让他们也感受一下。

回帖是一种美德,也是对楼主发帖的尊重和支持。

*声明:敏捷大拇指是全球最大的Swift开发者社区、苹果粉丝家园、智能移动门户,所载内容仅限于传递更多最新信息,并不意味赞同其观点或证实其描述;内容仅供参考,并非绝对正确的建议。本站不对上述信息的真实性、合法性、完整性做出保证;转载请注明来源并加上本站链接,敏捷大拇指将保留所有法律权益。如有疑问或建议,邮件至marketing@swifthumb.com

*联系:微信公众平台:“swifthumb” / 腾讯微博:@swifthumb / 新浪微博:@swifthumb / 官方QQ一群:343549891(满) / 官方QQ二群:245285613 ,需要报上用户名才会被同意进群,请先注册敏捷大拇指

嗯,不错!期待更多好内容,支持一把:
支持敏捷大拇指,用支付宝支付10.24元 支持敏捷大拇指,用微信支付10.24元

评分

参与人数 1金钱 +10 贡献 +10 专家分 +10 收起 理由
Anewczs + 10 + 10 + 10 32个赞!专家给力!

查看全部评分

1起来 发表于 2016-6-16 07:20:13 | 显示全部楼层
用canvas啊,是不是可以用Swift在后台对图片进行处理来隐写呢?
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

做任务,领红包。
我要发帖

分享扩散

都看到这里了,就把这资料推荐给您的好朋友吧,让他们也感受一下。
您的每一位朋友访问此永久链接后,您都将获得相应的金钱积分奖励
热门推荐

合作伙伴

Swift小苹果

  • 北京治世天下科技有限公司
  • ©2014-2016 敏捷大拇指
  • 京ICP备14029482号
  • Powered by Discuz! X3.1 Licensed
  • swifthumb Wechat Code
  •   
快速回复 返回顶部 返回列表