I've been following this tutorial http://www.touch-code-magazine.com/ios5-saving-photos-in-custom-photo-album-category-for-download/ to save an image to a custom album. This works fine but it's saving to both the camera roll and my custom album.
Looking at the code it seems like this is a necessary step, as after saving the image to the camera roll we have an ALAsset that can be used with the ALAssetsGroup addAsset: method.
Is there a way that I can add an image to a custom album without adding it to the camera roll?
Currently using this code:
-(void)saveImage:(UIImage*)image toAlbum:(NSString*)albumName withCompletionBlock:(SaveImageCompletion)completionBlock
{
//write the image data to the assets library (camera roll)
[self writeImageToSavedPhotosAlbum:image.CGImage orientation:(ALAssetOrientation)image.imageOrientation
completionBlock:^(NSURL* assetURL, NSError* error) {
//error handling
if (error!=nil) {
completionBlock(error);
return;
}
//add the asset to the custom photo album
[self addAssetURL: assetURL
toAlbum:albumName
withCompletionBlock:completionBlock];
}];
}
-(void)addAssetURL:(NSURL*)assetURL toAlbum:(NSString*)albumName withCompletionBlock:(SaveImageCompletion)completionBlock
{
__block BOOL albumWasFound = NO;
//search all photo albums in the library
[self enumerateGroupsWithTypes:ALAssetsGroupAlbum
usingBlock:^(ALAssetsGroup *group, BOOL *stop) {
//compare the names of the albums
if ([albumName compare: [group valueForProperty:ALAssetsGroupPropertyName]]==NSOrderedSame) {
//target album is found
albumWasFound = YES;
//get a hold of the photo's asset instance
[self assetForURL: assetURL
resultBlock:^(ALAsset *asset) {
//add photo to the target album
[group addAsset: asset];
//run the completion block
completionBlock(nil);
} failureBlock: completionBlock];
//album was found, bail out of the method
return;
}
if (group==nil && albumWasFound==NO) {
//photo albums are over, target album does not exist, thus create it
__weak ALAssetsLibrary* weakSelf = self;
//create new assets album
[self addAssetsGroupAlbumWithName:albumName
resultBlock:^(ALAssetsGroup *group) {
//get the photo's instance
[weakSelf assetForURL: assetURL
resultBlock:^(ALAsset *asset) {
//add photo to the newly created album
[group addAsset: asset];
//call the completion block
completionBlock(nil);
} failureBlock: completionBlock];
} failureBlock: completionBlock];
//should be the last iteration anyway, but just in case
return;
}
} failureBlock: completionBlock];
}
Turns out there isn't - images will always be written to the camera roll by default.
Related
I'm trying to save a UIImage to Photo Album. I've tried severl methods the last one is:
-(IBAction)captureLocalImage:(id)sender{
[photoCaptureButton setEnabled:NO];
// Save to assets library
ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init];
[library writeImageToSavedPhotosAlbum: imageView.image.CGImage metadata:nil completionBlock:^(NSURL *assetURL, NSError *error2)
{
// report_memory(#"After writing to library");
if (error2) {
NSLog(#"ERROR: the image failed to be written");
}
else {
NSLog(#"PHOTO SAVED - assetURL: %#", assetURL);
}
runOnMainQueueWithoutDeadlocking(^{
// report_memory(#"Operation completed");
[photoCaptureButton setEnabled:YES];
});
}];
}
imageView is a UIImageView which contain the image I want to save.
On log I got "PHOTO SAVED - assetURL: (null)" and the photo doesn't save to library.
What am I doing wrong?
just use this bellow line for save the image in your photo library
UIImageWriteToSavedPhotosAlbum(imageView.image,nil,nil,nil);
:)
For iOS 11+ needs Privacy - Photo Library Additions Usage Description in info.plist
Add NSPhotoLibraryAddUsageDescription in info.plist
Code:
UIImageWriteToSavedPhotosAlbum(image, nil, nil, nil);
Reference
Check out this sample.. which explains how to save photos using assets library..
you can even use..
UIImageWriteToSavedPhotosAlbum(UIImage *image, id completionTarget, SEL completionSelector, void *contextInfo);
cehck out his link How to save picture to iPhone photo library?
I'm using GPUImage, Apparently there is some kind of problem with the library itself.
The code above is absolutely working. If you want to read more about this issue:
GPUImagePicture with imageFromCurrentlyProcessedOutput doesn't get UIImage
Since iOS 8.1 UIKit framework has the UIImageWriteToSavedPhotosAlbum() function as vishy said.
I use it in this way:
UIImageWriteToSavedPhotosAlbum(myImage, self, "image:didFinishSavingWithError:contextInfo:", nil)
and then
func image(image: UIImage, didFinishSavingWithError error: NSError?, contextInfo:UnsafePointer<Void>) {
// check error, report image has been saved, ...
}
When you take a photo from camera, then you can save image in picker delegate:
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info
{
UIImage *image = [info valueForKey:UIImagePickerControllerEditedImage];
[library writeImageToSavedPhotosAlbum:image.CGImage metadata:[info objectForKey:UIImagePickerControllerMediaMetadata] completionBlock:^(NSURL *assetURL, NSError *error) {
...
}];
[picker dismissViewControllerAnimated:YES completion:nil];
}
I have created "photos album" from my App, using IOS AssetsLibrary.
Reading ALAssetsLibrary,ALAssetsGroup and ALAsset documentations, i have seen methods to "addAsset","addAssetsGroupAlbumWithName".
Is there a way to delete PROGRAMMATICALLY my ALAssetsGroup and ALAsset.
(the property 'editable' suppose to be TRUE because i create this data).
You can only delete the ALAsset which is created by your app with document API [ALAsset setImageData:metadata:completionBlock:] (But I have not found any API to delete a ALAssetGroup).
1). Add an image "photo.jpg" to your project
2). Save an image to asset library:
ALAssetsLibrary *lib = [ALAssetsLibrary new];
UIImage *image = [UIImage imageNamed:#"photo.jpg"];
[lib writeImageToSavedPhotosAlbum:image.CGImage metadata:#{} completionBlock:^(NSURL *assetURL, NSError *error) {
NSLog(#"Write image %# to asset library. (Error %#)", assetURL, error);
}];
3). Go to default gallery, you will find photo.jpg in your "Saved Photos" album.
4). Delete this image from asset library:
ALAssetsLibrary *lib = [ALAssetsLibrary new];
[lib enumerateGroupsWithTypes:ALAssetsGroupSavedPhotos usingBlock:^(ALAssetsGroup *group, BOOL *stop) {
[group enumerateAssetsUsingBlock:^(ALAsset *asset, NSUInteger index, BOOL *stop) {
if(asset.isEditable) {
[asset setImageData:nil metadata:nil completionBlock:^(NSURL *assetURL, NSError *error) {
NSLog(#"Asset url %# should be deleted. (Error %#)", assetURL, error);
}];
}
}];
} failureBlock:^(NSError *error) {
}];
5). Go to default gallery, you will find photo.jpg has already been deleted.
This is not possible using any documented API. Only the photos app can delete Albums. If you want this feature to be added to iOS, I would fill a feature request at https://feedbackassistant.apple.com/.
in ios8 deleting photos might be possible using the Photos Framework
Please check the documentation of Photos Framework
For deleting assets refer to PHAssetChangeRequest
+ (void)deleteAssets:(id<NSFastEnumeration>)assets
where assets is an array of PHAsset objects to be deleted.
For deleting collections refer to PHAssetCollectionChangeRequest
+ (void)deleteAssetCollections:(id<NSFastEnumeration>)assetCollections
https://developer.apple.com/library/prerelease/ios/documentation/Photos/Reference/PHAssetChangeRequest_Class/index.html#//apple_ref/occ/clm/PHAssetChangeRequest/deleteAssets:
As Ted said, this is now possible in iOS 8 using the Photos service. It's pretty clean actually. You need to submit a change request to the photolibrary. Here's an example.
[[PHPhotoLibrary sharedPhotoLibrary] performChanges:^{
[PHAssetChangeRequest deleteAssets:arrayOfPHAssets];
} completionHandler:^(BOOL success, NSError *error) {
NSLog(#"Finished deleting asset. %#", (success ? #"Success." : error));
}];
Make sure you've imported Photos, and gotten authorization from the user. (Which you probably did to show the image already)
PHAssetchangeRequest - deleteAssets
https://developer.apple.com/library/prerelease/ios/documentation/Photos/Reference/PHAssetChangeRequest_Class/index.html#//apple_ref/occ/clm/PHAssetChangeRequest/deleteAssets:
PHPhotoLibrary Class - authorizationStatus
https://developer.apple.com/library/ios/documentation/Photos/Reference/PHPhotoLibrary_Class/#//apple_ref/occ/clm/PHPhotoLibrary/authorizationStatus
evanchin is correct. Further more, if you want to do this in Xamarin.iOS (aka monotouch):
var lib = new ALAssetsLibrary();
lib.Enumerate(ALAssetsGroupType.All, (ALAssetsGroup group, ref bool libStop) =>
{
if (group == null)
{
return;
}
group.Enumerate((ALAsset asset, int index, ref bool groupStop) =>
{
if (asset != null && asset.Editable)
{
asset.SetImageDataAsync(new NSData(IntPtr.Zero), new NSDictionary(IntPtr.Zero));
}
});
}, error => { });
This code will delete all images that your app added to the ALAssetsLibrary.
You may delete any asset in the library using documented API ONLY.
over writing the [ALAsset isEditable] function:
#implementation ALAsset(DELETE)
-(BOOL)isEditable{
return YES;
}
#end
like evanchin said, delete the asset:
ALAssetsLibrary *lib = [ALAssetsLibrary new];
[lib enumerateGroupsWithTypes:ALAssetsGroupSavedPhotos
usingBlock:^(ALAssetsGroup *group, BOOL *stop) {
[group enumerateAssetsUsingBlock:^(ALAsset *asset, NSUInteger index, BOOL *stop) {
if(asset.isEditable) {
[asset setImageData:nil
metadata:nil
completionBlock:^(NSURL *assetURL, NSError *error) {
NSLog(#"Asset url %# should be deleted. (Error %#)", assetURL, error);
}];
}
}];
} failureBlock:^(NSError *error) {
}];
Part of my app has a photo browser, somewhat similar to Apple's Photos app, with an initial view controller to browse photo thumbnails and a detail view that's shown when you tap on a photo.
I'm using ALAssetsLibrary to access photos, and I pass an array of ALAsset URL's to my detail view controller so you can swipe from one photo to the next.
Everything works great, until I receive an ALAssetsLibraryChangedNotification while swiping from one photo to another (in the detail view controller), which often results in a crash:
NOTIFICATION: the asset library changed // my own NSLog for when the
notification occurs
loading assets... // my own NSLog for when I start reloading assets in
the thumbnail browser
Assertion failed: (size == bytesRead), function
-[ALAssetRepresentation _imageData], file /SourceCache/AssetsLibrary/MobileSlideShow-1373.58.1/Sources/ALAssetRepresentation.m,
line 224.
The specific line of code it crashes on, is in calling [currentRep metadata] as shown here:
- (void)someMethod {
NSURL *assetURL = [self.assetURLsArray objectAtIndex:index];
ALAsset *currentAsset;
[self.assetsLibrary assetForURL:assetURL resultBlock:^(ALAsset *asset) {
[self performSelectorInBackground:#selector(configureDetailViewForAsset:) withObject:asset];
} failureBlock:^(NSError *error) {
NSLog(#"failed to retrieve asset: %#", error);
}];
}
- (void)configureDetailViewForAsset:(ALAsset *)currentAsset {
ALAssetRepresentation *currentRep = [currentAsset defaultRepresentation];
if (currentAsset != nil) {
// do some stuff
}
else {
NSLog(#"ERROR: currentAsset is nil");
}
NSDictionary *metaDictionary;
if (currentRep != nil) {
metaDictionary = [currentRep metadata];
// do some other stuff
}
else {
NSLog(#"ERROR: currentRep is nil");
}
}
I understand that once a notification is received, it invalidates any references to ALAsset and ALAssetRepresentation objects... but how am I supposed to deal with the situation where it invalidates something right in the middle of trying to access it?
I've tried setting a BOOL, right when receiving the notification to completely abort and prevent [currentRep metadata] from ever being called, but even that doesn't catch it every time:
if (self.receivedLibraryChangeNotification) {
NSLog(#"received library change notification, need to abort");
}
else {
metaDictionary = [currentRep metadata];
}
Is there anything I can do? At this point I'm almost ready to give up on using the ALAssetsLibrary framework.
(note this unresolved thread on the Apple dev forums describing the same issue: https://devforums.apple.com/message/604430 )
It seems the problem is around here:
[self.assetsLibrary assetForURL:nextURL
resultBlock:^(ALAsset *asset) {
// You should do some stuff with asset at this scope
ALAssetRepresentation *currentRep = [asset defaultRepresentation];
// Assume we have a property for that
self.assetRepresentationMetadata = [currentRep metadata];
...
// assume we have a method for that
[self updateAssetDetailsView];
}
failureBlock:^(NSError *error) {
NSLog(#"failed to retrieve asset: %#", error);
}];
Once you have got user asset it is better to copy asset information by providing necessary data to your details controller subviews or by caching for later use. It can be helpful for avoiding ALAsset invalidation troubles. When notification ALAssetsLibraryChangedNotification sent you may need to discard details controller and query the Library content from the beginning.
Is there any way to acccess the properties of the Albums synced in ipad photo library.I want to get the names with which the Album is saved in the photo library.Please anyone who have tries this or who have any knowledge in this case ,please help.
Thanks,
Christy
You'd want to use the ALAssetsLibrary. This ought to get you moving in the right direction:
ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init];
[library enumerateGroupsWithTypes:ALAssetsGroupAll
usingBlock:^(ALAssetsGroup *group, BOOL *stop)
{
if (group == nil)
return;
//this is the album name
NSLog(#"%#",[group valueForProperty:ALAssetsGroupPropertyName]);
}
failureBlock:^(NSError *error)
{
//failure code here
}];
Is there a way I can delete an image that is loaded into my app from a UIImagePickerController?
I want to be able to delete the image from the user's photo library when the user performs a specific action.
I am prompting the user to choose a image from their library, then it gets loaded into my app at which point the app does some shnazzy animation, then actually deletes the image.
Please help!
Apple doesn't actually allow you to delete from the photo library through an API. The user has to actually go to the Photos app and delete it manually themselves. Apple does allow you write to the photo library:
To save a still image to the user’s
Saved Photos album, use the
UIImageWriteToSavedPhotosAlbum
function. To save a movie to the
user’s Saved Photos album, use the
UISaveVideoAtPathToSavedPhotosAlbum
function.
But for deleting and editing/overriding an existing photo, Apple doesn't have anything like that right now.
Actually, you can delete photos saved by your app (saved to photo library with UIImageWriteToSavedPhotosAlbum API call).
The documented API [ALAsset setImageData:metadata:completionBlock:] works.
1). Add an image "photo.jpg" to your project
2). Save an image to asset library:
ALAssetsLibrary *lib = [ALAssetsLibrary new];
UIImage *image = [UIImage imageNamed:#"photo.jpg"];
[lib writeImageToSavedPhotosAlbum:image.CGImage metadata:#{} completionBlock:^(NSURL *assetURL, NSError *error) {
NSLog(#"Write image %# to asset library. (Error %#)", assetURL, error);
}];
3). Go to default gallery, you will find photo.jpg in your "Saved Photos" album.
4). Delete this image from asset library:
ALAssetsLibrary *lib = [ALAssetsLibrary new];
[lib enumerateGroupsWithTypes:ALAssetsGroupSavedPhotos usingBlock:^(ALAssetsGroup *group, BOOL *stop) {
[group enumerateAssetsUsingBlock:^(ALAsset *asset, NSUInteger index, BOOL *stop) {
if(asset.isEditable) {
[asset setImageData:nil metadata:nil completionBlock:^(NSURL *assetURL, NSError *error) {
NSLog(#"Asset url %# should be deleted. (Error %#)", assetURL, error);
}];
}
}];
} failureBlock:^(NSError *error) {
}];
5). Go to default gallery, you will find photo.jpg has already been deleted.
Yes we can delete a photo. We can use PHAssetChangeRequest for this operation.
From Apple:
A request to create, delete, change metadata for, or edit the content of a Photos asset, for use in a photo library change block.
class func deleteAssets(_ assets: NSFastEnumeration)
where assets:
An array of PHAsset objects to be deleted.
PHAssetChangeRequest.deleteAssets([assetToDelete])
So, you could use the above code to delete assets.
below is swift 3 code,
PHPhotoLibrary.shared().performChanges({
let imageAssetToDelete = PHAsset.fetchAssets(withALAssetURLs: imageUrls as! [URL], options: nil)
PHAssetChangeRequest.deleteAssets(imageAssetToDelete)
}, completionHandler: {success, error in
print(success ? "Success" : error )
})