深度解析

什么是 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

你的文件永远不会离开你的设备。这才是重点。

更多推荐阅读