ByteScope

JPEG 檔案格式

有損壓縮的點陣圖格式,照片的通用格式。

MIME 類型
image/jpeg
副檔名
.jpg, .jpeg
分類
圖片

Magic number(檔案簽章)

0x00000000FFD8FF···Start-Of-Image marker

關於 JPEG 格式

JPEG 使用針對照片調校的離散餘弦轉換來壓縮,以幾乎看不出來的少量畫質換取檔案大小的大幅下降。檔案以 Start-Of-Image 標記 FF D8 開頭,並以 FF D9 結尾。這兩個標記之間全部是一連串的 segment,每一段都由 FF 加一個標記位元組帶頭,而且幾乎每一段緊接著都有兩個位元組的大端序長度 — 剖析器不必看懂任何一段,也能靠這個長度一路走完整個 JPEG。像素本身住在 Start-Of-Scan 標記之後的熵編碼串流裡,而那段串流是全檔唯一沒有長度欄位的部分:解碼器只能往前掃到下一個真正的標記,才知道它在哪裡結束。

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

位移長度欄位意義
02Start of Image markerFF D8。少數幾個沒有長度也沒有酬載的標記之一。這份目錄的簽章讀三個位元組而不是兩個,是因為下一個標記開頭的 FF 緊跟在後面,多要求這一個位元組就能排除掉剛好以 FF D8 開頭的檔案。
22First application markerFF E0 帶出 APP0,代表檔案遵循 JFIF;FF E1 帶出 APP1,通常代表 Exif。相機和手機寫 APP1,影像編輯器習慣先寫 APP0 再寫 APP1,兩個都有的檔案完全正常。
42Segment length這一段 segment 的位元組數,大端序,含這兩個位元組本身,但不含前面那兩個標記位元組。沒有縮圖的 APP0 會讀到 00 10 — 十六 — 所以下一個標記從 4 加 16、也就是位移 20 開始。
65JFIF identifier4A 46 49 46 00,ASCII 的 JFIF 加一個 NUL。如果排在最前面的是 APP1,位移 6 放的會是 45 78 69 66 00 00 這六個位元組,整段就是 Exif 而不是 JFIF。
112JFIF version主版本號和次版本號各一個位元組:01 01 是 1.01,01 02 是 1.02。只有在 APP0 是第一段時才存在;Exif 排前面的檔案裡,這兩個位元組已經是 TIFF 結構的一部分了。
131Density units0 代表後面那組密度數字只表示長寬比,1 代表每英吋點數,2 代表每公分點數。很多編碼器這裡寫 0,卻還是照樣填上 72 和 72 — 這就是為什麼從 JPEG 推算出來的列印尺寸常常毫無意義。
144Horizontal and vertical density兩個大端序 16 位元數字,先 X 後 Y,怎麼解讀要看前面那個單位位元組。這是 JFIF 版本的 pHYs,而且沒有任何東西會讓它跟 PNG 那邊保持一致。
182Thumbnail width and height寬和高各一個位元組,幾乎一律是 00 00。如果不是零,位移 20 之後會跟著寬乘高乘三個位元組的未壓縮 RGB,而位移 4 的段長度也會跟著變大 — 用手算就能對得起來。
-22End of Image markerFF D9,跟 SOI 一樣沒有長度。它後面的多餘位元組合法到解碼器會直接忽略,ZIP 壓縮檔和 shell script 就是這樣被夾帶進影像檔的。

怎麼跟長得像的格式分開

容易搞混的怎麼分
JFIF/Exif兩種都是 JPEG,差別完全由位移 2 的標記決定。FF E0 加上位移 6 的 4A 46 49 46 00 是 JFIF,而它能告訴你的就只有那組密度。FF E1 加上位移 6 的 45 78 69 66 00 00 是 Exif,位移 12 開始是一整份 TIFF 標頭 — 49 49 2A 00 或 4D 4D 00 2A,接著四個位元組指向第一個目錄。相機型號、曝光、方向和 GPS 都在那裡。一個檔案可以同時帶兩段,這時值得讀的是 Exif 那段。
HEIC這兩種格式在同一批手機上搶同一個工作,切換它們的設定藏在相機 app 裡的某個開關。JPEG 在位移 0 是 FF D8 FF。HEIC 的位移 0 只是一個 box 長度,位移 4 才讀得到 66 74 79 70 68 65 69 63。iPhone 用「最相容」模式匯出的照片是 JPEG,其他都是 HEIC。
PNGFF D8 FF 對上 89 50 4E 47。與其相信副檔名不如查一下,因為存成 .png 的 JPEG 還是 JPEG,每個瀏覽器照樣畫得出來;也因為把截圖重新編成 JPEG,是圖裡文字糊掉最常見的單一原因。
JPEG 2000只是名字撞在一起的另一種編碼。純 JPEG 2000 codestream 開頭是 FF 4F FF 51;裝成 box 的 JP2 檔案形式開頭是 00 00 00 0C 6A 50 20 20 0D 0A 87 0A。兩種瀏覽器都解不開,所以從科學或典藏來源下載的 .jp2 看起來才會像壞掉。

常見的壞法

  • 截斷。標頭還在,所以檢視器知道尺寸、也畫得出照片上半部,接著熵編碼串流用完,畫面剩下的部分不是留在灰色就是重複最後一個區塊。判斷方式是看最後兩個位元組:完好的 JPEG 以 FF D9 結尾。
  • 掃描資料裡多了或少了一個位元組。霍夫曼編碼沒有位元組對齊可以重新同步,所以損壞之後的每一個區塊都用錯誤的 DC 預測值解出來,影像從那一列開始化成一條條偏移的色帶。除非編碼器有寫 restart 標記,否則救不回來。
  • 文字模式傳輸。那套毀掉 PNG 的換行轉換,在這裡一樣會改寫壓縮資料裡的 0D 0A,而 JPEG 沒有逐段的檢查碼可以察覺。檔案打得開、標頭完美無缺,下面三分之二糊成一片。
  • Exif 目錄壞掉。APP1 的段長度是對的,但 TIFF 結構裡某個位移指到段尾之外,照片的方向標籤就此遺失,在有些 app 裡轉了九十度、在另一些裡卻是正的。把整段拿掉可以修好顯示,代價是中介資料全滅。
  • 伺服器錯誤頁或多餘的 BOM 塞在前面。FF D8 FF 不在位移 0 了,嚴格的解碼器直接拒收,寬鬆的則往前掃過去照樣開起來,於是就出現那個熟悉的場面:圖在瀏覽器裡好好的,在 build 裡壞掉。

這個格式現在還在用嗎

JPEG 已經三十歲,網路上幾乎每一張照片還是用它送出去的。沒有第二種格式是被有史以來每一台相機、手機、瀏覽器、印表機、掃描器和數位相框都解得開的,而這種通用性比 WebP、AVIF、HEIC 能省下的那兩成到五成更值錢。它真正吃虧的是所有邊緣銳利的東西 — 截圖、示意圖、文字、線稿 — 因為區塊轉換抹掉的正好就是這類影像賴以成形的高頻細節;另一個是會被反覆編輯再存檔的東西,畢竟每存一次就是一次全新的有損編碼,傷害會累積。它完全沒有 alpha 通道,所以需要透明背景的 logo 不可能是 JPEG。原本的接班人 JPEG XL 能對既有 JPEG 做無損重壓縮,每個位元組換到的畫質也更好,但瀏覽器支援停在半路,今天還不是能拿來上線的選項。實務上現在的答案是:把 JPEG 留在 picture 元素裡當 fallback,吃得下 WebP 或 AVIF 的就送新格式。

在這個站上打開 JPEG 檔

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

相關格式

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

格式開頭位元組副檔名
PNG89 50 4E 47 0D 0A.png
WebP52 49 46 46.webp
HEIC66 74 79 70.heic
GIF47 49 46 38 39 61.gif

常見問題

檔案的 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 仍然可能夾帶惡意內容。辨識真實類型是有用的第一道檢查,尤其在副檔名和位元組不一致的時候,但它不是惡意軟體掃描。

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