對圖片學習的記錄

        最近在項目裏面看到一個上傳圖片的功能,該功能對用戶上傳的照片會做一些驗證,比如,文件後綴名,大小,尺寸,其中還會驗證該圖片是否爲釣魚圖片,而他驗證的方式是通過使用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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章