ByteScope

PNG 檔案格式

Portable Network Graphics,一種無損的點陣圖格式。

MIME 類型
image/png
副檔名
.png
分類
圖片

Magic number(檔案簽章)

0x0000000089504E470D0A1A0A·PNG····PNG magic + CRLF guard

關於 PNG 格式

PNG 儲存影像時完全不損失畫質,並支援完整的 alpha 透明度,因此成為螢幕截圖、logo、圖示,以及任何邊緣銳利的圖形的預設選擇。每個 PNG 都以 8 位元組的簽章開頭,其中刻意包含一組換行字元 — 這樣一旦檔案經過文字模式傳輸而損壞,就會明顯壞掉而不是悄悄出錯。

檔頭結構,一個位元組一個位元組看

位移長度欄位意義
08PNG signature固定是 89 50 4E 47 0D 0A 1A 0A。第一個位元組的最高位元被設起來,7 位元的傳輸一剝掉就看得出來;第 1 到 3 個位元組拼出 PNG;後面那組 CR LF、DOS 的檔案結束符 1A 和結尾的 LF 存在的唯一理由,就是讓被文字模式傳輸搞爛的檔案大聲壞掉,而不是默默出錯。
84IHDR chunk lengthIHDR 資料的位元組數,大端序,固定是 00 00 00 0D — 13 個位元組。PNG 的每個 chunk 都是長度、類型、資料、CRC 這個順序,而 IHDR 一定是第一個。
124IHDR chunk type四個 ASCII 字母 IHDR。chunk 類型的大小寫本身有意義:首字母大寫代表這個 chunk 是關鍵的,解碼器看不懂就必須拒絕整個檔案,不能跳過去。
164Width影像寬度(像素),大端序 32 位元無號整數。0 不合法,規格上限是 2^31 - 1。工具報出誇張的尺寸,幾乎都是把這四個位元組當成小端序在讀。
204Height影像高度(像素),編碼方式和寬度一模一樣。這裡加上位移 16,是 PNG 唯一交代自己尺寸的地方 — 檔案裡沒有第二份可以拿來對照。
241Bit depth每個取樣的位元數:1、2、4、8 或 16。不是每種深度都配得上每種色彩類型 — 索引色最多到 8,兩種帶 alpha 的類型則從 8 起跳。
251Colour type0 灰階、2 全彩、3 索引色(必須有 PLTE chunk)、4 灰階加 alpha、6 全彩加 alpha。PNG「透明度不見了」的時候就是讀這個位元組:本來寫 6 的地方變成 2。
261Compression method固定是 0,代表 deflate,滑動視窗最大 32768 位元組。從來沒有第二種方法被登記過,所以只要不是 0 就是標頭壞了。
271Filter method固定是 0,也就是那組五種、逐掃描線自適應的濾波器。每一列實際用哪一種,是壓縮串流裡面的一個位元組,不在標頭這裡。
281Interlace method0 是不交錯,1 是 Adam7。Adam7 讓檢視器可以先畫出一張粗略的圖,代價是檔案大個幾個百分比;現在幾乎沒有東西會產生它。
294IHDR CRC-32對 chunk 類型和 chunk 資料算出來的 CRC-32,不包含長度欄位。位移 12 到 28 之間動任何一個位元組,這裡就對不上 — 手改標頭會被 hex 編輯器抓到就是靠這個。
33variableFirst chunk after IHDR下一組長度加類型。通常是 IDAT,不然就是 PLTE、tRNS、gAMA、sRGB、iCCP、pHYs、eXIf 或 acTL 之一 — 那些必須排在像素資料前面的色彩與中介資料 chunk。
-1212IEND trailer完好的 PNG 一律以同樣的十二個位元組結尾:00 00 00 00 49 45 4E 44 AE 42 60 82,一個長度為零的 IEND chunk 加上它那個固定的 CRC。結尾不是這串,檔案就是被截斷了。

怎麼跟長得像的格式分開

容易搞混的怎麼分
APNG動畫 PNG 的前 33 個位元組跟一般 PNG 完全一樣 — 同樣的簽章、同樣的 IHDR。差別在多了一個 acTL 動畫控制 chunk,規格要求它必須排在第一個 IDAT 之前,所以在前幾百個位元組裡找 61 63 54 4C 就對了。不認得 acTL 的解碼器只會畫出靜止的第一格,而這正是設計上預期的降級行為。
ICO現在的 .ico 可以直接把整張 PNG 塞進去,所以 hex dump 裡確實會出現 PNG 簽章 — 只是不在位移 0。ICO 開頭是 00 00 01 00,接著一份目錄,每一筆記著各張影像的位移;PNG 簽章就坐在其中某個位移上。斷定它是 PNG 之前,先看位移 0。
JPEG沒什麼玄機:FF D8 FF 對上 89 50 4E 47。但還是值得查,因為大多數編輯器的「另存為 PNG」是把 JPEG 已經有損的像素再編一次,不是真的轉換;而且截圖被改名成 .jpg 之後,裡面還是 PNG 的位元組,照樣到處都開得起來。
WebP兩者都能處理帶 alpha 的無損資料,也都常出現在截圖輸出。WebP 是 RIFF 檔案:位移 0 是 52 49 46 46,接四個位元組的小端序長度,位移 8 是 57 45 42 50。它裡面任何地方都不會有 PNG 簽章。

常見的壞法

  • 文字模式傳輸。老的 FTP 用戶端和某些 CI 的產出物步驟會轉換換行字元,位移 4-5 的 0D 0A 就塌成單一個 0A,整個檔案往前位移一個位元組,那之後每個 chunk 的 CRC 全部對不上。那組簽章當初就是為了抓這件事設計的。
  • 下載被截斷。簽章和 IHDR 都完好,所以尺寸還讀得出來,檢視器會把影像上半部畫出來,然後在 IDAT 串流用完的地方掉進一片灰色或透明的列。判斷方式是看最後十二個位元組,IEND 不見了。
  • chunk 裡面有一個位元組被翻掉。libpng 會因為 CRC 對不上而拒收,瀏覽器通常照樣畫出來,於是同一張 PNG 在 Chrome 裡「正常」,在 build script 裡就掛掉。把每個 chunk 的 CRC 重算一次,就知道是哪一個被動過。
  • 前面被塞了垃圾。一個多出來的 UTF-8 BOM、一頁 HTML 錯誤訊息,或是在影像本體之前噴出來的 PHP warning,都會把簽章擠離位移 0。影像的每個位元組其實都還在;解法就是把 89 50 4E 47 之前的東西全部刪掉。
  • 色彩類型被悄悄改寫。某個流程用色彩類型 2 而不是 6 重新編碼,alpha 通道就沒了。結果是一張完全合法、但沒有透明度的 PNG,而整個檔案裡只有第 25 個位元組會承認這件事。

這個格式現在還在用嗎

只要圖裡有硬邊或透明度,PNG 到現在都還是預設答案:螢幕截圖、UI 素材、logo、示意圖、圖示,還有任何要放進 README 的東西。照片這一塊它幾十年前就輸給 JPEG,近年又被 WebP 和 AVIF 拉開 — 那兩個在漸層多的影像上把 PNG 打得很難看,而且一樣有 alpha。PNG 真正無可取代的場合是「之後還會再編輯」的檔案,因為它是無損的:一張截圖存成 PNG,來回裁切、加註解十幾次都不會變樣,同一張存成 JPEG 則每存一次就肉眼可見地爛一點。它從 1997 年就被所有瀏覽器支援,所以不像那些新格式,永遠不需要準備 fallback。

在這個站上打開 PNG 檔

這些全部在你的瀏覽器裡跑,檔案不會離開你的電腦。

相關格式

容易和 PNG 搞混的格式,可以比對它們的開頭位元組。

格式開頭位元組副檔名
JPEGFF D8 FF.jpg
GIF47 49 46 38 39 61.gif
WebP52 49 46 46.webp
BMP42 4D.bmp

常見問題

檔案的 magic number 是什麼?

檔案開頭的前幾個位元組,不管檔名寫什麼,它標明的是真正的格式。PNG 一定以 89 50 4E 47 開頭,ZIP 則是 50 4B 03 04。作業系統、瀏覽器和 file 指令讀的都是這幾個位元組,而不是相信副檔名 — 這就是為什麼把檔案改名並不會改變它實際上是什麼。

我要怎麼自己檢查 magic number?

在 macOS 或 Linux 上,xxd -l 16 檔名 會印出前 16 個位元組;在 Windows 上,PowerShell 的 Format-Hex -Path 檔名 -Count 16。或者把檔案丟進本站的檔案類型辨識工具,它會在本機讀取位元組並告訴你是什麼格式,不會上傳任何東西。

為什麼兩種格式的 magic number 會一樣?

因為其中一種是建立在另一種之上。docx、xlsx、pptx、apk、jar 與 epub 骨子裡都是 ZIP 壓縮檔,所以全都以 ZIP 的簽章開頭;要分辨它們得看裡面的項目。Java class 檔和 macOS 的通用二進位檔都以 CA FE BA BE 開頭,靠緊接其後的欄位區分。

有完全沒有 magic number 的檔案嗎?

有。XML、HTML、JSON、SVG、CSV 這類以文字為基礎的格式沒有固定的位元組簽章,所以改用結構來辨識:開頭的 <?xml 宣告、<svg 元素,或是 { 後面接著帶引號的鍵。這種偵測是合理推測而非確定,因此本參考頁會把這些格式標示為結構偵測。

magic number 相符就代表檔案安全嗎?

不代表。它告訴你的是格式,不是內容是否無害 — 一個貨真價實的 PDF 或 docx 仍然可能夾帶惡意內容。辨識真實類型是有用的第一道檢查,尤其在副檔名和位元組不一致的時候,但它不是惡意軟體掃描。

手上有檔案可能是 PNG?用檔案類型辨識工具查出來 — 它在本機讀取 magic number,不上傳任何東西。或者瀏覽所有格式。