Saving Already Created Live Photos
You can create a LivePhoto from separate elements from a LivePhoto by using PHLivePhoto.requestLivePhotoWithResourceFileURLs
, you will then be able to save it to the library.
func makeLivePhotoFromItems(imageURL: NSURL, videoURL: NSURL, previewImage: UIImage, completion: (livePhoto: PHLivePhoto) -> Void) {
PHLivePhoto.requestLivePhotoWithResourceFileURLs([imageURL, videoURL], placeholderImage: previewImage, targetSize: CGSizeZero, contentMode: PHImageContentMode.AspectFit) {
(livePhoto, infoDict) -> Void in
if let lp = livePhoto {
completion(livePhoto: lp)
}
}
}
makeLivePhotoFromItems(imgURL, videoURL: movURL, previewImage: prevImg) { (livePhoto) -> Void in
// "livePhoto" is your PHLivePhoto object, save it/use it here
}
You will need the JPEG file URL, the MOV file URL, and a "preview" image (which is usually just the JPEG or a lighter version of it).
Full example working in a Playground here.
Live Photo saving automatically
Here are a few things to get you unstuck here.
Issue 1: How do I get my save button to call exportLivePhoto():
Your IBAction for your button should look something like this:
@IBAction func savePhotoTapped(_ sender: Any) {
print("in savePhotoTapped | start"
exportLivePhoto()
}
Make sure this action is connected to your button that you created in your storyboard.
Issue 2: Multiple saves:
These lines look like they save a jpg and mov version of the image. If you only want one comment out the other.
try FileManager.default.removeItem(atPath: output + "/IMG.JPG")
try FileManager.default.removeItem(atPath: output + "/IMG.MOV")
Also try cleaning up your code so its more easily readable in the future.
Working with Live Photos in Playground
It's possible to make and view a PHLivePhoto in the Playground from the elements of an actual Live Photo.
In OS X's Photos
app, select a Live Photo and go to menu
File > Export > Export original...
It will create a .JPG
and a .mov
.
Drop these two files in the Resources
folder of the Playground (menu View > Navigators > Show Project Navigator).
Get the URLs for these two files with NSBundle
(in my example the files are "IMG_0001.JPG" and "IMG_0001.mov"):
let imgURL = NSBundle.mainBundle().URLForResource("IMG_0001", withExtension: "JPG")!
let movURL = NSBundle.mainBundle().URLForResource("IMG_0001", withExtension: "mov")!
And create an actual image, we will need it for the Live Photo preview image:
let prevImg = UIImage(named: "IMG_0001.JPG")!
Import the necessary frameworks:
import Photos
import PhotosUI
import XCPlayground
And set the Playground in asynchronous mode:
XCPlaygroundPage.currentPage.needsIndefiniteExecution = true
Now we're going to use PHLivePhoto
's requestLivePhotoWithResourceFileURLs
method to create a PHLivePhoto from our elements:
func makeLivePhotoFromItems(imageURL: NSURL, videoURL: NSURL, previewImage: UIImage, completion: (livePhoto: PHLivePhoto) -> Void) {
PHLivePhoto.requestLivePhotoWithResourceFileURLs([imageURL, videoURL], placeholderImage: previewImage, targetSize: CGSizeZero, contentMode: PHImageContentMode.AspectFit) {
(livePhoto, infoDict) -> Void in
// for debugging: print(infoDict)
if let lp = livePhoto {
completion(livePhoto: lp)
}
}
}
Then we call like this:
makeLivePhotoFromItems(imgURL, videoURL: movURL, previewImage: prevImg) { (livePhoto) -> Void in
// "livePhoto" is your PHLivePhoto object
}
For example, let's say you want the Playground to make a live view:
makeLivePhotoFromItems(imgURL, videoURL: movURL, previewImage: prevImg) { (livePhoto) -> Void in
let rect = CGRect(x: 0, y: 0, width: 2048, height: 1536)
let livePhotoView = PHLivePhotoView(frame: rect)
livePhotoView.livePhoto = livePhoto
XCPlaygroundPage.currentPage.liveView = livePhotoView
livePhotoView.startPlaybackWithStyle(PHLivePhotoViewPlaybackStyle.Full)
}
Note that since there's no way to interact with the live view to start the playback of the Live Photo we have to do it ourselves with PHLivePhotoView
's startPlaybackWithStyle
method.
You can force the live view to appear in the Playground by showing the Assistant Editor in menu
View > Assistant Editor > Show Assistant Editor
Note: it can take some time for the Playground to create the PHLivePhoto and initiate the live view.
With Xcode 7.3b+ we can finally have some UI interaction in Playgrounds.
I've made an adaptation of this answer with a simple view and touchesBegan, just click the LivePhoto when the console says so:
import UIKit
import XCPlayground
import Photos
import PhotosUI
class PLView: UIView {
let image: UIImage
let imageURL: NSURL
let videoURL: NSURL
let liveView: PHLivePhotoView
init(image: UIImage, imageURL: NSURL, videoURL: NSURL) {
self.image = image
self.imageURL = imageURL
self.videoURL = videoURL
let rect = CGRect(x: 0, y: 0, width: image.size.width, height: image.size.height)
self.liveView = PHLivePhotoView(frame: rect)
super.init(frame: rect)
self.addSubview(self.liveView)
}
func prepareLivePhoto() {
makeLivePhotoFromItems { (livePhoto) in
self.liveView.livePhoto = livePhoto
print("\nReady! Click on the LivePhoto in the Assistant Editor panel!\n")
}
}
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
print("\nClicked! Wait for it...\n")
self.liveView.startPlaybackWithStyle(.Full)
}
private func makeLivePhotoFromItems(completion: (PHLivePhoto) -> Void) {
PHLivePhoto.requestLivePhotoWithResourceFileURLs([imageURL, videoURL], placeholderImage: image, targetSize: CGSizeZero, contentMode: .AspectFit) {
(livePhoto, infoDict) -> Void in
// This "canceled" condition is just to avoid redundant passes in the Playground preview panel.
if let canceled = infoDict[PHLivePhotoInfoCancelledKey] as? Int where canceled == 0 {
if let livePhoto = livePhoto {
completion(livePhoto)
}
}
}
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
XCPlaygroundPage.currentPage.needsIndefiniteExecution = true
let plview = PLView(image: UIImage(named: "IMG_0001.JPG")!,
imageURL: NSBundle.mainBundle().URLForResource("IMG_0001", withExtension: "JPG")!,
videoURL: NSBundle.mainBundle().URLForResource("IMG_0001", withExtension: "mov")!)
XCPlaygroundPage.currentPage.liveView = plview
plview.prepareLivePhoto()
The same example for Swift 3.0.2 (Xcode 8.2.1):
import UIKit
import PlaygroundSupport
import Photos
import PhotosUI
class PLView: UIView {
let image: UIImage
let imageURL: URL
let videoURL: URL
let liveView: PHLivePhotoView
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
init(image: UIImage, imageURL: URL, videoURL: URL) {
self.image = image
self.imageURL = imageURL
self.videoURL = videoURL
let rect = CGRect(x: 0, y: 0, width: 300, height: 400)
self.liveView = PHLivePhotoView(frame: rect)
super.init(frame: rect)
self.addSubview(self.liveView)
}
func prepareLivePhoto() {
makeLivePhotoFromItems { (livePhoto) in
self.liveView.livePhoto = livePhoto
print("\nReady! Click on the LivePhoto in the Assistant Editor panel!\n")
}
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
print("\nClicked! Wait for it...\n")
self.liveView.startPlayback(with: .full)
}
private func makeLivePhotoFromItems(completion: @escaping (PHLivePhoto) -> Void) {
PHLivePhoto.request(withResourceFileURLs: [imageURL, videoURL], placeholderImage: image, targetSize: CGSize.zero, contentMode: .aspectFit) {
(livePhoto, infoDict) -> Void in
if let canceled = infoDict[PHLivePhotoInfoCancelledKey] as? NSNumber,
canceled == 0,
let livePhoto = livePhoto
{
completion(livePhoto)
}
}
}
}
let plview = PLView(image: UIImage(named: "IMG_0001.JPG")!,
imageURL: Bundle.main.url(forResource: "IMG_0001", withExtension: "JPG")!,
videoURL: Bundle.main.url(forResource: "IMG_0001", withExtension: "mov")!)
PlaygroundPage.current.needsIndefiniteExecution = true
PlaygroundPage.current.liveView = plview
plview.prepareLivePhoto()
Integrating Live Photos in my app
There is really no simple out-of-the-box API from Apple to integrate Live Photo in iOS apps.
That being said, there's an interesting article that has been going around lately which will explain what Live Photo is under the hood and how you can use it.
Extract video portion from Live Photo
Use the PHAssetResourceManager
to get the video file from the PHAssetResource
.
PHAssetResourceManager.defaultManager().writeDataForAssetResource(assetRes,
toFile: fileURL, options: nil, completionHandler:
{
// Video file has been written to path specified via fileURL
}
NOTE: The Live Photo specific APIs were introduced in iOS 9.1
Related Topics
Convenience Initialization of Uinavigationcontroller Subclass Makes Subclass Constant Init Twice
(Swift Spritekit) Rotate Sprite in the Direction of Touch
Save Image with the Correct Orientation - Swift & Core Image
Skvideonode Only on a Small Part of Scnsphere
iOS Keyboard Active But Invisible When Uisearchbar Is Tapped
Cocoapods, Add Dependencies to All Targets in a Generic Way
How to Use Key-Value Coding in Swfit 4.0
How to Change Button Text Size in iOS 8 Swift
How to Update a Swiftui View That Was Embedded into Uikit
Core Data Transient Values with Swift
Avmutablevideocomposition Output Video Shrinked
Return in Function Without Return Value in Swift
How to Auto Call an @Ibaction Function
How to Make Synchronous Operation with Asynchronous Callback
In iOS Avplayer, Addperiodictimeobserverforinterval Seems to Be Missing