源文件地址:https://blog.mythsman.com/2015/12/08/1/
最近在看隱寫術的時候經常需要研究圖片文件的二進制文檔格式,那么這就很有必要了解我們的圖片文件究竟是如何保存的了,今天找了個時間看了下png文件的文檔格式。總體還是挺麻煩的,不過畢竟不需要有什么要求,能了解即可。
概述
PNG是20世紀90年代中期開始開發的圖像文件存儲格式,其目的是替代GIF和TIFF文件格式,同時增加一些GIF文件格式所不具備的特性。流式網絡圖形格式(Portable Network Graphic Format,PNG)名稱來源於非官方的“PNG’s Not GIF”,是一種位圖文件(bitmap file)存儲格式,讀成“ping”。PNG用來存儲灰度圖像時,灰度圖像的深度可多到16位,存儲彩色圖像時,彩色圖像的深度可多到48位,並且還可存儲多到16位的α通道數據。PNG使用從LZ77派生的無損數據壓縮算法。(說白了這就是一種方便的、適於網絡傳播的輕便圖片文件格式)
特性
- 使用調色板技術可支持256種顏色的彩色圖像。(必須的)
- 流式讀/寫性(streamability):圖像文件格式允許連續讀出和寫入圖像數據。(因此適於網絡傳播)
- 逐次逼近顯示(progressive display):這種特性可使在通信鏈路上傳輸圖像文件的同時就在終端上顯示圖像,把整個輪廓顯示出來之后逐步顯示圖像的細節,也就是先用低分辨率顯示圖像,然后逐步提高它的分辨率。(類似馬賽克逐漸消除的過程)
- 透明性(transparency):這個性能可使圖像中某些部分不顯示出來,用來創建一些有特色的圖像。
- 輔助信息(ancillary information):這個特性可用來在圖像文件中存儲一些文本注釋信息。(就是可以說一些廢話)
- 獨立於計算機軟硬件環境。
- 使用無損壓縮。(無損!)
- 可在一個文件中存儲多幅圖像。
文件結構
PNG圖像格式文件由文件署名和數據塊(chunk)組成。
文件署名域
8字節的PNG文件署名域用來識別該文件是不是PNG文件。該域的值是:
十進制數 | 十六進制數 |
---|---|
137 | 89 |
80 | 50 |
78 | 4e |
71 | 47 |
13 | 0d |
10 | 0a |
26 | 1a |
10 | 0a |
這個文件署名就是在《利用文件頭標志判斷文件類型》中提到的文件頭標志了,很簡單。
數據塊
這里有兩種類型的數據塊,一種是稱為關鍵數據塊(critical chunk),就是必須要有的塊;另一種叫做輔助數據塊(ancillary chunks)。
每個數據塊都由下表所示的的4個域組成。
名稱 | 字節數 | 說明 |
---|---|---|
Length(長度) | 4字節 | 指定數據塊中數據域的長度,其長度不超過(231−1)(231−1)字節 |
Chunk Type Code(數據塊類型碼) | 4字節 | 數據塊類型碼由ASCII字母(A-Z和a-z)組成 |
Chunk Data(數據塊實際內容 | 可變長度 | 存儲按照Chunk Type Code指定的數據 |
CRC(循環冗余檢測 | 4字節 | 存儲用來檢測是否有錯誤的循環冗余碼 |
其中CRC(cyclic redundancy check)域中的值是對Chunk Type Code域和Chunk Data域中的數據進行計算得到的,可以看做一種校驗碼。
關鍵數據塊
關鍵數據塊中的4個標准數據塊是:
(1) 文件頭數據塊IHDR(header chunk):
它包含有PNG文件中存儲的圖像數據的基本信息,並要作為第一個數據塊出現在PNG數據流中,而且一個PNG數據流中只能有一個文件頭數據塊。
文件頭數據塊由13字節,組成結構如下:
域的名稱 | 字節數 | 說明 |
---|---|---|
Width | 4 bytes | 圖像寬度,以像素為單位 |
Height | 4 bytes | 圖像高度,以像素為單位 |
Bit depth | 1 byte | 圖像深度:索引彩色圖像:1,2,4或8 ;灰度圖像:1,2,4,8或16 ;真彩色圖像:8或16 |
ColorType | 1 byte | 顏色類型:0:灰度圖像, 1,2,4,8或16;2:真彩色圖像,8或16;3:索引彩色圖像,1,2,4或84:帶α通道數據的灰度圖像,8或16;6:帶α通道數據的真彩色圖像,8或16 |
Compression method | 1 byte | 壓縮方法(LZ77派生算法) |
Filter method | 1 byte | 濾波器方法 |
Interlace method | 1 byte | 隔行掃描方法:0:非隔行掃描;1: Adam7(由Adam M. Costello開發的7遍隔行掃描方法) |
(2) 調色板數據塊PLTE(palette chunk):
它包含有與索引彩色圖像((indexed-color image))相關的彩色變換數據,它僅與索引彩色圖像有關,而且要放在圖像數據塊(image data chunk)之前。真彩色的PNG數據流也可以有調色板數據塊,目的是便於非真彩色顯示程序用它來量化圖像數據,從而顯示該圖像。結構如下:
|顏色|字節|意義|
|Red|1 byte||0 = 黑色, 255 = 紅|
|Green|1 byte||0 = 黑色, 255 = 綠色|
|Blue|1 byte||0 = 黑色, 255 = 藍色|
PLTE數據塊是定義圖像的調色板信息,PLTE可以包含1~256個調色板信息,每一個調色板信息由3個字節組成,因此調色板數據塊所包含的最大字節數為768,調色板的長度應該是3的倍數,否則,這將是一個非法的調色板。
對於索引圖像,調色板信息是必須的,調色板的顏色索引從0開始編號,然后是1、2……,調色板的顏色數不能超過色深中規定的顏色數(如圖像色深為4的時候,調色板中的顏色數不可以超過2^4=16),否則,這將導致PNG圖像不合法。
(3) 圖像數據塊IDAT(image data chunk):
它存儲實際的數據,在數據流中可包含多個連續順序的圖像數據塊。
IDAT存放着圖像真正的數據信息,因此,如果能夠了解IDAT的結構,我們就可以很方便的生成PNG圖像。
(4) 圖像結束數據IEND(image trailer chunk):
它用來標記PNG文件或者數據流已經結束,並且必須要放在文件的尾部。
如果我們仔細觀察PNG文件,我們會發現,文件的結尾12個字符看起來總應該是這樣的:
00 00 00 00 49 45 4E 44 AE 42 60 82
不難明白,由於數據塊結構的定義,IEND數據塊的長度總是0(00 00 00 00,除非人為加入信息),數據標識總是IEND(49 45 4E 44),因此,CRC碼也總是AE 42 60 82。
最后,除了表示數據塊開始的IHDR必須放在最前面, 表示PNG文件結束的IEND數據塊放在最后面之外,其他數據塊的存放順序沒有限制。
輔助數據塊
(比較雜,不需要全部了解透)
PNG文件格式規范制定的10個輔助數據塊是:
- 背景顏色數據塊bKGD(background color)。
- 基色和白色度數據塊cHRM(primary chromaticities and white point)。所謂白色度是指當R=G=B=最大值時在顯示器上產生的白色度。
- 圖像γ數據塊gAMA(image gamma)。
- 圖像直方圖數據塊hIST(image histogram)。
- 物理像素尺寸數據塊pHYs(physical pixel dimensions)。
- 樣本有效位數據塊sBIT(significant bits)。
- 文本信息數據塊tEXt(textual data)。
- 圖像最后修改時間數據塊tIME (image last-modification time)。
- 圖像透明數據塊tRNS (transparency)。
- 壓縮文本數據塊zTXt (compressed textual data)。
數據塊摘要
關鍵數據塊、輔助數據塊和專用公共數據塊(special-purpose public chunks)綜合下表中:
數據塊符號 | 數據塊名稱 | 多數據塊 | 可選否 | 位置限制 |
---|---|---|---|---|
IHDR | 文件頭數據塊 | 否 | 否 | 第一塊 |
cHRM | 基色和白色點數據塊 | 否 | 是 | 在PLTE和IDAT之前 |
gAMA | 圖像γ數據塊 | 否 | 是 | 在PLTE和IDAT之前 |
sBIT | 樣本有效位數據塊 | 否 | 是 | 在PLTE和IDAT之前 |
PLTE | 調色板數據塊 | 否 | 是 | 在IDAT之前 |
bKGD | 背景顏色數據塊 | 否 | 是 | 在PLTE之后IDAT之前 |
hIST | 圖像直方圖數據塊 | 否 | 是 | 在PLTE之后IDAT之前 |
tRNS | 圖像透明數據塊 | 否 | 是 | 在PLTE之后IDAT之前 |
oFFs | (專用公共數據塊) | 否 | 是 | 在IDAT之前 |
pHYs | 物理像素尺寸數據塊 | 否 | 是 | 在IDAT之前 |
sCAL | (專用公共數據塊) | 否 | 是 | 在IDAT之前 |
IDAT | 圖像數據塊 | 是 | 否 | 與其他IDAT連續 |
tIME | 圖像最后修改時間數據塊 | 否 | 是 | 無限制 |
tEXt | 文本信息數據塊 | 是 | 是 | 無限制 |
zTXt | 壓縮文本數據塊 | 是 | 是 | 無限制 |
fRAc | (專用公共數據塊) | 是 | 是 | 無限制 |
gIFg | (專用公共數據塊) | 是 | 是 | 無限制 |
gIFt | (專用公共數據塊) | 是 | 是 | 無限制 |
gIFx | (專用公共數據塊) | 是 | 是 | 無限制 |
IEND | 圖像結束數據 | 否 | 否 | 最后一個數據塊 |
tEXt和zTXt數據塊中的標准關鍵字:
關鍵字 | 說明 |
---|---|
Title | 圖像名稱或者標題 |
Author | 圖像作者名 |
Description | 圖像說明 |
Copyright | 版權聲明 |
CreationTime | 原圖創作時間 |
Software | 創作圖像使用的軟件 |
Disclaimer | 棄權 |
Warning | 圖像內容警告 |
Source | 創作圖像使用的設備 |
Comment | 各種注釋 |
一個例子
為了便於研究,我在本地找了個24x24像素的圖片:
用十六進制打開后是這樣的:
1 |
0000000: 8950 4e47 0d0a 1a0a 0000 000d 4948 4452 .PNG........IHDR |
接下來我們試着分析一下:
首先是八個字節的文件頭標志,標識着png文件:
1 |
8950 4e47 0d0a 1a0a |
接下來的地方就是IHDR數據塊了:
0000 000d
說明IHDR頭塊長為13
4948 4452
IHDR標識(ascii碼為IHDR)
下面是IHDR數據塊的實際內容
0000 0018
圖像的寬,24像素
0000 0018
圖像的高,24像素
08
表示色深,這里是2^8=256,即這是一個256色的圖像
06
顏色類型,查表可知這是帶α通道數據的真彩色圖像
00
PNG Spec規定此處總為0(非0值為將來使用更好的壓縮方法預留),表示使壓縮方法(LZ77派生算法)
00
同上
00
非隔行掃描
e0 773d f8
CRC校驗
以上分析了第一個IHDR塊的內容,其他塊的分析方法類似,比如接下來的就是tEXt塊了,很簡單,不做分析了。(當然這里還有重要的IDAT塊,這是圖像的實際內容)
最后得有個IEND數據塊,這部分正如上所說,通常都應該是
00 00 00 00 49 45 4E 44 AE 42 60 82
由於我用的是vim打開,vim在文件最后都會惡心的自己加上0a換行,當然這並沒有什么壞的影響。不過這也提醒了我們一個問題,既然在IEND塊后面添加任何的字符都對文件的打開造成不了影響,那我們就可以在這里藏一些數據了(當然這種藏法很low)。。。
OK,這就是png文件的基本構造了。