Save Photos to Custom Album in iPhones Photo Library
I'm trying to create a custom album in the Photo Library of an iPhone and then save photos that I've taken with the camera, or chosen from the phones Camera Roll to that custom album. I can successfully create the album but the photos are not getting saved there, instead they are getting saved to the simulators Saved Photos album... I'm not sure how to tell UIImageWriteToSavedPhotosAlbum
to save to the new album I've just created using addAssetsGroupAlbumWithName
...
Here is the code I have so far - I've snipped out a few sections to keep my code example short...
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info
{
NSString *mediaType = [info objectForKey:UIImagePickerControllerMediaType];
if([mediaType isEqualToString:(__bridge NSString *)kUTTypeImage])
{
// pull GPS information from photos metadata using ALAssetsLibrary
void (^ALAssetsLibraryAssetForURLResultBlock)(ALAsset *) = ^(ALAsset *asset)
{
// code snipped out
};
NSURL *assetURL = [info objectForKey:UIImagePickerControllerReferenceURL];
ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init];
[library assetForURL:assetURL
resultBlock:ALAssetsLibraryAssetForURLResultBlock
failureBlock:^(NSError *error)
{
// code snipped out
}];
// getimage from imagePicker and resize it to the max size of the iPhone screen
UIImage *originalImage = [info objectForKey:UIImagePickerControllerOriginalImage];
UIImage *resizedImage = [util_ createThumbnailForImage:originalImage thumbnailSize:[util_ determineIPhoneScreenSize]];
NSData *imageData = UIImagePNGRepresentation(resizedImage);
// code snipped out
// code snipped out
// code snipped out
// code snipped out
// code snipped out
// code snipped out
// create a new album called "My Apps Photos"
[library addAssetsGroupAlbumWithName:@"My Apps Photos"
resultBlock:^(ALAssetsGroup *group)
{
NSLog(@"in addAssetsGroupAlbumWithName resultBlock");
// save file to album
UIImageWriteToSavedPhotosAlbum(resizedImage, self, nil, nil);
}
failureBlock:^(NSError *error)
{
NSLog(@"in addAssetsGroupAlbumWithName failureBlock");
}
];
}
}
So... Like I said, it creates the new album but does not save the photo there. How do I tell it to save into the new album? Perhaps I sound not use UIImageWriteToSavedPhotosAlbum
??
Note: I'm using Xcode 4.3.2, IOS 5.1, and ARC
Solution 1:
If you are using iOS6, Fernando's answer will not work, because the saveImage selector is no longer available.
The process is pretty confusing, and I have not seen any clear answers posted, so here is the method I've used to solve this in iOS6.
You will need to use a combination of the following:
Create the Album:
[self.library addAssetsGroupAlbumWithName:albumName
resultBlock:^(ALAssetsGroup *group) {
NSLog(@"added album:%@", albumName);
}
failureBlock:^(NSError *error) {
NSLog(@"error adding album");
}];
Find the Album:
__block ALAssetsGroup* groupToAddTo;
[self.library enumerateGroupsWithTypes:ALAssetsGroupAlbum
usingBlock:^(ALAssetsGroup *group, BOOL *stop) {
if ([[group valueForProperty:ALAssetsGroupPropertyName] isEqualToString:albumName]) {
NSLog(@"found album %@", albumName);
groupToAddTo = group;
}
}
failureBlock:^(NSError* error) {
NSLog(@"failed to enumerate albums:\nError: %@", [error localizedDescription]);
}];
Save the Image to Asset Library, and put it into the album:
CGImageRef img = [image CGImage];
[self.library writeImageToSavedPhotosAlbum:img
metadata:[info objectForKey:UIImagePickerControllerMediaMetadata]
completionBlock:^(NSURL* assetURL, NSError* error) {
if (error.code == 0) {
NSLog(@"saved image completed:\nurl: %@", assetURL);
// try to get the asset
[self.library assetForURL:assetURL
resultBlock:^(ALAsset *asset) {
// assign the photo to the album
[groupToAddTo addAsset:asset];
NSLog(@"Added %@ to %@", [[asset defaultRepresentation] filename], albumName);
}
failureBlock:^(NSError* error) {
NSLog(@"failed to retrieve image asset:\nError: %@ ", [error localizedDescription]);
}];
}
else {
NSLog(@"saved image failed.\nerror code %i\n%@", error.code, [error localizedDescription]);
}
}];
Solution 2:
Fernando's answer worked for me in iOS 7.
Steps :
1) Download the ALAssetsLibrary+CustomPhotoAlbum code from here: http://www.touch-code-magazine.com/wp-content/uploads/2011/11/ALAssetsLibrary_CustomPhotoAlbum.zip?a071b6 and copy the 2 files for the category inside your Xcode project.
2)In your header file,add the following lines
#import <AssetsLibrary/AssetsLibrary.h>
#import "ALAssetsLibrary+CustomPhotoAlbum.h"
@property (strong, atomic) ALAssetsLibrary* library;
3) In your implementation file,add the following lines
@synthesize library=_library;
EDIT: 4) initialise the asset library instance, preferably in "viewDidLoad" method, otherwise the saveImage method below won't execute. (CONFIRMED):
[I am resubmitting the suggested edit because someone with non-iphone skills rejected the previous submission. This is undoubtedly a great answer by @santhu & Fernando and helped me a lot, however, the initialisation piece of code was missing so it took me a bit of time to figure out why the code didn't work. Hence, I would appreciate if a moderator with iPhone development skillset reviews the edit.]
_library = [[ALAssetsLibrary alloc] init];
5) Add this in the method where you wish to save
//Add this in the method where you wish to save
[self.library saveImage:(UIImage *) toAlbum:(NSString *) withCompletionBlock:^(NSError *error) {
if (error!=nil) {
NSLog(@"Big error: %@", [error description]);
}
}];
Solution 3:
For swift users:- I made function to do the same thing.
declare closure outsize class definition (above class definition)
typealias CompletionHandler = (success:Bool!) -> Void
declare library variable inside class
var library:ALAssetsLibrary?;
initialize variable in viewDidLoad
library = ALAssetsLibrary();
method to add Image to Particular Album
func addImage(image:UIImage, metaData:NSDictionary, toAlbum albumName:String, handler:CompletionHandler){
library?.addAssetsGroupAlbumWithName(albumName, resultBlock: {(group:ALAssetsGroup!) -> Void in
print("\nAlbum Created:= \(albumName)");
/*-- Find Group --*/
var groupToAddTo:ALAssetsGroup?;
self.library?.enumerateGroupsWithTypes(ALAssetsGroupType(ALAssetsGroupAlbum),
usingBlock: { (group:ALAssetsGroup?, stop:UnsafeMutablePointer<ObjCBool>) -> Void in
if(group != nil){
if group!.valueForProperty(ALAssetsGroupPropertyName) as String == albumName{
groupToAddTo = group;
print("\nGroup Found \(group!.valueForProperty(ALAssetsGroupPropertyName))\n");
self.library?.writeImageToSavedPhotosAlbum(image.CGImage, metadata:metaData, completionBlock: {(assetURL:NSURL!,error:NSError!) -> Void in
if(error == nil){
self.library?.assetForURL(assetURL,
resultBlock: { (asset:ALAsset!) -> Void in
var yes:Bool? = groupToAddTo?.addAsset(asset);
if (yes == true){
handler(success: true);
}
},
failureBlock: { (error2:NSError!) -> Void in
print("Failed to add asset");
handler(success: false);
});
}
});
}
} /*Group Is Not nil*/
},
failureBlock: { (error:NSError!) -> Void in
print("Failed to find group");
handler(success: false);
});
}, failureBlock: { (error:NSError!) -> Void in
print("Failed to create \(error)");
handler(success: false);
});
}
call this method as :--
func imagePickerController(picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [NSObject : AnyObject]){
var image:UIImage = info[UIImagePickerControllerOriginalImage] as UIImage;
var metadata:NSDictionary = info[UIImagePickerControllerMediaMetadata] as NSDictionary;
self.addImage(image, metaData: metadata, toAlbum: "SwiftAlbum") { (success) -> Void in
print("Image Added : \(success)");
}
picker.dismissViewControllerAnimated(true, completion: nil);
}
Solution 4:
The code from @Scott Allen was close but would not save the image for me the first time. So if I did not already have the album created, the image would not save. My solution was to move this snippet that creates the album to the app delegate didFinishLaunchingWithOptions:
NSString *albumName=@"album name";
ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init];
[library addAssetsGroupAlbumWithName:albumName
resultBlock:^(ALAssetsGroup *group) {
NSLog(@"added album:%@", albumName);
}
failureBlock:^(NSError *error) {
NSLog(@"error adding album");
}];