音視訊入門-11-PNG檔案格式詳解
* 音視訊入門文章目錄 *
PNG 檔案格式解析
PNG 影象格式檔案由一個 8 位元組的 PNG 檔案署名域和 3 個以上的後續資料塊(IHDR、IDAT、IEND)組成。
PNG 檔案包括 8 位元組檔案署名(89 50 4E 47 0D 0A 1A 0A,十六進位制),用來識別 PNG 格式。
用十六進位制檢視器開啟任意一個 PNG 檔案,都是可以看到這樣的頭部:
PNG 定義了兩種型別的資料塊:一種是 PNG 檔案必須包含、讀寫軟體也都必須要支援的關鍵塊(critical chunk);另一種叫做輔助塊(ancillary chunks),PNG 允許軟體忽略它不認識的附加塊。這種基於資料塊的設計,允許 PNG 格式在擴充套件時仍能保持與舊版本相容。
資料塊總覽
下表就是 PNG 中資料塊的類別,關鍵資料塊部分突出顯示以區分:
資料塊符號 | 資料塊名稱 | 多資料塊 | 是否可選 | 位置限制 |
---|---|---|---|---|
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 |
影象結束資料 |
否 |
否 |
最後一個數據塊 |
我們目前只需關注關鍵資料塊即可。
資料塊中有 4 個關鍵資料塊:
- 檔案頭資料塊 IHDR(header chunk):包含有影象基本資訊,作為第一個資料塊出現並只出現一次。
- 調色盤資料塊 PLTE(palette chunk):必須放在影象資料塊之前。
- 影象資料塊 IDAT(image data chunk):儲存實際影象資料。PNG 資料允許包含多個連續的影象資料塊。
- 影象結束資料 IEND(image trailer chunk):放在檔案尾部,表示 PNG 資料流結束。
資料塊連起來,大概這個樣子:
PNG 識別符號 | PNG 資料塊(IHDR) | PNG 資料塊(其他型別資料塊) | … | PNG 結尾資料塊(IEND) |
---|
資料塊結構
PNG 檔案中,每個資料塊(比如IHDR,IDAT等)由4個部分組成:
名稱 | 位元組數 | 說明 |
---|---|---|
Length (長度) | 4 位元組 | 指定資料塊中資料域的長度,其長度不超過(2^31-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 域中的資料進行計算得到的。
- 注意:Length 值的是除:length 本身,Chunk Type Code,CRC 外的長度,也就是 Chunk Data 的長度。
資料塊-檔案頭資料塊 IHDR
它包含 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或8 4:帶α通道資料的灰度影象,8或16 6:帶α通道資料的真彩色影象,8或16 |
Compression method | 1 byte | PNG Spec 規定此處總為 0,表示使用壓縮方法(LZ77派生演算法) |
Filter method | 1 byte | PNG Spec 規定此處總為 0,濾波器方法 |
Interlace method | 1 byte | 隔行掃描方法:0:非隔行掃描 1: Adam7(由Adam M. Costello開發的7遍隔行掃描方法) |
用十六進位制檢視器開啟一個 PNG 檔案:
十六進位制 | 說明 |
---|---|
00 00 00 0D | 資料塊長度 13 位元組 |
49 48 44 52 | 資料塊型別碼 “IHDR” 的 ASCII 字母 |
00 00 04 1D | 影象寬度 1053 |
00 00 02 B3 | 影象高度 691 |
08 | 影象深度 8 |
06 | 帶α通道資料的真彩色圖 |
00 | 壓縮方法 |
00 | 濾波器方法 |
00 | 隔行掃描方法:00非隔行掃描 |
52 C3 75 3A | CRC (迴圈冗餘檢測) |
資料塊-調色盤資料塊 PLTE
包含有與索引彩色影象(indexed-color image)相關的彩色變換資料,它僅與索引彩色影象有關,而且要放在影象資料塊(image data chunk)之前。
PLTE 資料塊是定義影象的調色盤資訊,PLTE 可以包含 1~256 個調色盤資訊,每一個調色盤資訊由 3 個位元組組成:
顏色 | 位元組 | 意義 |
---|---|---|
Red | 1 byte | 0 = 黑色, 255 = 紅 |
Green | 1 byte | 0 = 黑色, 255 = 綠色 |
Blue | 1 byte | 0 = 黑色, 255 = 藍色 |
調色盤的長度應該是 3 的倍數,否則,這將是一個非法的調色盤。
對於索引影象,調色盤資訊是必須的,調色盤的顏色索引從 0 開始編號,然後是 1、2……,調色盤的顏色數不能超過色深中規定的顏色數(如影象色深為 4 的時候,調色盤中的顏色數不可以超過 2^4=16),否則,這將導致 PNG 影象不合法。
真彩色影象和帶 α 通道資料的真彩色影象也可以有調色盤資料塊,目的是便於非真彩色顯示程式用它來量化影象資料,從而顯示該影象。
用十六進位制檢視器開啟一個索引影象 PNG 檔案:
十六進位制 | 說明 |
---|---|
00 00 00 27 | 資料塊長度 39 位元組 |
50 4C 54 45 | 資料塊型別碼 “PLTE” 的 ASCII 字母 |
B7 00 34 FF 99 00 60 00 73 FF 0F 00 FF ED 00 09 00 B2 FF 66 00 FF 3B 00 E2 00 15 8B 00 54 FF C1 00 33 00 99 FF FF 00 |
調色盤顏色 13 個 |
48 29 75 2C | CRC (迴圈冗餘檢測) |
預覽調色盤中的顏色:
資料塊-影象資料塊 IDAT
它儲存實際的資料,在資料流中可包含多個連續順序的影象資料塊。
IDAT 存放著影象真正的資料資訊,因此,如果能夠了解 IDAT 的結構,我們就可以很方便的生成 PNG 影象。
用十六進位制檢視器開啟一個索引影象 PNG 檔案:
十六進位制 | 說明 |
---|---|
00 00 00 D3 | 資料塊長度 211 位元組 |
49 44 41 54 | 資料塊型別碼 “IDAT” 的 ASCII 字母 |
78 9C ...... | 壓縮的資料 211 位元組,LZ77 派生壓縮方法 |
52 98 5D 9D | CRC (迴圈冗餘檢測) |
影象資料塊 IDAT 細節在本文下半部分有詳細分析
資料塊-影象結束資料 IEND
它用來標記 PNG 檔案或者資料流已經結束,並且必須要放在檔案的尾部。
如果我們仔細觀察 PNG 檔案,我們會發現,檔案的結尾 12 個字元看起來總應該是這樣的:
00 00 00 00 49 45 4E 44 AE 42 60 82
用十六進位制檢視器開啟一個 PNG 檔案:
由於資料塊結構的定義,IEND 資料塊的長度總 是 0(00 00 00 00,除非人為加入資訊),資料標識總是 IEND(49 45 4E 44),因此,CRC 碼也總是 AE 42 60 82。
影象資料塊 IDAT 細節
IDAT 壓縮資料細節
在 PNG Spec 壓縮演算法部分:
PNG compression method 0 is deflate/inflate compression with a sliding window (which is an upper bound on the distances appearing in the deflate stream) of at most 32768 bytes. Deflate compression is an LZ77 derivative [ZL].
Deflate-compressed datastreams within PNG are stored in the "zlib" format, which has the structure:
- zlib compression method/flags code 1 byte
- Additional flags/check bits 1 byte
- Compressed data blocks n bytes
- Check value 4 bytes
Further details on this format are given in the zlib specification [RFC-1950].
- PNG 使用 DEFLATE 壓縮演算法。
- DEFLATE 是同時使用了 LZ77 演算法與哈夫曼編碼(Huffman Coding)的一個無損資料壓縮演算法。
- DEFLATE 壓縮的資料以 zlib 格式儲存。
zlib(RFC1950):一種格式,是對 deflate 進行了簡單的封裝,他也是一個實現庫(delphi中有zlib,zlibex)
gzip(RFC1952):一種格式,也是對 deflate 進行的封裝。
gzip = gzip 頭 + deflate 編碼的實際內容 + gzip 尾
zlib = zlib 頭 + deflate 編碼的實際內容 + zlib 尾
提取&解壓 IDAT 中壓縮資料
Windows 上可以用 [hexeditor](https://www.hhdsoftware.com/free-hex-editor)
Mac 上可以用 [hexfiend](http://ridiculousfish.com/hexfiend/)、[Hopper Disassembler](https://www.hopperapp.com/)
使用 zlib
解壓 78 9C ......
壓縮的資料位元組:
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include "zlib.h"
int main() {
FILE *inFile = fopen("/Users/staff/Desktop/indexed-color-image.data", "rb");
FILE *outFile = fopen("/Users/staff/Desktop/indexed-color-image-uncompress.data", "wb");
fseek(inFile, 0L, SEEK_END);
long size = ftell(inFile);
fseek(inFile, 0L, SEEK_SET);
uint8_t dataBuf[size];
fread(dataBuf, size, 1, inFile);
printf("壓縮檔案大小:%ld\n", size);
uint8_t destBuf[1500000]={0};
uint32_t destLen = 0;
uncompress(destBuf, &destLen, dataBuf, size);
printf("解壓後大小:%d\n", destLen);
fwrite(destBuf, destLen, 1, outFile);
fflush(outFile);
fclose(inFile);
fclose(outFile);
return 0;
}
分析解壓後的資料
在 PNG Spec 7.1 Integers and byte order
All integers that require more than one byte shall be in network byte order (as illustrated in figure 7.1): the most significant byte comes first, then the less significant bytes in descending order of significance (MSB LSB for two-byte integers, MSB B2 B1 LSB for four-byte integers). The highest bit (value 128) of a byte is numbered bit 7; the lowest bit (value 1) is numbered bit 0. Values are unsigned unless otherwise noted. Values explicitly noted as signed are represented in two's complement notation.
- PNG 使用
網路位元組序
大端位元組序(Big Endian)
。
在 PNG Spec 7.2 Scanlines
In PNG images of colour type 0 (greyscale) each pixel is a single sample, which may have precision less than a byte (1, 2, or 4 bits). These samples are packed into bytes with the leftmost sample in the high-order bits of a byte followed by the other samples for the scanline.
In PNG images of colour type 3 (indexed-colour) each pixel is a single palette index. These indices are packed into bytes in the same way as the samples for colour type 0.
- PNG 影象深度小於 1 位元組,將會被
packed into bytes
。
在 PNG Spec 7.3 Filtering
PNG allows the scanline data to be filtered before it is compressed. Filtering can improve the compressibility of the data. The filter step itself results in a sequence of bytes of the same size as the incoming sequence, but in a different representation, preceded by a filter type byte. Filtering does not reduce the size of the actual scanline data. All PNG filters are strictly lossless.
Different filter types can be used for different scanlines, and the filter algorithm is specified for each scanline by a filter type byte. The filter type byte is not considered part of the image data, but it is included in the datastream sent to the compression step. An intelligent encoder can switch filters from one scanline to the next. The method for choosing which filter to employ is left to the encoder.
- 每一掃描行前有一位元組用於指定
過濾器型別
。
在 PNG Spec Filters:
Filtering transforms the PNG image with the goal of improving compression. PNG allows for a number of filter methods. All the reduced images in an interlaced image shall use a single filter method. Only filter method 0 is defined by this International Standard. Other filter methods are reserved for future standardization (see 4.9 Extension and registration). Filter method 0 provides a set of five filter types, and individual scanlines in each reduced image may use different filter types.
。。。。。。
- 檔案頭資料塊 IHDR 中
Filter method
過濾方法只能是 0。 Filter method
=0 定義了 5 種Filter Type
過濾器型別:0:None
、1:Sub
、2:Up
、3:Average
、4:Paeth
。
當 PNG 圖片是索引影象時(下圖資料:影象深度: 4
尺寸 256X256
過濾器型別: 0:None
隔行掃描方法:0:非隔行掃描
):
indexed-color-image.png
- 每個高亮區域前面一個位元組
00
代表過濾器型別
:0:None
【PNG Spec 7.3 Filtering】【 PNG Spec Filters】。 - 如果高亮區域前面一個位元組不是
00
,高亮區將不是掃描行索引資料,需要參考 【PNG Spec 9.2 Filter types for filter method 0】 - 每種顏色高亮顯示的部分
128 位元組
是一個掃描行顏色索引資料,因為影象深度:4
,所以每個位元組代表兩個顏色索引 【PNG Spec 7.2 Scanlines】。 - 如位元組
55
是十六進位制,二進位制為01010101
,前四 bit 位代表一個顏色索引0101
十進位制為 5,後四 bit 位代表一個顏色索引0101
十進位制為 5 。
當 PNG 圖片是真彩圖像時(下圖資料:影象深度: 8
尺寸 70X70
過濾器型別: 0:None
隔行掃描方法:0:非隔行掃描
):
true-color-image.png
- 每個高亮區域前面一個位元組
00
代表過濾器型別
:0:None
【PNG Spec 7.3 Filtering】【 PNG Spec Filters】。 - 如果高亮區域前面一個位元組不是
00
,高亮區將不是掃描行顏色資料,需要參考 【PNG Spec 9.2 Filter types for filter method 0】 - 每種顏色高亮顯示的部分
210 位元組
是一個掃描行顏色資料,因為真彩圖片
影象深度:8
,所以每三個位元組代表一個畫素顏色。 - 如位元組
FF 00 00
,代表一個畫素 RGB 顏色。
More
下一步,將用程式碼手動生成一張 PNG 圖片,文章目錄:* 音視訊入門文章目錄 *。
所有可能存在問題的答案:PNG Specification。
程式碼:
demos/demos-zlib
參考資料:
PNG 檔案格式詳解
PNG、JPEG、BMP等幾種圖片格式詳解(一)—— PNG
詳解PNG檔案結構
《PNG檔案格式》(二)PNG檔案格式分析
圖片知識梳理(一): PNG檔案結構
隱寫技巧——利用PNG檔案格式隱藏Payload
Portable Network Graphics (PNG) Specification and Extensions
gzip,deflate,zlib辨析
Zlib庫的安裝與使用
內容有誤?聯絡作者:
本文由部落格一文多發平臺 OpenWrite 釋出!