Save UIImage to Photo Album with writeImageToSavedPhotosAlbum - iphone

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];
}

Related

UIImagePickerControllerReferenceURL is missing

I'm trying to get some data about a video i chose in the UIImagePicker.
So when it gets into the UIImagePicker delegate method (below) i understand i need to use the UIImagePickerControllerReferenceURL key from the info dictionary.
-(void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info {
NSURL *url = [info objectForKey:UIImagePickerControllerReferenceURL];
NSLog(#"%#",url);
[library addAssetURL:[info objectForKey:UIImagePickerControllerReferenceURL] toAlbum:#"Compedia" withCompletionBlock:^(NSError *error) {
if (error!=nil) {
NSLog(#"Big error: %#", [error description]);
}
}];
}
The problem is that the url is resulting with nil.
I printed the description of info and it looks like this:
Printing description of info:
{
UIImagePickerControllerMediaType = "public.movie";
UIImagePickerControllerMediaURL = "file://localhost/private/var/mobile/Applications/6630FBD3-1212-4ED0-BC3B-0C23AEEFB267/tmp/capture-T0x1f57e880.tmp.Ulfn5o/capturedvideo.MOV";
}
After i've done some research i found out that if i set the camera with kUTTypeMovie it should give me both media and reference url.
This is how i defined my camera:
cameraUI = [[UIImagePickerController alloc] init];
cameraUI.sourceType = UIImagePickerControllerSourceTypeCamera;
cameraUI.mediaTypes = [[NSArray alloc] initWithObjects:(NSString *)kUTTypeMovie, nil];
cameraUI.allowsEditing = YES;
cameraUI.delegate = delegate;
cameraUI.showsCameraControls = NO;
cameraUI.cameraOverlayView = [self getCustomToolBar];
Is there something i'm missing?
Thanks,
Nearly went insane on this one. Every where I looked everyone seemed to be convinced that the UIImagePickerControllerReferenceURL was always there.
Anyway the issue is that if your delegate is being called after you have taken a pic using the camera than the UIImagePickerControllerReferenceURL object will not be there as the image has not been saved to the camera roll yet so therefore there is no UIImagePickerControllerReferenceURL. It is only there when the delegate is called after selecting an image from the camera roll.
So my way around this is to use the ALAssetLibrary to save it to the camera roll then read back the URL.
Heres my solution:
First you want to detect your PickerController sourceType to see if it was the camera or photosLibrary/savedPhotosAlbum. If it is the camera then we use the Asset library's writeImageToSavedPhotosAlbum:orientation:completionBlock: to write the image to the camera roll and give us back the images URL in the completion block.
However if the its not the camera then that means is was either the photosLibrary or savedPhotosAlbum which in both cases [info objectForKey:UIImagePickerControllerReferenceURL] would return a valid url
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info
{
//dismiss the imagepicker view
[self dismissViewControllerAnimated:YES completion:nil];
if( [picker sourceType] == UIImagePickerControllerSourceTypeCamera )
{
UIImage *image = [info objectForKey:UIImagePickerControllerOriginalImage];
ALAssetsLibrary *library = [Utils defaultAssetsLibrary];
[library writeImageToSavedPhotosAlbum:image.CGImage orientation:(ALAssetOrientation)image.imageOrientation completionBlock:^(NSURL *assetURL, NSError *error )
{
//here is your URL : assetURL
}];
}
else
{
//else this is valid : [info objectForKey:UIImagePickerControllerReferenceURL]];
}
}
Hope that helps.
ALAssetsLibrary is deprecated... use PHFetchOptions..
Refer below answer:
https://stackoverflow.com/a/44328085/5315917

save image in camera roll and get asset url

for an app I'm developing, I use UIImagePickerController to shoot a picture and store it in camera roll:
- (void)imagePickerController:(UIImagePickerController*)picker didFinishPickingMediaWithInfo:(NSDictionary*)info {
//... some stuff ...
UIImageWriteToSavedPhotosAlbum([info objectForKey:#"UIImagePickerControllerOriginalImage"], nil, nil, nil);
}
the image is saved, now I need to get its reference url so I try to enumerate camera roll and get the last image, but I always get the image before the one I just shot.
Anybody has an idea how to get the reference of the just saved picture?
Thanks,
Max
This solution should fix the problem:
ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init];
[library writeImageToSavedPhotosAlbum:((UIImage *)[info objectForKey:UIImagePickerControllerOriginalImage]).CGImage
metadata:[info objectForKey:UIImagePickerControllerMediaMetadata]
completionBlock:^(NSURL *assetURL, NSError *error) {
NSLog(#"assetURL %#", assetURL);
}];
et voila:
assetURL assets-library://asset/asset.JPG?id=1611E84C-24E2-4177-B49A-1C57B4A9C665&ext=JPG

Saving Image To Custom Library

I have an App which stores images to Custom Library in Photo Album in iphone.
I called the following Function of ALAssetLibrary
-(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];
}];
}
in my SaveImage IBAction
-(IBAction)saveToLib:(id)sender
{
UIImage *savedImage = imgPicture.image;
NSLog(#"Saved Image%#",savedImage);
[self.library saveImage:savedImage toAlbum:#"Touch Code" withCompletionBlock:^(NSError *error) {
if (error!=nil) {
NSLog(#"Big error: %#", [error description]);
}
}];
}
but my application keep getting Crashed
Help me out
Thanks in Advance
It seems that you are not calling the [self.library saveImage:savedImage toAlbum:#....] correctly. If you are following this web site, add #import "ALAssetsLibrary+CustomPhotoAlbum.h" in your view controller.
Not sure if it is the problem. Sorry if this workaround is the wrong approach.
Problem is the file from the website he downloaded.
I had the same issue and rewriting the code myself solved this.
Maybe encoding or something like this...

Zeroing ALAssetRepresentation after saving image captured via UIImagePickerController in iOS5

In my app (which worked under iOS 4) I collect pictures selected via UIImagePickerController. Unfortunately, I have a strange problem after upgrading to iOS 5.
In a nutshell, I store ALAssetRepresentation in NSMutableArray. When I add photos from Library, everything is ok. However, when I capture and save a picture, all ALAssetRepresentations (including a new one) become 0-sized. ALAssetRepresentation.size and ALAssetRepresentation.getBytes:fromOffset:length:error: return 0 and getBytes:error is nil.
I init ALAssetsLibrary in AppDelegate, so the
“The lifetimes of objects you get back from a library instance are tied to the lifetime of the library instance.” condition is OK.
Is there a way to prevent ALAssetRepresentation from zeroing? Or how can I read image by bytes after this?
My code:
-(void) imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info{
if ([picker sourceType] == UIImagePickerControllerSourceTypePhotoLibrary){
[self addPhoto:[info valueForKey:UIImagePickerControllerReferenceURL]];
}
else if ([picker sourceType] == UIImagePickerControllerSourceTypeCamera){
[self savePhoto:[info valueForKey:UIImagePickerControllerOriginalImage]];
}
[self dismissModalViewControllerAnimated:YES];
}
-(ALAssetsLibrary*) getLibrary{
if (!library){
testAppDelegate *appDelegate = (testAppDelegate *)[[UIApplication sharedApplication] delegate];
library = appDelegate.library;
}
NSLog(#"getLibrary: %#", library);
return library;
}
-(void) addPhoto:(NSURL*) url{
ALAssetsLibraryAssetForURLResultBlock successBlock = ^(ALAsset *asset_){
ALAssetRepresentation *assetRepresentation = [[asset_ defaultRepresentation] retain];
[photos addObject: assetRepresentation];
};
ALAssetsLibraryAccessFailureBlock failureBlock = ^(NSError *error){
NSLog(#"Error: Cannot get image. %#", [error localizedDescription]);
};
[[self getLibrary] assetForURL:url resultBlock:successBlock failureBlock:failureBlock];
}
- (void)savePhoto:(UIImage *)image {
[[self getLibrary] writeImageToSavedPhotosAlbum:[image CGImage] orientation:[image imageOrientation] completionBlock:^(NSURL *assetURL, NSError *error) {
if (error) {
NSLog(#"Error: Cannot save image. %#", [error localizedDescription]);
} else {
NSLog(#"photo saved");
[self addPhoto:assetURL];
}
}];
}
I solved it!
ALAssetsLibraryChangedNotification
Sent when the contents of the assets library have changed from under the app that is using the data.
When you receive this notification, you should discard any cached information and query the assets library again. You should consider invalid any ALAsset, ALAssetsGroup, or ALAssetRepresentation objects you are referencing after finishing processing the notification.
Have you tried retaining the ALAssets instead of the ALAssetRepresentation? This should work, I have used this approach before.

using UISaveVideoAtPathToSavedPhotosAlbum

On simulator UISaveVideoAtPathToSavedPhotosAlbum cannot save movie into photo album unless photo album is open. Can it? How can I check if Photo Album is running and run it silently from my app? Chances are that on a real iPhone/Pad it will be already running but just in case...?
My movie is in Resources of my app. I want to copy it to album. Here is the methods that I put in my AppDelegate.m to accomplish that:
-(void)downloadVideo:(NSString *)sampleMoviePath{
if (UIVideoAtPathIsCompatibleWithSavedPhotosAlbum(sampleMoviePath)){
UISaveVideoAtPathToSavedPhotosAlbum(sampleMoviePath, self, #selector(video:didFinishSavingWithError: contextInfo:), sampleMoviePath);
}
}
-(void)video:(NSString *)videoPath didFinishSavingWithError:(NSError *)error contextInfo:(void *)contextInfo{
NSLog(#"Finished with error: %#", error);
}
I call it like this:
NSString *sampleMediaPathFromApp = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:#"movie_01.m4v"];
[self downloadVideo:sampleMediaPathFromApp];
Error message that I get:
Finished saving video with error: Error Domain=ALAssetsLibraryErrorDomain Code=-3310 "Data unavailable" UserInfo=0x564ab10 {NSLocalizedRecoverySuggestion=Launch the Photos application, NSLocalizedDescription=Data unavailable}
Naturally, if I open Photo album and then run my app it works fine.
Thanks a lot for your input.
BG
----edits----
I have edited the code so it is more readable - sorry I do not have an answer, but it is a good question - I had to put this here or else I could not submit the changes. --jwk82
You can save it as..
ALAssetsLibrary *assetLibrary = [[ALAssetsLibrary alloc] init];
[assetLibrary writeVideoAtPathToSavedPhotosAlbum:url completionBlock:^(NSURL *assetURL, NSError *error){