I am making an app that takes pictures with AVFoundation and I want to save them to a custom album that I can then query and show in my app. (I\'d prefer to not have them in
Answer in Objective-C and cleaned up a bit.
__block PHFetchResult *photosAsset;
__block PHAssetCollection *collection;
__block PHObjectPlaceholder *placeholder;
// Find the album
PHFetchOptions *fetchOptions = [[PHFetchOptions alloc] init];
fetchOptions.predicate = [NSPredicate predicateWithFormat:@"title = %@", @"YOUR_ALBUM_TITLE"];
collection = [PHAssetCollection fetchAssetCollectionsWithType:PHAssetCollectionTypeAlbum
subtype:PHAssetCollectionSubtypeAny
options:fetchOptions].firstObject;
// Create the album
if (!collection)
{
[[PHPhotoLibrary sharedPhotoLibrary] performChanges:^{
PHAssetCollectionChangeRequest *createAlbum = [PHAssetCollectionChangeRequest creationRequestForAssetCollectionWithTitle:@"YOUR_ALBUM_TITLE"];
placeholder = [createAlbum placeholderForCreatedAssetCollection];
} completionHandler:^(BOOL success, NSError *error) {
if (success)
{
PHFetchResult *collectionFetchResult = [PHAssetCollection fetchAssetCollectionsWithLocalIdentifiers:@[placeholder.localIdentifier]
options:nil];
collection = collectionFetchResult.firstObject;
}
}];
}
// Save to the album
[[PHPhotoLibrary sharedPhotoLibrary] performChanges:^{
PHAssetChangeRequest *assetRequest = [PHAssetChangeRequest creationRequestForAssetFromImage:[UIImage imageWithData:imageData]];
placeholder = [assetRequest placeholderForCreatedAsset];
photosAsset = [PHAsset fetchAssetsInAssetCollection:collection options:nil];
PHAssetCollectionChangeRequest *albumChangeRequest = [PHAssetCollectionChangeRequest changeRequestForAssetCollection:collection
assets:photosAsset];
[albumChangeRequest addAssets:@[placeholder]];
} completionHandler:^(BOOL success, NSError *error) {
if (success)
{
NSString *UUID = [placeholder.localIdentifier substringToIndex:36];
self.photo.assetURL = [NSString stringWithFormat:@"assets-library://asset/asset.PNG?id=%@&ext=JPG", UUID];
[self savePhoto];
}
else
{
NSLog(@"%@", error);
}
}];
The bit at the end with the UUID was something I found on another StackOverflow thread for creating a replacement for AssetURL property from an ALAsset.
Note: See chris' comment below for more complete answer.
I like to reuse the code I write so I decided to create an extension for PHPhotoLibrary where it is possible to use it like:
PHPhotoLibrary.saveImage(photo, albumName: "Trip") { asset in
guard let asset = asset else {
assert(false, "Asset is nil")
return
}
PHPhotoLibrary.loadThumbnailFromAsset(asset) { thumbnail in
print(thumbnail)
}
}
Here is the code: https://gist.github.com/ricardopereira/636ccd0a3c8a327c43d42e7cbca4d041
I improved on @ricardopereira and @ColossalChris code. Added video to the extension, and added another extension on top of PHAsset to get rid of the compilation errors. Works in Swift 2.1.
Sample usage:
#import "Yourtargetname-Swift.h"//important!
NSURL *videoURL = [[NSURL alloc] initFileURLWithPath:PATH_TO_VIDEO];
[PHPhotoLibrary saveVideo:videoURL albumName:@"my album" completion:^(PHAsset * asset) {
NSLog(@"success");
NSLog(@"asset%lu",(unsigned long)asset.pixelWidth);
}];
Import both swift files: https://github.com/kv2/PHPhotoLibrary-PhotoAsset.swift
It is usable in objective-c as long as you import the swift header for your target (see the ViewController.m file).
As updated for Swift 2.1+ and for Video in case you are trying to do that and ended up here. Compare to the other answers for slight differences (such as using for Images rather than Video)
var photosAsset: PHFetchResult!
var collection: PHAssetCollection!
var assetCollectionPlaceholder: PHObjectPlaceholder!
//Make sure we have custom album for this app if haven't already
let fetchOptions = PHFetchOptions()
fetchOptions.predicate = NSPredicate(format: "title = %@", "MY_APP_ALBUM_NAME")
self.collection = PHAssetCollection.fetchAssetCollectionsWithType(.Album, subtype: .Any, options: fetchOptions).firstObject as! PHAssetCollection
//if we don't have a special album for this app yet then make one
if self.collection == nil {
PHPhotoLibrary.sharedPhotoLibrary().performChanges({
let createAlbumRequest : PHAssetCollectionChangeRequest = PHAssetCollectionChangeRequest.creationRequestForAssetCollectionWithTitle("MY_APP_ALBUM_NAME")
self.assetCollectionPlaceholder = createAlbumRequest.placeholderForCreatedAssetCollection
}, completionHandler: { success, error in
if success {
let collectionFetchResult = PHAssetCollection.fetchAssetCollectionsWithLocalIdentifiers([self.assetCollectionPlaceholder.localIdentifier], options: nil)
print(collectionFetchResult)
self.collection = collectionFetchResult.firstObject as! PHAssetCollection
}
})
}
//save the video to Photos
PHPhotoLibrary.sharedPhotoLibrary().performChanges({
let assetRequest = PHAssetChangeRequest.creationRequestForAssetFromVideoAtFileURL(self.VIDEO_URL_FOR_VIDEO_YOU_MADE!)
let assetPlaceholder = assetRequest!.placeholderForCreatedAsset
self.photosAsset = PHAsset.fetchAssetsInAssetCollection(self.collection, options: nil)
let albumChangeRequest = PHAssetCollectionChangeRequest(forAssetCollection: self.collection, assets: self.photosAsset)
albumChangeRequest!.addAssets([assetPlaceholder!])
}, completionHandler: { success, error in
if success {
print("added video to album")
}else if error != nil{
print("handle error since couldn't save video")
}
}
})
This is how I do:
At the top:
import Photos
var image: UIImage!
var assetCollection: PHAssetCollection!
var albumFound : Bool = false
var photosAsset: PHFetchResult!
var assetThumbnailSize:CGSize!
var collection: PHAssetCollection!
var assetCollectionPlaceholder: PHObjectPlaceholder!
Creating the album:
func createAlbum() {
//Get PHFetch Options
let fetchOptions = PHFetchOptions()
fetchOptions.predicate = NSPredicate(format: "title = %@", "camcam")
let collection : PHFetchResult = PHAssetCollection.fetchAssetCollectionsWithType(.Album, subtype: .Any, options: fetchOptions)
//Check return value - If found, then get the first album out
if let _: AnyObject = collection.firstObject {
self.albumFound = true
assetCollection = collection.firstObject as! PHAssetCollection
} else {
//If not found - Then create a new album
PHPhotoLibrary.sharedPhotoLibrary().performChanges({
let createAlbumRequest : PHAssetCollectionChangeRequest = PHAssetCollectionChangeRequest.creationRequestForAssetCollectionWithTitle("camcam")
self.assetCollectionPlaceholder = createAlbumRequest.placeholderForCreatedAssetCollection
}, completionHandler: { success, error in
self.albumFound = success
if (success) {
let collectionFetchResult = PHAssetCollection.fetchAssetCollectionsWithLocalIdentifiers([self.assetCollectionPlaceholder.localIdentifier], options: nil)
print(collectionFetchResult)
self.assetCollection = collectionFetchResult.firstObject as! PHAssetCollection
}
})
}
}
When saving the photo:
func saveImage(){
PHPhotoLibrary.sharedPhotoLibrary().performChanges({
let assetRequest = PHAssetChangeRequest.creationRequestForAssetFromImage(self.image)
let assetPlaceholder = assetRequest.placeholderForCreatedAsset
let albumChangeRequest = PHAssetCollectionChangeRequest(forAssetCollection: self.assetCollection, assets: self.photosAsset)
albumChangeRequest!.addAssets([assetPlaceholder!])
}, completionHandler: { success, error in
print("added image to album")
print(error)
self.showImages()
})
}
Showing the images from that album:
func showImages() {
//This will fetch all the assets in the collection
let assets : PHFetchResult = PHAsset.fetchAssetsInAssetCollection(assetCollection, options: nil)
print(assets)
let imageManager = PHCachingImageManager()
//Enumerating objects to get a chached image - This is to save loading time
assets.enumerateObjectsUsingBlock{(object: AnyObject!,
count: Int,
stop: UnsafeMutablePointer<ObjCBool>) in
if object is PHAsset {
let asset = object as! PHAsset
print(asset)
let imageSize = CGSize(width: asset.pixelWidth, height: asset.pixelHeight)
let options = PHImageRequestOptions()
options.deliveryMode = .FastFormat
imageManager.requestImageForAsset(asset, targetSize: imageSize, contentMode: .AspectFill, options: options, resultHandler: {(image: UIImage?,
info: [NSObject : AnyObject]?) in
print(info)
print(image)
})
}
}