深度解析

什麼是 HEIC?從檔案簽名、偵測到轉換的技術深度解析

koboshiCo-founder
·4 分鐘閱讀
什麼是 HEIC?從檔案簽名、偵測到轉換的技術深度解析
概述

HEIC 不只是體積更小的 JPEG。它是一種基於 ISO Base Media File Format 的容器格式,內部封裝 HEVC 編碼的影像。本文詳解其運作原理、如何透過讀取原始位元組偵測它,以及在相容性失敗時如何轉換。

用十六進位編輯器開啟一個 HEIC 檔案。前十二個位元組:

00 00 00 18 66 74 79 70 68 65 69 63

這是 ISOBMFF —— MP4 使用的同一個容器標準。0x18(24 位元組)是 box 大小,ftyp 是檔案類型 box,heic 是主品牌。HEIC 檔案不是影像編碼,它是一個帶品牌標記的容器,內部封裝 HEVC 編碼的影像。

HEIC 到底是什麼

HEIC = High Efficiency Image Container。Apple 對 HEIF 的品牌化實作,MPEG 於 2015 年標準化為 ISO/IEC 23008-12。JPEG 同時是壓縮演算法和檔案格式,HEIC 只是一個容器。內部壓縮用的是 HEVC(H.265),與 4K 影片同一個編解碼器。

單個 HEIC 檔案可以儲存:

  • 一幅主影像
  • 多幅備選影像(連拍)
  • 影像序列(原況照片:靜態圖 + 3 秒影片)
  • Alpha 通道和深度圖
  • 每通道 16 位元色深(JPEG 上限為 8 位元)

容器使用 box 結構 —— 與 MP4 完全一致:

Box作用
ftyp檔案類型和相容品牌
meta項目詮釋資料和屬性
mdat原始編碼影像資料(HEVC 位元流)
iloc項目在 mdat 中的位置

正是這種可擴展性讓 HEIC 做到了 JPEG 永遠做不到的事。解析它需要理解 box 層級,而不是簡單讀取原始位元流。

Apple 為什麼切換

Apple 沒有發明 HEIC。MPEG 於 2015 年發布了 HEIF,Apple 在 2017 年的 iOS 11 中將其採納為 iPhone 預設相機格式。

切換的驅動力是算術,不是行銷。一張 1200 萬畫素的 iPhone 照片,JPEG 約 3.5 MB,HEIC 約 1.8 MB。在 50 GB 的免費 iCloud 儲存檔位下,這個差距意味著大約多出 14,000 張照片。Apple 賣儲存檔位,這筆賬不用算第二遍。

另一個因素是生態對齊。Apple 早已在影片中採用 HEVC(iOS 11 中的 H.265)。對靜態影像復用同一個編解碼器,意味著 A 系列晶片上可以共享硬體解碼模組、降低功耗,並且只需要一條授權路徑。

利弊權衡

HEIC 在幾乎所有指標上都優於 JPEG,除了相容性。

維度HEICJPEG
壓縮效率同等畫質下小約 40–50%基準
色深最高 16 位元8 位元
透明度支援不支援
單檔案多圖支援不支援
無損再編輯支援不支援
Windows 原生支援需安裝 HEIF 擴充功能通用
Web 瀏覽器支援僅 Safari通用
Android 支援9 以上原生支援通用
專利授權HEVC 專利池JPEG 免權利金

HEVC 被多個專利池覆蓋(MPEG LA、Access Advance)。Apple 替 iOS 使用者支付了授權費,第三方廠商沒有這份待遇。這種不確定性是 Apple 生態系統之外採用停滯的主要原因。

透過讀取檔案簽名偵測 HEIC

不要信任 .heic 副檔名。讀取前 32 位元組,解析 ftyp box。

有效 HEIC 檔案頭的精確位元組布局:

Bytes 0–3:   Box 大小(大端 uint32)
Bytes 4–7:   Box 類型: "ftyp"(0x66 0x74 0x79 0x70)
Bytes 8–11:  主品牌: "heic" 或 "heif" 或 "mif1"
Bytes 12–15: 次版本號(通常為 0x00000000)
Bytes 16+:   相容品牌列表(如 "mif1"、"heic"、"MiHE")

瀏覽器端 TypeScript:

async function isHeic(file: File): Promise<boolean> {
  const buffer = await file.slice(0, 32).arrayBuffer()
  const bytes = new Uint8Array(buffer)

  if (String.fromCharCode(...bytes.slice(4, 8)) !== "ftyp") return false

  const brand = String.fromCharCode(...bytes.slice(8, 12))
  return ["heic", "heif", "mif1", "msf1"].includes(brand)
}

我們的轉換器在嘗試解碼前會執行這項檢查。品牌不對 = 立即拒絕,不浪費 CPU。

Python

def is_heic(path: str) -> bool:
    with open(path, "rb") as f:
        header = f.read(32)

    if len(header) < 12:
        return False

    if header[4:8].decode("ascii", errors="ignore") != "ftyp":
        return False

    return header[8:12].decode("ascii", errors="ignore") in {"heic", "heif", "mif1", "msf1"}

更高階的偵測可以用 filetype

import filetype

kind = filetype.guess("photo.heic")
if kind and kind.extension in ("heic", "heif"):
    print(kind.mime)  # image/heic

或使用 pillow-heif

from pillow_heif import is_heif

if is_heif("photo.heic"):
    # 有效容器
    pass

Go

func isHeic(path string) bool {
	f, err := os.Open(path)
	if err != nil {
		return false
	}
	defer f.Close()

	buf := make([]byte, 32)
	if _, err := f.Read(buf); err != nil {
		return false
	}

	if string(buf[4:8]) != "ftyp" {
		return false
	}

	brand := string(buf[8:12])
	return brand == "heic" || brand == "heif" || brand == "mif1" || brand == "msf1"
}

PHP

function isHeic(string $path): bool {
    $header = file_get_contents($path, false, null, 0, 32);
    if (strlen($header) < 12) return false;
    if (substr($header, 4, 4) !== 'ftyp') return false;

    return in_array(substr($header, 8, 4), ['heic', 'heif', 'mif1', 'msf1'], true);
}

使用 fileinfo

$finfo = new finfo(FILEINFO_MIME_TYPE);
$mime = $finfo->file('photo.heic');
// image/heic 或 image/heif

ImageMagick CLI

ImageMagick 7+ 在編譯時帶上 libheif 後支援 HEIC:

magick identify -verbose photo.heic | grep "Format:"
# Format: HEIC (High Efficiency Image Container)

如果未編譯 libheif,會返回 no decode delegate for this image format。大多數 Linux 發行版上,安裝 libheif-examples 會提供 heif-convert 作為替代方案。

轉換路徑

知道一個檔案是 HEIC,不代表你能開啟它。Windows 需要 HEIF Image Extensions。大多數瀏覽器拒絕在 <img> 標籤中渲染 HEIC。Android 9+ 原生支援,老舊裝置不支援。

解決方式:轉換。我們的 HEIC 轉 JPG 轉換器 在瀏覽器中處理整個流程:

  1. 拖曳檔案 — 單張照片或整個資料夾,自動批次處理。
  2. 簽名驗證 — 上述位元組檢查對每個檔案執行。非 HEIC 檔案立即拒絕並給出清晰提示。
  3. 客戶端解碼 — libheif 的 WebAssembly 版本在本地執行。不上傳。不觸碰伺服器。
  4. 保品質輸出 — 90% 品質的 JPG 保留原始解析度和色彩精度。
  5. 批次下載 — 單個檔案或一個 ZIP 壓縮檔。

需要帶透明度的無損輸出:HEIC 轉 PNG。需要針對 Web 優化的體積:HEIC 轉 WebP

你的檔案永遠不會離開你的裝置。這才是重點。

更多推薦閱讀