Skip to content

Instantly share code, notes, and snippets.

@whexy
Last active August 13, 2023 21:08
Show Gist options
  • Save whexy/0e50ba51e8c6f71a321fcd514032425f to your computer and use it in GitHub Desktop.
Save whexy/0e50ba51e8c6f71a321fcd514032425f to your computer and use it in GitHub Desktop.
Read Apple Maker Note Asset Identifier from a HEIC file and a MOV file (live photo)
import Foundation
import ImageIO
func modifyAndSaveHEICPhoto(atPath path: String, assetIdentifier: String) {
let imageSource = CGImageSourceCreateWithURL(URL(fileURLWithPath: path) as CFURL, nil)
let imageProperties = CGImageSourceCopyPropertiesAtIndex(imageSource!, 0, nil) as? [CFString: Any]
var modifiedProperties = imageProperties!
var appleMakerDict = modifiedProperties[kCGImagePropertyMakerAppleDictionary] as? [CFString: Any]
appleMakerDict?["17" as CFString] = assetIdentifier
modifiedProperties[kCGImagePropertyMakerAppleDictionary] = appleMakerDict
let newImageData = NSMutableData()
let destination = CGImageDestinationCreateWithData(newImageData, CGImageSourceGetType(imageSource!)!, 1, nil)!
CGImageDestinationAddImageFromSource(destination, imageSource!, 0, modifiedProperties as CFDictionary)
CGImageDestinationFinalize(destination)
let newFilePath = (path as NSString).deletingPathExtension + "_modified.HEIC"
newImageData.write(toFile: newFilePath, atomically: true)
print("Modified photo saved at: \(newFilePath)")
}
let heicFilePath = CommandLine.arguments[1]
let assetIdentifier = CommandLine.arguments[2]
modifyAndSaveHEICPhoto(atPath: heicFilePath, assetIdentifier: assetIdentifier)
import AVFoundation
import Foundation
func fetchAssetIdentifier(fromURL url: URL) async -> String? {
let asset = AVAsset(url: url)
let metadata = try! await asset.loadMetadata(for: AVMetadataFormat.quickTimeMetadata)
for item in metadata {
let key = item.commonKey?.rawValue
let value = try! await item.load(.value)
if key == "identifier" {
return value as? String
}
}
return nil
}
let movieFilePath = CommandLine.arguments[1]
let movieURL = URL(fileURLWithPath: movieFilePath)
let assetIdentifier = await fetchAssetIdentifier(fromURL: movieURL)
print("Asset Identifier: \(assetIdentifier!)")
import Foundation
import ImageIO
func fetchAssetIdentifier(fromHEICPhotoAtPath path: String) -> String? {
let imageSource = CGImageSourceCreateWithURL(URL(fileURLWithPath: path) as CFURL, nil)
let imageProperties = CGImageSourceCopyPropertiesAtIndex(imageSource!, 0, nil) as? [CFString: Any]
let appleMakerDict = imageProperties?[kCGImagePropertyMakerAppleDictionary] as? [CFString: Any]
for (key, value) in appleMakerDict! {
if key as String == "17" {
return value as? String
}
}
return nil
}
let heicFilePath = CommandLine.arguments[1]
let assetIdentifier = fetchAssetIdentifier(fromHEICPhotoAtPath: heicFilePath)!
print("Asset Identifier: \(assetIdentifier)")
@whexy
Copy link
Author

whexy commented Aug 13, 2023

Usage example:

swift photoId.swift example.HEIC
swift movieId.swift example2.mov
swift modifyPhotoId.swift example.HEIC <another-id>

You can use these three scripts to combine a static photo and a short video into a Apple's Live Photo.

@whexy
Copy link
Author

whexy commented Aug 13, 2023

BTW, check out my blog about how Apple Live Photo works :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment