音視頻入門-11-PNG文件格式詳解

音視頻入門文章目錄

PNG 文件格式解析

PNG 圖像格式文件由一個 8 字節的 PNG 文件署名域和 3 個以上的後續數據塊(IHDR、IDAT、IEND)組成。

PNG 文件包括 8 字節文件署名(89 50 4E 47 0D 0A 1A 0A,十六進制),用來識別 PNG 格式。

用十六進制查看器打開任意一個 PNG 文件,都是可以看到這樣的頭部:

png-hex-file-signture.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 文件:

png-hex-ihdr.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 文件:

png-indexed-color-hex-plte.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 (循環冗餘檢測)

預覽調色板中的顏色:

indexed-color-plte-colors.png

數據塊-圖像數據塊 IDAT

它存儲實際的數據,在數據流中可包含多個連續順序的圖像數據塊。

IDAT 存放着圖像真正的數據信息,因此,如果能夠了解 IDAT 的結構,我們就可以很方便的生成 PNG 圖像。

用十六進制查看器打開一個索引圖像 PNG 文件:

png-hex-idat.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 文件:

png-hex-iend.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/)

png-hex-idat-data-extract.png

使用 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-hex-idat-uncompress.png
png-hex-idat-uncompress-contrast.png

分析解壓後的數據

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:None1:Sub2:Up3:Average4:Paeth

當 PNG 圖片是索引圖像時(下圖數據:圖像深度: 4 尺寸 256X256 過濾器類型: 0:None 隔行掃描方法:0:非隔行掃描):

indexed-color-image.png

png-indexed-color-uncompress-data.png

  • 每個高亮區域前面一個字節 00 代表 過濾器類型 : 0:NonePNG 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

png-true-color-uncompress-data.png

  • 每個高亮區域前面一個字節 00 代表 過濾器類型 : 0:NonePNG 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 發佈!
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章