1. 程式人生 > >音視訊入門-11-PNG檔案格式詳解

音視訊入門-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:None1:Sub2:Up3:Average4: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 釋出!