对图片学习的记录

        最近在项目里面看到一个上传图片的功能,该功能对用户上传的照片会做一些验证,比如,文件后缀名,大小,尺寸,其中还会验证该图片是否为钓鱼图片,而他验证的方式是通过使用JMagic对照片进行缩放,如果出现异常,说明这一定不是图片,否则就允许上传。我好奇的是怎样让图片变成钓鱼图片,都有哪些方法?图片的缩放对钓鱼图片的影响是什么?


1.学习数字图片在计算机中是怎样表示的(图片编码是怎样的)?

        在网上搜的时候发现对bmp格式的图片编码讲解的比较多,于是就从bmp图片开始入手。

        数字图片在计算机中用2进制表示,然后操作系统读取解析这些2进制编码,来控制显示器中显像管显示红,绿,蓝(三原色RGB)。就这样,一张照片就呈现出来了,详细原理请见下文。

对于这样一个bmp格式的图片(不要直接右键另存为下载图片,因为这已经不是bmp格式的图片了):

  图1

我们用手机拍照片然后放大:


                                     图2

可以比较清楚的看到液晶显示器每个点显示的颜色

一张bmp图片的二进制编码结构是这样子的:


                            图3

各部分包含的信息说明:

文件头


                                                                               图4

信息头


                                                                                    图5

上面的表格可能还不够直观,现在将图片用编辑器(比如EditPlus)的16进制查看器打开,可看到真实的bmp编码如下所示(大家可以到这里下载bmp图片对照着看):


                                                                                  图6

       编码分为4个部分(用中括号括起来了),和图3一一对应,从上述2个表格中挑几个我认为重要的值对照着图6说明一下(注意:bmp图片编码用的是小端模式,比如“42 4D”应该是0x4D42):

文件头 前2个字节表示文件类型,0x42 换算成十进制为66,对应ascii码中的B,所以该文件类型为“BM”,接下来4个字节表示该图片的大小,0x00000276 十进制为630,单位字节,你可以查看图片(图片下载链接在上文中有提供)大小进行验证,看看是不是630字节。最后的0x00000076表示从头开始,到正真的图像数据的偏移量,也就是说上图中最后一部分“位图数据”是从0x00000076开始的。

信息头 0x00000028表示信息头本身的大小,也就是40个字节,数数看对吧?接下来2个四字节分别表示图片宽高为32,单位为像素,你可以到图2数数看是不是长宽都是32个点。接下来表示的是调色板的数量,该值总是为1,不管了。再看0x0004,单位比特数/像素,也就是说该图用4比特来表示一个像素,这个到后面在说。

然后在说说调色板,调色板长度不一定的,颜色板里面的颜色越丰富,那么说明展示好看的图片的能力越强。我们把调色板中的颜色列出来(每4个字节一组):

0   00 00 00 00

1   00 00 80 00

2   00 80 00 00

3   00 80 80 00

4   80 00 00 00

5   80 00 80 00

6   80 80 00 00

7   80 80 80 00

  c0 c0 c0 00

9   00 00  ff  00

A   00  ff  00 00

B   00  ff   ff  00

C   ff   00 00 00

D   ff   00  ff  00

E    ff   ff  00 00

F    ff   ff  ff   00

这里一共列出来了16种颜色,那为什么一种颜色需要4个字节来表示呢?我们都知道三原色RGB(红,绿,蓝),这4个字节对应表示的颜色分别是蓝,绿,红, Alpha(保留字,一般设置为0, 可以用来表示透明度)。字节的大小来表示相应颜色的强弱的,比如第一个字节表示蓝色,那么颜色强度的范围为0~255,比如0x00就是黑色,0xFF就表示相应颜色达到最强,这让我想起css里面也是用十六进制来表示颜色的:


                               图7

位图数据  其实调色板相当与“索引”,然后位图数据是要说明每一个像素应该显示上述16种颜色中的哪种颜色就行了!那是怎样说明的呢?还记得信息头里面申明的4比特/像素吗?呵呵现在就用到了,你想啊!调色板里面一共有16种颜色,我在位图数据中需要4比特(半个字节)就能表示16个数,刚好能任意选择颜色板中的颜色。下面把位图数据列出来(只列了3行)说明,这样更直观:

00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F

00 00 00 00 00 00 00 00 00 00  00 00 00 00  00 00

00 00 00 00 00 00 00 00 09 00  00 00 00 00  00 00

11 11 01 19 11 01 10 10 09 09  01 09 11 11  01 90

首先要说明的是,位图数据的编码顺序是从左到右, 从下到上的。如上所示,第一排一共表示了32个像素(每半个字节表示一个像素),而且每个像素都是黑色的(全都是0x0),再去看看图2,发现图片最底下全都是黑的。然后在接下来看,发现从左往右数第18个像素是0x9,查看调色板,该像素对应的颜色是红色,你可以再到图2验证一下。所以一张bmp图片在计算机里面大致就是这样表示的。


2.学习位图图片缩放的实现原理

        在网上找到了2种算法实现, 该博客对缩放的原理讲的比较清楚了,建议看看。看到博客该博客中这2张美女的放大效果让我想到window自带的图像查看器和美图看看的图片放大效果,应该就是这2种缩放算法引起的区别。


下面说一个我在放大图片的时候遇到的一个问题

        对图片操作的软件有几种,有jdk自带的图片处理库,有imagemagick(本身是c/c++写的,然后有很多语言的版本),我项目中用的就是JMagick,于是我就用他对图1进行放大,把图片的长宽都加了100像素,放大之后看图片编码:

                                                                                  图8
发现调色板不见了(从文件头的图像数据偏移量以及信息头的大小可以看出来),这是为毛?赶紧谷歌,经过学习我想原因应该是这样的(之所以不肯定,是因为我没有看过ImageMagick源代码):

           你知道吗,调色板是可以没有的,当没有调色板的时候,就直接用4个字节来表示一个像素该显示什么颜色,这样子的话,一张32*32的bmp图片大小应该是32*32*4(Byte)=4096字节(头部大小忽略),可是如果引入了调色板,把用到的16种颜色做成一个索引,这样我们在图像数据里面只要用4位就能表示一个像素的颜色了,这样图片的大小变为:16*4(Byte)+32*32*4(Bit),是不是节省很多空间呢?!可是你懂的,我们平常看的美女图片,颜色表现那么细腻,怎么可能只有16种颜色呢?是的,现在图片颜色总数达到了256*256*256*256种,这就是传说中的32位真彩色(当然还有24位的,就是只用三原色,32位的增加使用了Alpha通道)。“256*256*256*256”是怎么算的?没个字节都能表示256种强度啊,乘起来就是这个啊!那么在这个时候我们就不需要调色板了,为什么?原因很明显,假如用调色板,那么调色板就有2e32(2的32次方)种颜色,然后每种颜色需要4个字节表示,到了位图数据这里,我们还是需要用4个字节表示索引值!所以我们发现,在这种情况下使用调色板,我们一点便宜都占不到,反而还要搭进去2e32 *4个字节的调色板空间,所以我觉得ImageMagick在缩放的时候就去掉了调色板!


3.做的一些实践

       ImageMagick是用c语言写的,本来学到这里可以直接尝试去看源代码学习在缩放的时候对图片做了什么。奈何C语言水平太基础了。于是尝试做了一些实践:1,把代码插到图片里面去,并尽可能的插在多种地方。2,对图片进行缩放,看看缩放后的图片有什么变化。

我现在知道的往图片里面插入代码的方式有2种:

第一种最简单,直接在图片文件结尾用2进制的形式把代码copy进去

图9就是在图1中插入一段script代码,插入后文件大小变为750字节


                                                                                   图9

对上图进行原大小缩放,发现文件大小又变为630字节,并且缩放后的图片编码和缩放前的一样。


第二种是可以通过一些工具将代码插入到gif图片的注释块当中去


                                                                                  图10

对图10进行缩放也是一样的效果。


学习资料:

BMP文件格式详解http://blog.csdn.net/o_sun_o/article/details/8351037

例解BITMAP的数据格式:http://blog.csdn.net/pathuang68/article/details/4219681

图片病毒技术原理剖析:http://bbs.lyarc.net/read-377.html

如何将js代码隐藏到图片中:http://blog.csdn.net/shixing_11/article/details/7072804

图像缩放的双线性内插值算法的原理解析:http://blog.csdn.net/qiqi5521/article/details/2207562

java判断文件类型:http://blog.csdn.net/shixing_11/article/details/5708145

如何在GIF中插入代码:http://www.thinkfu.com/blog/gifjavascript-polyglots

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值