182 lines
8.8 KiB
Markdown
182 lines
8.8 KiB
Markdown
# pyheic-struct
|
||
|
||
`pyheic-struct` 诞生的初衷,是为了解决我个人在迁移照片时遇到的需求:把三星手机拍摄的动态照片(Motion Photo)批量转换成 iOS/macOS 可以直接识别、导入的 Live Photo。
|
||
工具会自动拆分并重建 HEIC 与 MOV 配对文件,补齐 Apple 生态所必需的 `ContentIdentifier`、`PhotoIdentifier` 与 MakerNote 元数据,让 macOS「照片」或 iOS 设备将它们视为同一张 Live Photo,而不是互不关联的静态图与视频。
|
||
|
||
> Looking for an English version? Please see [README.en.md](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 深层解析能力**:提供 `HEICFile`、`HEICBuilder` 等类,可读取 `ftyp`、`meta`、`iloc`、`iinf`、`iprp`、`iref` 等关键盒,适用于诊断和自定义修复。
|
||
- **安全重建机制**:`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.0`、`pillow-heif>=0.15.0`
|
||
- 新增依赖:`piexif>=1.1.3`(用于 MakerNote 写入)
|
||
- 可选依赖:`exiftool-wrapper>=0.5.0`
|
||
- 推荐系统安装 [ExifTool](https://exiftool.org/)
|
||
- macOS: `brew install exiftool`
|
||
- Ubuntu/Debian: `sudo apt install libimage-exiftool-perl`
|
||
- Windows: 下载官方 exe 并加入 `PATH`
|
||
|
||
安装方式:
|
||
|
||
```bash
|
||
# 仓库根目录安装
|
||
pip install .
|
||
|
||
# 或开发模式(含可选依赖)
|
||
pip install -e .[full]
|
||
```
|
||
|
||
如仅需解析能力,可忽略 `.[full]`;若要写入 MOV 的 `ContentIdentifier`,请启用 `full` 并确保系统可调用 `exiftool`。
|
||
|
||
---
|
||
|
||
## 快速开始:把三星动态照片变成 Live Photo
|
||
|
||
### 1. 准备样例
|
||
|
||
仓库中已经附带常用测试素材(位于 `examples/` 目录):
|
||
|
||
- `examples/samsung.heic`:原始三星 Motion Photo
|
||
- `examples/samsung_apple_compatible.HEIC` / `.MOV`:转换后的示例输出
|
||
- `examples/apple.HEIC`:来自苹果的原生 Live Photo 参考
|
||
|
||
### 2. 命令行一键转换
|
||
|
||
```bash
|
||
python3 scripts/samsung_to_live_photo.py examples/samsung.heic \
|
||
--output-dir output/live
|
||
```
|
||
|
||
生成的 `output/live/samsung_apple_compatible.heic` 与 `.mov` 拥有同一个 `ContentIdentifier` 和 `PhotoIdentifier`,可直接导入 macOS「照片」验证。
|
||
|
||
常用参数:
|
||
|
||
| 参数 | 说明 |
|
||
| ---- | ---- |
|
||
| `source` | 必选,原始三星 HEIC |
|
||
| `--output-dir` | 输出目录,默认与源文件相同路径 |
|
||
| `--heic-name` / `--mov-name` | 输出文件名(不含路径),默认 `*_apple_compatible` |
|
||
| `--skip-mov-tag` | 无 `exiftool` 时跳过 MOV 的 `ContentIdentifier` 注入 |
|
||
|
||
### 3. 通过 API 集成
|
||
|
||
```python
|
||
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;
|
||
- 内置“停止”按钮和窗口关闭钩子,可安全取消长时间任务。
|
||
|
||
运行示例:
|
||
|
||
```bash
|
||
python3 scripts/batch_media_manager.py
|
||
```
|
||
|
||
---
|
||
|
||
## Live Photo 转换管线解读
|
||
|
||
1. **解析原始 HEIC**:读取 `ftyp`、`meta`、`iloc` 等盒;通过 handler 自动识别三星文件并查找 `mpvd` 盒。
|
||
2. **重建主图像**:借助 `pillow-heif` 还原三星的网格化主图,写入临时平面 HEIC(`mif1` brand)。
|
||
3. **提取并存储 MOV**:抽取 `mpvd` 中的嵌入视频,写成独立 MOV,并用 `exiftool` 写入 `ContentIdentifier`(如未安装可跳过)。
|
||
4. **修正 item ID 与引用**:三星会将 item ID 左移 16 位;工具会同步修复 `iinf`、`ipma`、`iref`。
|
||
5. **补齐 Apple 元数据**:设置苹果兼容的 `ftyp` 品牌,写入新的 `ContentIdentifier`、`PhotoIdentifier`,填充 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`,实现 `matches`、`extract_motion_video`、`prepare_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](README.en.md);若你想贡献改进英文文档,也欢迎提交 PR。
|
||
|
||
---
|
||
|
||
## 开发提示
|
||
|
||
- 项目使用 `ruff` / `black` 风格指南,可根据需要自行配置。
|
||
- 在修改 HEIC 结构后务必重新运行转换脚本,确保 `HEICBuilder` 输出的文件能被 `pillow-heif` 与 `exiftool` 读取。
|
||
- 欢迎围绕 HEIC 解析、Motion Photo 适配提交 issue 或 PR,特别是其它安卓厂商的兼容性案例。
|