news 2026/10/6 11:33:24

HEIF/HEIC 文件结构解析:ISO/IEC 23008-12:2017 标准与 box 实战

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
HEIF/HEIC 文件结构解析:ISO/IEC 23008-12:2017 标准与 box 实战

简介:ISO/IEC 23008-12:2017 是国际标准化组织与国际电工委员会联合发布的图像文件格式标准,聚焦高效编码与异构环境下的媒体交付,是理解 HEIF、HEIC 格式的权威依据。资源面向从事图像编解码、移动端多媒体开发、流媒体与智能终端适配的工程师及研究人员,帮助厘清 HEVC 编码下图像容器的结构规范与互操作要求。压缩包内共 1 个 PDF 文件,约 906KB,即标准正文,涵盖范围、规范性引用、术语定义、总体要求等章节,并涉及图像序列、元数据存储、兼容性转换与性能测试等核心内容。目前已有 259 人学习浏览。通过该标准可系统掌握 HEIF/HEIC 的文件组织方式、解码器与编码器规范,以及与其他图像格式的转换规则,为实际开发中的格式解析、兼容性排查与方案设计提供一手参考。

1. 从一张 iPhone 照片说起:ISO/IEC 23008-12:2017 到底规定了什么

你从 iPhone 导出一张.heic照片,扔进某些老版本 Windows 或 Android 工具里,要么打不开,要么只剩一张缩略图,要么色彩发灰。问题往往不在“解码器不行”,而在于没吃透 ISO/IEC 23008-12:2017 这份标准对 HEIF 文件结构的约束。它是 MPEG 体系下 High Efficiency Coding and Media Delivery 的第 12 部分,2017 年 12 月首版,专门定义 Image File Format,也就是大家口中的 HEIF,.heic是它最常见的编码载体。标准从 ISO Base Media File Format 派生,规定了 image item、image sequence、derived image、image properties、metadata 等 box 的组织方式。适合做相册、相机管线、跨端图片 SDK、格式转换工具的工程师;如果你只是偶尔转个图,了解第 2 章就够,想做解析器或写入器,后面几章的 box 语义必须啃。

2. HEIF 的 box 骨架:从 ISO BMFF 派生出的图像容器

2.1 为什么 HEIF 不是“另一种 JPEG”

JPEG 把整张图当成一段连续熵编码数据,元数据靠 APPn 段塞进去,结构松散。HEIF 走的是 ISO BMFF 路线:文件是一棵 box 树,图像数据被切成多个 item,每个 item 有类型、有属性、有位置。ISO/IEC 23008-12:2017 第 6 章明确,单张图像和图像集合都从 ISO base media file format 派生,metabox 下挂hdlr、pitm、iloc、iinf、iprp、iref等。这样做的好处是:一张 HEIC 里可以同时放主图、缩略图、辅助图、深度图、透明通道,还能声明它们之间的引用关系。代价是解析器必须按 box 逐层读,不能像 JPEG 那样扫到 SOI 就开干。

常见做法是先用ffprobe或MP4Box看 box 结构,再决定自己写到哪一层。下面这段命令能快速列出顶层 box:

# 列出 HEIC 文件顶层 box 类型与大小 xxd -l 256 photo.heic # 或用 MP4Box 查看完整 box 树 MP4Box -info photo.heic 2>&1 | head -60

xxd看的是前 256 字节,能确认ftyp品牌是不是heic、mif1、msf1。MP4Box -info会打印meta、iprp、iloc等层级。参数上,-info只读不写,适合排查;如果要看某个 item 的偏移,得配合-dump-item。

2.2 核心 box 的职责划分

标准第 9 章对 ISO BMFF 做了扩展,重点在ItemInfoEntry和Item Properties Box。iinf描述每个 item 的 ID 和类型,iloc给出数据偏移和长度,iprp里的ipco是属性容器,ipma把属性关联到具体 item。iref负责 item 之间的引用,比如缩略图指向主图、辅助图指向主图。pitm指定主 item,读图工具通常先找它。

box作用常见坑
ftyp声明品牌与兼容性品牌写错导致播放器拒识
meta图像元数据总容器版本号与 flags 影响子 box 解析
iinfitem 信息表item 类型hvc1/grid/iden混用
iloc数据位置构造方式 0/1/2 偏移基数不同
iprp属性容器ipma关联错位导致色彩异常
irefitem 引用缩略图未正确指向主图

这张表不是让你背,而是排错时按行查。比如色彩发灰,先看iprp里有没有colr,再看ipma有没有把它关联到主 item。

2.3 用 Python 读ftyp和meta的最小实现

不依赖第三方库也能起步。下面这段代码只做一件事:按 box 长度和类型遍历,打印层级。

import struct def read_boxes(data, offset=0, end=None, depth=0): """递归读取 ISO BMFF box,打印类型与大小""" if end is None: end = len(data) while offset < end: if offset + 8 > end: break size, = struct.unpack('>I', data[offset:offset+4]) btype = data[offset+4:offset+8].decode('latin1') header = 8 if size == 1: # 64 位长度 size, = struct.unpack('>Q', data[offset+8:offset+16]) header = 16 elif size == 0: # 延伸到文件末尾 size = end - offset print(' ' * depth + f'{btype} size={size}') # 只递归容器 box,避免把图像数据当 box 读 if btype in ('meta', 'iprp', 'ipco', 'iinf', 'iref'): child_start = offset + header if btype == 'meta': child_start += 4 # meta 有 version/flags read_boxes(data, child_start, offset + size, depth + 1) offset += size with open('photo.heic', 'rb') as f: read_boxes(f.read())

逻辑说明:struct.unpack('>I')读 32 位大端长度,size==1时读 64 位,size==0表示到文件尾。metabox 在 ISO BMFF 里是 FullBox,前 4 字节是 version 和 flags,所以递归子 box 时要跳过。参数上,depth只控制缩进,不影响解析。这段代码不处理uuidbox 和widebox,生产环境要补。

提示:读iloc时注意 construction method。方法 0 的偏移是相对文件起点,方法 1 是相对idatbox,方法 2 是相对metabox。搞错基数会读到完全无关的数据。

3. 图像属性与派生图像:色彩、旋转、缩略图怎么落 box

3.1ipco里的属性不是装饰品

标准 6.5 节列了一长串 image properties:decoder configuration、spatial extents、pixel aspect ratio、colour information、pixel information、relative location、clean aperture、rotation、mirroring、layer selection。它们都放在ipco里,由ipma按 item ID 关联。ispe给宽高,pixi给通道位深,colr给色彩原色和传递特性,irot给旋转角度,imir给镜像。很多工具读 HEIC 时方向不对,就是没处理irot和imir。

irot的角度是逆时针 0/90/180/270,存在 1 字节里,实际值要乘 90。imir的 axis 为 0 表示上下翻转,1 表示左右翻转。这两个属性经常和 EXIF Orientation 同时存在,谁优先?标准里irot/imir是容器级变换,EXIF 是元数据级,解析器一般先应用容器变换再读 EXIF。如果两处冲突,以容器为准更安全。

3.2 派生图像:grid与iden

6.6 节定义了 derived image。最常见的是grid,把多张图拼成一张,用于 HEVC 的 tile 编码。iden是 identity,表示派生图就是原图。griditem 的数据区不是像素,而是一段描述:行数、列数、每块宽高。解析时要先读grid描述,再按dimg引用找到各 tile,最后拼合。

下面这段代码演示如何从iref里找dimg引用:

def parse_iref(data, offset, size): """解析 iref box,返回 {from_id: [(type, to_id), ...]}""" refs = {} pos = offset + 8 + 4 # 跳过 box header 和 FullBox version/flags end = offset + size while pos < end: ref_size, = struct.unpack('>I', data[pos:pos+4]) ref_type = data[pos+4:pos+8].decode('latin1') child = pos + 8 child_end = pos + ref_size while child < child_end: from_id, = struct.unpack('>H', data[child:child+2]) to_id, = struct.unpack('>H', data[child+2:child+4]) refs.setdefault(from_id, []).append((ref_type, to_id)) child += 4 pos += ref_size return refs

逻辑说明:iref是 FullBox,跳过 4 字节 version/flags 后,每个子 box 是SingleItemTypeReferenceBox,里面是一组from_item_ID和to_item_ID。ref_type常见有dimg(派生来源)、thmb(缩略图)、auxl(辅助图)。参数上,item ID 是 16 位,超过 65535 的 item 需要iref的 32 位变体,标准里有定义但少见。

3.3 缩略图与辅助图的引用关系

缩略图用thmb引用主图,辅助图用auxl。辅助图类型由auxC属性里的 URN 决定,比如深度图、透明通道、alpha。标准 6.4 节还定义了 hidden image、cover image、master image、pre-derived coded image、multi-layer image。hidden image 不在普通浏览中显示,但可被引用。cover image 用于相册封面。这些角色不是靠文件名区分,而是靠iref和属性组合。

实操中,如果你要生成 HEIC,常见做法是:主图一个 item,缩略图一个 item,thmb指向主图,ispe给缩略图尺寸,colr继承主图。辅助图要加auxC,URN 写对,否则播放器不知道这是深度还是 alpha。

注意:auxC的 URN 字符串必须符合标准注册值,自己编一个会导致兼容性问题。常见值包括urn:mpeg:hevc:2015:auxid:1和urn:mpeg:hevc:2015:auxid:2。

4. 图像序列与元数据:从单张到轨道

4.1 image sequence 不是视频轨的简单复用

标准第 7 章讲 image sequences。它从 ISO BMFF 的 track 派生,但 handler type 不同,hdlr里要写pict。Track Header box 的字段有约束,Coding Constraints box 也有专门要求。图像序列可以带缩略图序列轨和辅助图序列轨,分别用thmb和auxl引用。和普通视频轨的区别在于:图像序列的样本是静态图像编码,时间轴用于连拍或动画,不是连续运动补偿。

如果你用ffmpeg把一组 HEIC 转成序列,注意它可能默认按视频处理,丢掉picthandler。更稳的做法是用MP4Box的-add配合-new指定序列类型,或者直接按标准写 box。

4.2 元数据与完整性校验

第 8 章规定 metadata support,包括 image item 和 image sequence track 的元数据,以及 integrity checks。完整性校验的语法和语义在 8.4 节,用于验证 item 数据没被篡改。常见实现是存一个哈希或校验和,读取时比对。实际产品里用得不多,但做归档或版权保护时会用到。

元数据可以放在meta下的ilst,也可以放在 item 属性里。EXIF 和 XMP 通常作为独立 item,用cdsc引用主图。这样设计的好处是元数据可以单独更新,不用重写图像数据。

4.3 用MP4Box做一次完整拆包

# 查看 HEIC 所有 item MP4Box -info photo.heic # 导出主图 item 到 raw 文件 MP4Box -dump-item 1:path=item1.hevc photo.heic # 导出所有 item MP4Box -dump-item all:path=items photo.heic

-dump-item的1是 item ID,来自iinf。导出后得到的是 HEVC 码流,不是直接可看的图片,还要送解码器。参数path=指定输出目录或文件名。如果 item 是grid,导出的是描述数据,不是像素。

提示:不同版本的MP4Box对 HEIF 支持程度不同,遇到解析失败先升级 GPAC,再确认文件ftyp品牌是否在支持列表里。

5. 避坑与排查:HEIC 解析中最容易翻车的五件事

5.1 现象:图片能打开但颜色发灰

原因:colr属性缺失或ipma没关联到主 item,解码器按默认 sRGB 处理,实际是 Display P3 或 BT.2020。 解决:读iprp/ipco找colr,确认colour_type是nclx还是prof,再查ipma的 association。如果colr存在但没关联,手动补关联或换解析库。

5.2 现象:缩略图显示成主图

原因:pitm指向了缩略图 item,或者thmb引用方向写反。 解决:pitm的 item ID 必须是主图。thmb是缩略图指向主图,不是主图指向缩略图。用MP4Box -info确认pitm值。

5.3 现象:iloc读到的数据是乱码

原因:construction method 搞错,或者base_offset没加。 解决:先看iloc的 version 和 flags,方法 0 用文件绝对偏移,方法 1 用idat偏移,方法 2 用meta偏移。把base_offset和extent_offset相加再读。

5.4 现象:多 tile 图拼出来错位

原因:grid的行列数和 tile 顺序没按标准读,或者 tile 尺寸不一致。 解决:grid数据区前 4 字节是 version/flags,接着 1 字节 rows-1、1 字节 columns-1、4 字节 output width、4 字节 output height。tile 按行优先排列,尺寸由各自ispe给出。拼合时按dimg引用顺序放。

5.5 现象:Windows 资源管理器不显示缩略图

原因:系统 HEIF 扩展没装,或文件ftyp品牌不被识别。 解决:确认ftyp包含heic或mif1。Windows 需要 HEIF Image Extensions 和 HEVC Video Extensions。这不是文件问题,是环境问题,别改文件结构去迁就。

6. 进阶:自己写一个 HEIC 解析器要盯住的三个参数

如果你不满足于调库,想自己写解析器,有三个参数决定成败。第一是iloc的 construction method,它决定偏移基数,写错全盘皆输。第二是ipma的 association 数量,一个 item 可以关联多个属性,顺序不重要,但必须全部处理。第三是iref的引用类型,dimg、thmb、auxl、cdsc语义不同,混用会导致派生图解析失败。

验证方法很简单:拿一张已知正确的 HEIC,用你的解析器读出主图宽高、色彩原色、旋转角度,和exiftool或MP4Box的输出比对。三个值全对,基本结构就通了。再拿一张带缩略图和深度图的 HEIC,检查iref是否完整。最后拿一张grid编码的 HEIC,拼合后和原图做像素级比对。

我自己的习惯是:每次改解析器,先跑这三类样本,再跑一遍iloc边界测试——偏移为 0、长度为 0、item ID 不连续的情况。血泪经验是,很多 bug 不在主流程,而在这些边界。从那以后我每次写 box 解析都强制走一遍边界样本,希望帮到你。

本文还有配套的精品资源,点击获取

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/6 11:33:24

ArduPilot避障实战:MR72与TFmini Plus参数配置与调试指南

1. 从零讲清楚&#xff1a;ArduPilot 避障到底在解决什么问题 很多人第一次接触 ArduPilot 的避障功能&#xff0c;脑子里想的都是“装个雷达&#xff0c;车就能自己绕开障碍物了”。但实际动手之后才发现&#xff0c;事情远没有这么简单——雷达装上了&#xff0c;参数也改了&…

作者头像 李华
网站建设 2026/10/6 11:33:01

VS Code + MCP + Seedream 搭建中文海报生成工作台指南

之前做海报&#xff0c;我的路径基本是&#xff1a;打开网页版 AI 绘画工具&#xff0c;把想好的文案粘进去&#xff0c;生成&#xff0c;下载&#xff0c;拖进修图软件改文字&#xff0c;再导出。听起来不算远&#xff0c;但一天做 5 张就烦了——来回切换窗口、反复试提示词、…

作者头像 李华
网站建设 2026/10/6 11:32:56

浏览器端侧视觉AI工程实战:WebGL+WASM协同推理

1. 这不是“跑个 demo”&#xff0c;而是把神经网络真刀真枪塞进浏览器标签页里 “把神经网络塞进一个浏览器标签页”——这句话听起来像极了技术圈里那种带点戏谑又藏着狠活的标题党。但如果你真去翻过 TensorFlow.js 的 GitHub star 数、看看 ONNX Runtime Web 的 release no…

作者头像 李华
网站建设 2026/10/6 11:32:46

DeepSeek Harness 桌面端安装配置与插件 Skill 实战指南

DeepSeek Harness 的官方桌面端终于来了。要说这玩意儿&#xff0c;圈子里不少搞 AI 辅助编码的人已经盼了大半年——以前要么在终端里敲命令&#xff0c;要么开个 Web 页面将就用&#xff0c;本地文件和模型之间的交互总是隔着一层。现在桌面端一出来&#xff0c;等于把之前 C…

作者头像 李华
网站建设 2026/10/6 11:32:45

Attero网络损伤仪实操:从接口到双方向损伤配置全解析

简介&#xff1a;这份中文使用手册面向网络设备测试与运维人员&#xff0c;聚焦Attero损伤仪在复杂网络环境下的性能评估需求。手册从硬件接口讲起&#xff0c;说明10GE光口、1G/100Mb电口、LED显示屏与PC控制终端连接方式&#xff0c;并提示XFP/SFP光模块选配、.NET Framework…

作者头像 李华
网站建设 2026/10/6 11:32:26

8GB内存旧电脑本地跑大模型:Ollama量化部署实战指南

前阵子收拾书桌&#xff0c;翻出一台吃了五年灰的旧笔记本&#xff0c;8GB内存、四核老CPU、集成显卡&#xff0c;跑个Chrome开十个标签都喘。本来想直接扔回收站&#xff0c;结果刷到一条帖子说这种配置也能本地跑大模型&#xff0c;还就是一行命令的事。我琢磨着反正闲着也是…

作者头像 李华