Files

9.9 KiB
Raw Permalink Blame History

pyheic-struct

pyheic-struct 诞生的初衷,是为了解决我个人在迁移照片时遇到的需求:把三星手机拍摄的动态照片(Motion Photo)批量转换成 iOS/macOS 可以直接识别、导入的 Live Photo。
工具会自动拆分并重建 HEIC 与 MOV 配对文件,补齐 Apple 生态所必需的 ContentIdentifierPhotoIdentifier 与 MakerNote 元数据,让 macOS「照片」或 iOS 设备将它们视为同一张 Live Photo,而不是互不关联的静态图与视频。

Looking for an English version? Please see README.en.md. (本 README 以中文为主,当需要英文说明时可跳转到该文件。)

同时,转换流程也促使我编写了一套可复用的 HEIF/HEIC 结构化解析、诊断与重建工具:它能读出盒结构、修复三星特有的 shifted item ID、重算 iloc 偏移,并以可预测的方式重新写回文件。即便你暂时不需要完整的 Live Photo 转换,也能够将其中的模块用在其它 HEIC 调试或自定义处理流程中。


功能亮点

  • 三星 Motion Photo → Apple Live Photo:自动生成匹配的 HEIC 与 MOV,并写入统一的标识符;导入后即是一张可播放的 Live Photo。
  • 完整元数据补齐:在 MOV 中注入 ContentIdentifier,在 HEIC 中写入 MakerNote / PhotoIdentifier 等 Apple 生态所需字段。
  • HEIC 深层解析能力:提供 HEICFileHEICBuilder 等类,可读取 ftypmetailociinfiprpiref 等关键盒,适用于诊断和自定义修复。
  • 安全重建机制HEICBuilder 会自动重算偏移量与引用关系,避免手工编辑造成的结构损坏。
  • CLI 与 Python API 并存:既能在命令行一键转换,也可以在脚本、流水线甚至 GUI 中复用底层逻辑。
  • 真实样例随仓库提供:包含原始三星 HEIC、转换后的 Apple 兼容文件与苹果原生样例,便于对照调试。

组件概览

组件 作用
scripts/samsung_to_live_photo.py 命令行转换脚本,输出苹果兼容的 HEIC + MOV
scripts/batch_media_manager.py 图形化批处理工具:扫描目录、转换 Motion Photo、匹配 Live Photo 配对、清理由 MotionPhoto_Data 标记的冗余视频,并可归档原始素材
pyheic_struct.HEICFile 解析 HEIC 盒结构、重建主图、提取 Motion Photo 等
pyheic_struct.HEICBuilder 在修改元数据后重新写出 HEIC,确保偏移正确
pyheic_struct.convert_motion_photo 通用转换入口,可指定厂商与目标适配器
pyheic_struct.AppleTargetAdapter Apple 生态适配器,负责写入品牌、MakerNote、ContentIdentifier 等
pyheic_struct.handlers.SamsungHandler 三星专用处理逻辑:识别 mpvd、校正 shifted IDs
inspect_heic.py 快速巡检脚本,输出盒结构、偏移与引用信息

安装与环境

  • Python 3.10+
  • 必装依赖:Pillow>=10.0.0pillow-heif>=0.15.0
  • 新增依赖:piexif>=1.1.3(用于 MakerNote 写入)
  • 可选依赖:exiftool-wrapper>=0.5.0
  • 推荐系统安装 ExifTool
    • macOS: brew install exiftool
    • Ubuntu/Debian: sudo apt install libimage-exiftool-perl
    • Windows: 下载官方 exe 并加入 PATH

安装方式:

# 仓库根目录安装
pip install .

# 或开发模式(含可选依赖)
pip install -e .[full]

如仅需解析能力,可忽略 .[full];若要写入 MOV 的 ContentIdentifier,请启用 full 并确保系统可调用 exiftool


Windows/macOS 一键可执行程序

如果希望直接在 Windows 或 macOS 上使用单独的可执行文件,可以:

  • 在 GitHub Actions 中运行 Build Samsung Live Photo binaries 工作流(或等待自动触发),在构建完成后下载 SamsungToLivePhoto-windows / SamsungToLivePhoto-macos 构件;
  • 解压后按照压缩包内的 README.txt 操作即可(文件位于仓库的 packaging/README_windows.txtpackaging/README_macos.txt)。

若想自行本地打包,可在目标系统直接执行:

# Windows (PowerShell)
python -m pip install ".[full]" pyinstaller
pyinstaller --noconfirm --onefile --name SamsungToLivePhoto `
  --collect-all pillow_heif --collect-all pyheic_struct `
  scripts/samsung_to_live_photo.py

# macOS (bash/zsh)
python3 -m pip install ".[full]" pyinstaller
pyinstaller --noconfirm --onefile --name SamsungToLivePhoto \
  --collect-all pillow_heif --collect-all pyheic_struct \
  scripts/samsung_to_live_photo.py

打包完成后,可执行文件会出现在 dist/ 目录。Windows 版本为 SamsungToLivePhoto.exemacOS 版本为 SamsungToLivePhoto


快速开始:把三星动态照片变成 Live Photo

1. 准备样例

仓库中已经附带常用测试素材(位于 examples/ 目录):

  • examples/samsung.heic:原始三星 Motion Photo
  • examples/samsung_apple_compatible.HEIC / .MOV:转换后的示例输出
  • examples/apple.HEIC:来自苹果的原生 Live Photo 参考

2. 命令行一键转换

python3 scripts/samsung_to_live_photo.py examples/samsung.heic \
  --output-dir output/live

生成的 output/live/samsung_apple_compatible.heic.mov 拥有同一个 ContentIdentifierPhotoIdentifier,可直接导入 macOS「照片」验证。

常用参数:

参数 说明
source 必选,原始三星 HEIC
--output-dir 输出目录,默认与源文件相同路径
--heic-name / --mov-name 输出文件名(不含路径),默认 *_apple_compatible
--skip-mov-tag exiftool 时跳过 MOV 的 ContentIdentifier 注入

3. 通过 API 集成

from pathlib import Path
from pyheic_struct import convert_samsung_motion_photo, HEICFile, HEICBuilder

heic_path, mov_path = convert_samsung_motion_photo(
    "examples/samsung.heic",
    output_still=Path("converted/apple_ready.HEIC"),
    output_video=Path("converted/apple_ready.MOV"),
)

# 读取重建后的 HEIC,执行进一步操作
rebuilt = HEICFile(str(heic_path))
rebuilt.set_content_identifier("MY-INTERNAL-ID")
HEICBuilder(rebuilt).write("converted/customized.HEIC")

4. 图形化批处理工具(GUI

scripts/batch_media_manager.py 提供完整的桌面界面,便于批量巡检目录:

  • 递归扫描 HEIC/MOV/MP4 等媒体,并以进度条与日志反馈处理情况;
  • 检测 Live Photo 配对,自动移动缺失伴侣的孤立视频到安全子目录;
  • 将三星 Motion Photo 转换为 Apple 兼容的 HEIC + MOV,并补写 ContentIdentifier
  • 清理带 MotionPhoto_Data 标签、与 Motion Photo 重复的冗余 MP4
  • 可选地把成功转换的原始素材按照原路径层级移动到 归档/(或 Archive/)并打包 zip
  • 内置“停止”按钮和窗口关闭钩子,可安全取消长时间任务。

运行示例:

python3 scripts/batch_media_manager.py

Live Photo 转换管线解读

  1. 解析原始 HEIC:读取 ftypmetailoc 等盒;通过 handler 自动识别三星文件并查找 mpvd 盒。
  2. 重建主图像:借助 pillow-heif 还原三星的网格化主图,写入临时平面 HEIC(mif1 brand)。
  3. 提取并存储 MOV:抽取 mpvd 中的嵌入视频,写成独立 MOV,并用 exiftool 写入 ContentIdentifier(如未安装可跳过)。
  4. 修正 item ID 与引用:三星会将 item ID 左移 16 位;工具会同步修复 iinfipmairef
  5. 补齐 Apple 元数据:设置苹果兼容的 ftyp 品牌,写入新的 ContentIdentifierPhotoIdentifier,填充 MakerNote。
  6. 最终重建HEICBuilder 重新计算 iloc 偏移、盒大小并写回,释放临时文件。

了解以上步骤,有助于调试其它厂商的 Motion Photo,或在需要时定制新的 TargetAdapter。


核心 API 快速索引

  • pyheic_struct.convert_motion_photo(...):通用转换接口,可指定 vendor_hint(如 "samsung")与 TargetAdapter
  • pyheic_struct.convert_samsung_motion_photo(...):三星专用封装,调用更简洁。
  • pyheic_struct.HEICFile
    • get_primary_item_id()reconstruct_primary_image()list_items() 等解析方法
    • set_content_identifier()set_exif_maker_note() 等元数据操作
  • pyheic_struct.HEICBuilder:将修改后的 HEICFile 安全写回磁盘。
  • pyheic_struct.handlers.VendorHandler:厂商自定义扩展基类。
  • pyheic_struct.targets.TargetAdapter / AppleTargetAdapter:目标生态适配接口。

扩展与自定义

  1. 实现新的厂商 Handler:继承 VendorHandler,实现 matchesextract_motion_videoprepare_flat_heic 等方法,并注册到 HANDLER_REGISTRY
  2. 接入其它目标生态:继承 TargetAdapter,在 apply_to_flat_heic / post_process_mov 中写入所需元数据或外部脚本。
  3. 诊断 HEIC 文件:使用 inspect_heic.py 或直接调 HEICFile API,输出盒结构、偏移与引用,便于对比不同厂商实现。

常见问题

  • 导入照片后仍显示两个文件?
    请确认系统安装了 exiftool,并在转换时未使用 --skip-mov-tag。同时建议使用工具生成的最新 HEIC/MOV,避免手动修改导致标识符不匹配。

  • 能否支持其它厂商的 Motion Photo
    可以。通过实现新的 handler 并组合自定义 target adapter,即可重用现有的重建管线。

  • 英文说明在哪里?
    参见 README.en.md;若你想贡献改进英文文档,也欢迎提交 PR。


开发提示

  • 项目使用 ruff / black 风格指南,可根据需要自行配置。
  • 在修改 HEIC 结构后务必重新运行转换脚本,确保 HEICBuilder 输出的文件能被 pillow-heifexiftool 读取。
  • 欢迎围绕 HEIC 解析、Motion Photo 适配提交 issue 或 PR,特别是其它安卓厂商的兼容性案例。