Files
to-live-photo/Sources/LivePhotoCore/MakerNotesPatcher.swift
empty 299415a530 feat: 初始化 Live Photo 项目结构
- 添加 PRD、技术规范、交互规范文档 (V0.2)
- 创建 Swift Package 和 Xcode 项目
- 实现 LivePhotoCore 基础模块
- 添加 HEIC MakerNote 元数据写入功能
- 创建项目结构文档和任务清单
- 添加 .gitignore 忽略规则
2025-12-14 16:21:20 +08:00

84 lines
5.2 KiB
Swift
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import Foundation
/// HEIC Apple MakerNotes LivePhotoVideoIndex
/// CGImageDestination Int64 MakerNotes
/// 使
public struct MakerNotesPatcher {
// MARK: - iPhone MakerNotes
/// ContentIdentifier MakerNotes 36 ASCII UUID + null
private static let contentIdentifierOffset = 0x580 // 1408
private static let contentIdentifierLength = 36
/// LivePhotoVideoIndex MakerNotes 8 Big-Endian Int64
private static let livePhotoVideoIndexOffset = 0x5a6 // 1446
private static let livePhotoVideoIndexLength = 8
/// iPhone MakerNotes iPhone 13 Pro Max Live Photo
/// Apple MakerNotes ContentIdentifier LivePhotoVideoIndex
private static let makerNotesTemplate: Data = {
// Base64 MakerNotes
let base64 = """
QXBwbGUgaU9TAAABTU0APQABAAkAAAABAAAAEAACAAcAAAIAAAAC8AADAAcAAABoAAAE8AAEAAkA\
AAABAAAAAQAFAAkAAAABAAAAqQAGAAkAAAABAAAApQAHAAkAAAABAAAAAQAIAAoAAAADAAAFWAAM\
AAoAAAACAAAFcAANAAkAAAABAAAAFwAOAAkAAAABAAAABAAQAAkAAAABAAAAAQARAAIAAAAlAAAF\
gAAUAAkAAAABAAAACgAXABAAAAABAAAFpgAZAAkAAAABAAAAAgAaAAIAAAAGAAAFrgAfAAkAAAAB\
AAAAAAAgAAIAAAAlAAAFtAAhAAoAAAABAAAF2gAjAAkAAAACAAAF4gAlABAAAAABAAAF6gAmAAkA\
AAABAAAAAwAnAAoAAAABAAAF8gAoAAkAAAABAAAAAQArAAIAAAAlAAAF+gAtAAkAAAABAAATXAAu\
AAkAAAABAAAAAQAvAAkAAAABAAAAMAAwAAoAAAABAAAGIAAzAAkAAAABAAAQAAA0AAkAAAABAAAA\
BAA1AAkAAAABAAAAAwA2AAkAAAABAADnJAA3AAkAAAABAAAABAA4AAkAAAABAAACPgA5AAkAAAAB\
AAAAAAA6AAkAAAABAAAAAAA7AAkAAAABAAAAAAA8AAkAAAABAAAABAA9AAkAAAABAAAAAAA/AAkA\
AAABAAAAOwBAAAcAAABQAAAGKABBAAkAAAABAAAAAABCAAkAAAABAAAAAABDAAkAAAABAAAAAABE\
AAkAAAABAAAAAABFAAkAAAABAAAAAABGAAkAAAABAAAAAABIAAkAAAABAAACPgBJAAkAAAABAAAA\
AABKAAkAAAABAAAAAgBNAAoAAAABAAAGeABOAAcAAAB5AAAGgABPAAcAAAArAAAG+gBSAAkAAAAB\
AAAAAQBTAAkAAAABAAAAAQBVAAkAAAABAAAAAQBYAAkAAAABAAAHAwBgAAkAAAABAAASAABhAAkA\
AAABAAAAGgAAAAC9AtMCxAKWAlsCIALqAbwBkgFrAUYBJQEIAfEA3QDMAAMDMwNAA/QCmQJWAg0C\
1QGoAX4BUwEtAQ8B9QDhAM0ALANqA2oDTAPrAnUCKALpAb4BhgFWATABEAH0AN4AyQA9A7oDwgNP\
A7gCXAIYAugBqwF2AUwBJgEGAeoA0gC+ANECrwPSAxIDZAIVAt4BqwF8AVABKQEHAekA0AC6AKgA\
zwFCAnYCBAK/AZYBcwFQAS8BDQHvANQAvQCpAJgAigDUAP8AGgEVARoB5QC6AMUAsACsAJkAggBy\
AGQAXABTAGAAaABqAGYAXABMAEcARwBCAEEAPgAvACQAJAAlACoARgBIAEcARAA/ADcAMwAvACoA\
KAAnACEAHQAfAB8AIAAxADIAMQAwAC4AKwAnACcAJQAfABwAGgAXABkAEwAUACkAKgAmACQAIgAg\
ACEAIgAgAB4AHAAZABgAFAAXABUAIgAcABoAGwAaABcAHAAdABkAGAAYABgAFwAaABgAGAAaABsA\
GgAYABUAEwAWABcAEwAWABcAFQAVABYAEwAUABoAFwAWABMAEgATABAADwATABMAEgANAA8ADwAP\
AAwAEwAVABIAEwANABUAEwATABIADAAPAAsAEAASAA8ADgARABEADwAMAAwADwAWABMAEgASABQA\
DQAPAAoADAAOAGJwbGlzdDAw1AECAwQFBgcIVWZsYWdzVXZhbHVlWXRpbWVzY2FsZVVlcG9jaBAB\
EwABVEUBR7fxEjuaygAQAAgRFx0nLS84PQAAAAAAAAEBAAAAAAAAAAkAAAAAAAAAAAAAAAAAAAA/\
///J3gAANk3//8R4AAe+////5bUAAVy+AAAAOwAAAQAAAAAnAAABAAAAAAAAAAAAAAAAAAAAALtA\
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABI\
RUlDAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAbwBwAGwAaQBzAHQAMAAwANQBAgMEBQYHCFEzUTFR\
MlEwEAQiAAAAACQ/AAAAEAEIERMVFxkbICUAAAAAAAABAQAAAAAAAAAJAAAAAAAAAAAAAAAAAAAA\
JwAC8/UAABV+YnBsaXN0MDDSAQIDSFExUTIQA6IFCtIGBwgJUzIuMVMyLjIjQEsf2IAAAACJQAAA\
AAAAAADSBgcLDCM/4hqAAAAAAKNAVMAAAAAAAAgNDxETFhsfIywlOkMAAAAAAAABAQAAAAAAAAAL\
AAAAAAAAAAAAAAAAAAAAQQAAAAA=
"""
return Data(base64Encoded: base64.replacingOccurrences(of: "\\\n", with: "").replacingOccurrences(of: "\n", with: ""))!
}()
/// MakerNotes
/// - Parameters:
/// - contentIdentifier: Live Photo Content Identifier (UUID )
/// - livePhotoVideoIndex: Live Photo Video Index ( Float32 bitPattern)
/// - Returns: MakerNotes
public static func createMakerNotes(
contentIdentifier: String,
livePhotoVideoIndex: Int64
) -> Data {
var data = makerNotesTemplate
// ContentIdentifier
let uuidData = contentIdentifier.data(using: .ascii)!
let paddedUUID = uuidData + Data(repeating: 0, count: max(0, contentIdentifierLength - uuidData.count))
data.replaceSubrange(contentIdentifierOffset..<(contentIdentifierOffset + contentIdentifierLength), with: paddedUUID.prefix(contentIdentifierLength))
// LivePhotoVideoIndex (Big-Endian)
var bigEndianValue = UInt64(bitPattern: livePhotoVideoIndex).bigEndian
let indexData = Data(bytes: &bigEndianValue, count: livePhotoVideoIndexLength)
data.replaceSubrange(livePhotoVideoIndexOffset..<(livePhotoVideoIndexOffset + livePhotoVideoIndexLength), with: indexData)
return data
}
}