TIFF 檔案格式
Tagged Image File Format,掃描與印刷領域常用的彈性點陣圖容器。
- MIME 類型
- image/tiff
- 副檔名
- .tif, .tiff
- 分類
- 圖片
Magic number(檔案簽章)
| 0x00000000 | 49492A00 | II*· | 'II' little-endian + 42 |
大端序的 TIFF 開頭是 4D 4D 00 2A('MM' + 42)。
關於 TIFF 格式
TIFF 是以標籤為基礎的容器,可以容納多張影像、圖層與任意中介資料,在出版與文件掃描領域特別受青睞。前 2 位元組宣告位元組順序 — II 是小端序、MM 是大端序 — 後面接著 magic number 42。檔案裡其他所有東西都要靠追位移才找得到:標頭指向一份影像檔案目錄(IFD),每份目錄是一串 12 位元組的標籤項目加上指向下一份目錄的指標,而每個標籤不是把值直接放在項目裡,就是再指到別的地方去。這個設計就是 TIFF 熬死同期對手的原因,也是為什麼沒有兩個 TIFF 檔的結構長得一樣。
檔頭結構,一個位元組一個位元組看
| 位移 | 長度 | 欄位 | 意義 |
|---|---|---|---|
| 0 | 2 | Byte order | 49 49 是 II、小端序,4D 4D 是 MM、大端序。它決定整個檔案裡每一個多位元組數字該怎麼讀,包括緊接在它後面的那兩個位元組,所以這是唯一一個必須最先讀完、否則什麼都解讀不了的欄位。這份目錄的簽章只列小端序那一種,因為雙向的簽章沒辦法用固定位元組表示。 |
| 2 | 2 | Version number | 數字 42,在大端序檔案裡寫成 00 2A,小端序寫成 2A 00。它其實不算版本號 — 從來沒變過 — 而是第二個 magic number,順便證明位移 0 的位元組順序沒騙人。這裡是 43 就代表 BigTIFF,那是完全不同的標頭排版。 |
| 4 | 4 | Offset of the first image file directory | IFD0 從哪裡開始,從檔案開頭算起。沒有任何規定要求它是小數字:寫入端完全可以把目錄放在像素資料後面,macOS 的 sips 就常常這樣做,所以標頭指向幾千個位元組之後是完全正常的事。這個位移必須是偶數,而且不能是零。 |
| 8 | variable | First byte after the header | 位移 8 是 IFD 合法能待的最早位置,也很常見,但它終究只是位移 4 那個標頭剛好指到的地方。IFD 本身是 2 位元組的項目數,接著那麼多個 12 位元組的項目 — 標籤、型別、數量,然後不是值本身就是指向值的位移 — 最後是 4 位元組、指向下一份 IFD 的位移,或是用零結束整條鏈。 |
| 4 | 2 | Offset byte size — BigTIFF only | 當位移 2 讀到的是 43 而不是 42,標頭就多八個位元組,而這個欄位放的是檔案位移的大小,固定是 8。把 BigTIFF 當成傳統 TIFF 來讀,這個欄位會被看成 IFD 指標的下半截,剖析器就被送到毫無意義的地方去了。 |
| 6 | 2 | Reserved — BigTIFF only | 固定是 00 00。它和前一個欄位加起來,正好是傳統 TIFF 讀取器會當成四位元組 IFD 位移吃下去的那四個位元組 — 這也正是 BigTIFF 選擇改版本號、而不是硬要維持相容的理由。 |
| 8 | 8 | First IFD offset — BigTIFF only | 64 位元的位移,這就是 BigTIFF 的全部重點:傳統 TIFF 定址不到四 GB 之後的任何東西。BigTIFF 的目錄項目是二十個位元組而不是十二個,數量與值都是 64 位元,所以兩種排版除了前兩個位元組之外沒有任何共通處。 |
怎麼跟長得像的格式分開
| 容易搞混的 | 怎麼分 |
|---|---|
| Big-endian TIFF | 這份目錄的簽章只涵蓋 49 49 2A 00。大端序的檔案是 4D 4D 00 2A,一樣合法也一樣常見 — Motorola 與 Sun 血統的掃描器和印前軟體預設就寫這種,JPEG 裡的 Exif 也常常用它。只比對其中一種的偵測器,會把全世界一半的 TIFF 判成不明格式。 |
| JPEG | 它不是對手,而是一種值得在 hex dump 裡認出來的容器關係:JPEG 裡的 Exif 區塊本身就是一份完整、自成一體的 TIFF 結構。相機拍的 JPEG 裡,位移 12 會看到 49 49 2A 00 或 4D 4D 00 2A,就在 ASCII 的 Exif 加兩個 NUL 之後六個位元組。那份結構裡每個位移都是相對於 TIFF 標頭、不是相對於檔案,這就是自己手寫的 Exif 剖析器讀出一堆亂碼的經典原因。 |
| DNG | DNG、NEF、ARW、ORF 和多數其他 raw 格式,在位元組層級就是 TIFF 檔案,用 TIFF 讀取器可以乾淨地剖析完;真正認出它們身分的是 IFD0 裡的標籤,例如 DNG 的 DNGVersion(0xC612)。Canon 的 CR2 是例外,它標了自己的標頭,在位移 8 那個原本該放第一份目錄的位置塞了 ASCII 的 CR 和一組版本號 — 這種排版是逆向工程記錄下來的,不是 Canon 公布的。 |
| BigTIFF | 一個位元組的事。用檔案剛剛宣告的位元組順序去讀位移 2 的版本欄位:42 是傳統版,43 是 BigTIFF。凡是裝著全玻片顯微影像、衛星影像或大型 OME-TIFF 堆疊的都是後者;傳統 TIFF 讀取器拿到 BigTIFF 不會畫出錯的圖,它會算出一個荒謬的 IFD 位移然後報錯。 |
常見的壞法
- 截斷,而且行為跟這裡多數格式完全相反。當寫入端把 IFD0 放在像素資料後面(這是合法而且常見的選擇),被截斷的 TIFF 掉的是整份目錄,每一條掃描線卻都還在,於是影像明明完整卻打不開。要救就得猜出寬、高和位元深度,再手工重建一份目錄。
- IFD 位移指到檔案結尾之外。標頭完美無缺,讀取器卻無從下手,只能吐出「這不是 TIFF」這種幫不上忙的通用訊息。上傳到一半、或串接錯誤的掃描件,通常就長這樣。
- 位元組順序那兩個位元組被改寫或遺失。把 II 翻成 MM,版本號就讀不出 42,檔案立刻被拒收;如果版本號還讀得出來、卻在別處誤判了順序,檔案裡每個寬度、高度和位移都會變成天文數字。
- 編輯之後 StripOffsets 沒更新。目錄記著每一條掃描線帶(strip)住在哪裡,而工具重寫了影像資料卻沒更新那些標籤,產出的檔案打得開、尺寸也報得對,接著就把檔案裡錯誤位置的內容一帶一帶畫上去 — 看起來就是圖被切成一條條水平區塊,順序全亂。
- 標籤的值疊到標頭上。任何超過四個位元組的值都存在別處、用位移引用,而位移表差一格的寫入端,可能讓某個標籤指向標頭本身。檔案能通過結構檢查,中介資料讀出來卻是一團亂。
這個格式現在還在用嗎
TIFF 是給「這個檔案必須活下來」用的,不是給「這個檔案要送出去」用的。文件掃描與典藏影像幾十年前就標準化在它身上,因為它一個檔案裝得下多頁、對黑白掃描件有無損的 CCITT Group 4,還讓機構可以掛上自家編目需要的任何自訂中介資料而不會弄壞別人的讀取器。印前與印刷留住它,是為了 CMYK、特別色和內嵌 ICC 描述檔,這些 JPEG 表達不出來。攝影留住它,是因為 Adobe 的 DNG raw 格式本身就是 TIFF,所以現代相機吐出來的每個 raw 檔都是換了張皮的 TIFF。科學界抓得最緊:GeoTIFF 為衛星與地圖資料加上座標參考系統,OME-TIFF 和 BigTIFF 則把顯微影像堆疊帶到遠遠超過原始設計那個四 GB 上限的地方。它從來不是網路格式 — 沒有瀏覽器會顯示它 — 而且它的彈性確實是個負債:一個合法的 TIFF 可以用十來種壓縮方式和十來種色彩模型的任意組合,而號稱「支援 TIFF」的軟體,通常只是支援作者當年遇過的那兩三種變體。
在這個站上打開 TIFF 檔
這些全部在你的瀏覽器裡跑,檔案不會離開你的電腦。
相關格式
容易和 TIFF 搞混的格式,可以比對它們的開頭位元組。