I am trying to save a recorded video to the library using the UIImagePickerController delegate. It works fine for pictures but it doesn't save if it's a video, plus after trying to save a video if I open the Photos app, I get a message "Please wait. Updatring library", and a progress bar with the label "Rebuilding library". My photo library is restored but the video was not added to it.
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info {
NSString *mediaType = [info objectForKey:UIImagePickerControllerMediaType];
if ([mediaType isEqualToString:#"public.image"]){
UIImage *picture = [info objectForKey:UIImagePickerControllerOriginalImage];
UIImageWriteToSavedPhotosAlbum(picture, nil, nil, nil);
}
else if ([mediaType isEqualToString:#"public.movie"]){
NSString* m_objMediaURL= [info objectForKey:UIImagePickerControllerMediaURL];
NSLog(#"URL is %#", m_objMediaURL);
UISaveVideoAtPathToSavedPhotosAlbum(m_objMediaURL, nil, nil, nil);
}
[self dismissModalViewControllerAnimated:YES];
}
The NSLog above outputs the following:
URL is
file://localhost/private/var/mobile/Applications/3800A5FB-2A96-4A7A-85DF-B635E8D9A66C/tmp/capture-T0x1061f0.tmp.JMdxHq/capturedvideo.MOV
Has anyone implemented such method and can point me to the right direction please?
Thank you.
I think I see an issue.
NSString* m_objMediaURL= [info objectForKey:UIImagePickerControllerMediaURL];
Is the wrong type. My properly working code uses:
NSURL *url = [[[info objectForKey:UIImagePickerControllerMediaURL] copy] autorelease];
I copy it instead of retaining it because of some issues I have had in low memory situations after the picker view is dismissed. Although the save method you use might work, I use the newer and better (because of the callback block):
ALAssetsLibrary* library = [[[ALAssetsLibrary alloc] init] autorelease];
[library writeVideoAtPathToSavedPhotosAlbum:url
completionBlock:^(NSURL *assetURL, NSError *error){/*notify of completion*/}];
Also, you should be using kUTTypeMovie and kUTTypeImage instead of hard coding #"public.image.
I found the problem thanks to Peter's help. Turns out that [info objectForKey:UIImagePickerControllerMediaURL] returns a NSURL and not a NSString. So in the end here's how my method looks like
ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init];
NSURL *videoURL= [info objectForKey:UIImagePickerControllerMediaURL];
if ([library videoAtPathIsCompatibleWithSavedPhotosAlbum:videoURL])
{
[library writeVideoAtPathToSavedPhotosAlbum:videoURL
completionBlock:^(NSURL *assetURL, NSError *error){}
];
}
[library release];
This method uses the new ALAssetsLibrary framework. The whole method, which supports saving a picture or movie, follows:
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info {
ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init];
NSString *mediaType = [info objectForKey:UIImagePickerControllerMediaType];
if ([mediaType isEqualToString:#"public.image"]){
UIImage *picture= [info objectForKey:UIImagePickerControllerOriginalImage];
NSDictionary *metadata = [info objectForKey:UIImagePickerControllerMediaMetadata];
[library writeImageToSavedPhotosAlbum:[picture CGImage] metadata:metadata
completionBlock:^(NSURL *assetURL, NSError *error){}
];
}
else if ([mediaType isEqualToString:#"public.movie"]){
NSURL *videoURL= [info objectForKey:UIImagePickerControllerMediaURL];
if ([library videoAtPathIsCompatibleWithSavedPhotosAlbum:videoURL])
{
[library writeVideoAtPathToSavedPhotosAlbum:videoURL
completionBlock:^(NSURL *assetURL, NSError *error){}
];
}
}
[library release];
[self dismissModalViewControllerAnimated:YES];
}
Why are you passing nil, nil, nil into the method - if you pass in more options, it will tell you the error ;)
Try something like this instead :
UISaveVideoAtPathToSavedPhotosAlbum(m_objMediaURL, self, #selector(video:didFinishSavingWithError:contextInfo:), nil);
and later on in your class put this method
- (void)video:(NSString *)videoPath didFinishSavingWithError:(NSError *)error contextInfo:(void *)contextInfo {
// Let's see what happened
NSLog(#"path : %#", path);
NSLog(#:error : %#", error);
}
Hope the output of that helps you :)
EDIT :
Reading the docs a bit more, have you run this method to check that it's a valid video?
BOOL isVideoOK = UIVideoAtPathIsCompatibleWithSavedPhotosAlbum(m_objMediaURL);
if (NO == isVideoOK)
NSLog(#"Video at %# is not compatible", m_objMediaURL);
Related
I am trying to get picture taken date while choosing picture from Photo Library in iPhone. I am using below code to do the same.
NSDictionary* fileAttribs = [[NSFileManager defaultManager] attributesOfItemAtPath:path error:nil];
NSDate *result = [fileAttribs fileCreationDate]; //or fileModificationDate
But it is showing current date and time.
Is there any way to get picture taken date while choosing picture from Photo library.
You can do it checking the metadata of the picture with ALAsset
Look for the key ALAssetPropertyDate
EDIT, complete code:
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info {
NSURL *url = [info objectForKey:#"UIImagePickerControllerReferenceURL"];
ALAssetsLibrary* assetslibrary = [[ALAssetsLibrary alloc] init];
[assetslibrary assetForURL:url
resultBlock:^(ALAsset *asset) {
NSDate *myDate = [asset valueForProperty:ALAssetPropertyDate];
NSLog(#"Date: %#", myDate);
} failureBlock:^(NSError *error) {
NSLog(#"Error");
}];
[picker dismissViewControllerAnimated:YES completion:nil];
}
ALAssetsLibrary is deprecated, so with PHAsset:
#import <Photos/PHAsset.h>
Then:
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info {
NSURL *imageURL = [info valueForKey:UIImagePickerControllerReferenceURL];
PHAsset *phAsset = [[PHAsset fetchAssetsWithALAssetURLs:#[imageURL] options:nil] lastObject];
NSDate *date = [phAsset creationDate];
UIImage *image = [info valueForKey:UIImagePickerControllerOriginalImage];
}
I've been searching this forum up and down but I couldn't find what I really need. I want to get raw image data from the camera. Up till now I tried to get the data out of the imageDataSampleBuffer from that method captureStillImageAsynchronouslyFromConnection:completionHandler: and to write it to an NSData object, but that didn't work.
Maybe I'm on the wrong track or maybe I'm just doing it wrong.
What I don't want is for the image to be compressed in any way.
The easy way is to use jpegStillImageNSDataRepresentation: from AVCaptureStillImageOutput, but like I said I don't want it to be compressed.
Thanks!
This is how i do it:
1: I first open the camera using:
- (void)openCamera
{
imagePicker = [[UIImagePickerController alloc] init];
imagePicker.delegate = self;
if([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera])
{
imagePicker.sourceType = UIImagePickerControllerSourceTypeCamera;
imagePicker.mediaTypes = [NSArray arrayWithObjects:
(NSString *) kUTTypeImage,
(NSString *) kUTTypeMovie, nil];
imagePicker.allowsEditing = NO;
[self presentModalViewController:imagePicker animated:YES];
}
else {
lblError.text = NSLocalizedStringFromTable(#"noCameraFound", #"Errors", #"");
}
}
When the picture is taken this method gets called:
-(void) imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info {
// Save and get the path of the image
NSString *mediaType = [info objectForKey:UIImagePickerControllerMediaType];
ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init];
if([mediaType isEqualToString:(NSString *)kUTTypeImage])
{
// Save the image
image = [info objectForKey:#"UIImagePickerControllerOriginalImage"];
[library writeImageToSavedPhotosAlbum:[image CGImage] orientation:(ALAssetOrientation)[image imageOrientation] completionBlock:^(NSURL *assetURL, NSError *error){
if(!error) {
//Save path and location to database
NSString *pathLocation = [[NSString alloc] initWithFormat:#"%#", assetURL];
} else {
NSLog(#"CameraViewController: Error on saving image : %# {imagePickerController}", error);
}
}];
}
[imagePicker dismissModalViewControllerAnimated:YES];
}
Then with that path i get the picture from the library in FULL resolution (using the "1"):
-(void)preparePicture: (NSString *) filePathPicture{
ALAssetsLibraryAssetForURLResultBlock resultBlock = ^(ALAsset *myasset)
{
if(myasset != nil){
ALAssetRepresentation *assetRep = [myasset defaultRepresentation];
CGImageRef imageRef = [assetRep fullResolutionImage];
if (imageRef) {
NSData *imageData = UIImageJPEGRepresentation([UIImage imageWithCGImage:imageRef], 1);
}
}else {
//error
}
};
ALAssetsLibraryAccessFailureBlock failureBlock = ^(NSError *error)
{
NSString *errorString = [NSString stringWithFormat:#"can't get image, %#",[error localizedDescription]];
NSLog(#"%#", errorString);
};
if(filePathPicture && [filePathPicture length])
{
NSURL *assetUrl = [NSURL URLWithString:filePathPicture];
ALAssetsLibrary *assetslibrary = [[ALAssetsLibrary alloc] init];
[assetslibrary assetForURL:assetUrl
resultBlock:resultBlock
failureBlock:failureBlock];
}
}
Hope this helps you a bit further :-).
I've implemented the delegate method and can get access to the picked UIImage, like this:
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info {
UIImage *pickedImage = [info valueForKey:UIImagePickerControllerOriginalImage];
I want to save it to a directory, but I need a file name. So rather than just picking a random file name it would make sense to pick the same file name as the image.
Is there a way to retrieve it from that info dictionary?
You could use the UIImagePickerControllerReferenceURL value of the info dictionary instead of the UIImagePickerControllerOriginalImage. This should give you the URL to the original media item.
This would return you a NSURL object which you then can use to build your new filename from.
Use ALA Assets library framework
Use the code below
ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init];
UIImage *image = [info objectForKey:UIImagePickerControllerEditedImage];
[library writeImageToSavedPhotosAlbum:image.CGImage orientation:(ALAssetOrientation)image.imageOrientation completionBlock:^(NSURL *assetURL, NSError *error )
{
[library assetForURL:assetURL resultBlock:^(ALAsset *asset )
{
ALAssetsLibraryAssetForURLResultBlock resultblock = ^(ALAsset *imageAsset)
{
ALAssetRepresentation *imageRep = [imageAsset defaultRepresentation];
NSLog(#"reference image filename picking from camera: %#", [imageRep filename]);
};
ALAssetsLibrary* assetslibrary = [[ALAssetsLibrary alloc] init];
[assetslibrary assetForURL:assetURL resultBlock:resultblock failureBlock:nil];
}
failureBlock:^(NSError *error )
{
NSLog(#"Error loading asset");
}];
}];
imageView.image = [info objectForKey:UIImagePickerControllerEditedImage];
imageView.contentMode = UIViewContentModeScaleAspectFit;
i created a application to get images from iPhone photo Folder using ALAssetLibrary.
Can i retrieve files using AlAssetLibrary without using Location Service?
How can i avoid Location service in AlAssetLibrary?
Currently there is no way to access ALAssetLibrary without using location services. You have to use the, much more limited, UIImagePickerController to get around that problem.
The above answer is incorrect if you only need one image from the library. For example, if you are having the user choose a photo to upload. In this case you can get that single image with ALAssetLibrary, without needing Location permissions.
To do this, use a UIImagePickerController to select the picture; you just need the UIImagePickerControllerReferenceURL, which the UIImagePickerController provides.
This has the benefit of giving you access to an unmodified NSData object, which you can then upload.
This is helpful because re-encoding the image later using UIImagePNGRepresentation() or UIImageJPEGRepresentation() can double the size of your file!
To present the picker:
picker = [[UIImagePickerController alloc] init];
[picker setDelegate:self];
[picker setSourceType:UIImagePickerControllerSourceTypePhotoLibrary];
[self presentViewController:picker animated:YES completion:nil];
To get the image and/or data:
- (void)imagePickerController:(UIImagePickerController *)thePicker didFinishPickingMediaWithInfo:(NSDictionary *)info
{
[picker dismissViewControllerAnimated:YES completion:nil];
NSURL *imageURL = [info objectForKey:#"UIImagePickerControllerReferenceURL"];
ALAssetsLibrary *assetLibrary=[[ALAssetsLibrary alloc] init];
[assetLibrary assetForURL:imageURL
resultBlock:^(ALAsset *asset) {
// get your NSData, UIImage, or whatever here
ALAssetRepresentation *rep = [self defaultRepresentation];
UIImage *image = [UIImage imageWithCGImage:[rep fullScreenImage]];
Byte *buffer = (Byte*)malloc(rep.size);
NSUInteger buffered = [rep getBytes:buffer fromOffset:0.0 length:rep.size error:nil];
NSData *data = [NSData dataWithBytesNoCopy:buffer length:buffered freeWhenDone:YES];
if (picker.sourceType == UIImagePickerControllerSourceTypeCamera) {
UIImageWriteToSavedPhotosAlbum(image, nil, nil, nil);
}
}
failureBlock:^(NSError *err) {
// Something went wrong; get the image the old-fashioned way
// (You'll need to re-encode the NSData if you ever upload the image)
UIImage *image = [info objectForKey:UIImagePickerControllerOriginalImage];
if (picker.sourceType == UIImagePickerControllerSourceTypeCamera) {
UIImageWriteToSavedPhotosAlbum(image, nil, nil, nil);
}
}];
}
How can I save an image (like using UIImageWriteToSavedPhotosAlbum() method) with a filename of my choice to the private/var folder?
Kenny, you had the answer! For illustration I always think code is more helpful.
//I do this in the didFinishPickingImage:(UIImage *)img method
NSData* imageData = UIImageJPEGRepresentation(img, 1.0);
//save to the default 100Apple(Camera Roll) folder.
[imageData writeToFile:#"/private/var/mobile/Media/DCIM/100APPLE/customImageFilename.jpg" atomically:NO];
UIImageWriteToSavedPhotosAlbum() is only used for saving to the photos camera roll. To save to a custom folder, you need to convert the UIImage into NSData with UIImageJPEGRepresentation() or UIImagePNGRepresentation(), then save this NSData to anywhere you like.
You can use below code, without use of ALAssetsLibrary...
NSString *fileName;
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info
{
[picker dismissViewControllerAnimated:YES completion:^{
if( [picker sourceType] == UIImagePickerControllerSourceTypeCamera )
{
UIImageWriteToSavedPhotosAlbum(image,nil, nil, nil);
[self performSelector:#selector(GetImageName) withObject:nil afterDelay:0.5];
}
else
{
NSURL *refURL = [info valueForKey:UIImagePickerControllerReferenceURL];
PHFetchResult *result = [PHAsset fetchAssetsWithALAssetURLs:#[refURL] options:nil];
fileName = [[result firstObject] filename];
}
}];
-(void)GetImageName
{
NSString *str =#"";
PHFetchOptions *fetchOptions = [[PHFetchOptions alloc] init];
fetchOptions.sortDescriptors = #[[NSSortDescriptor sortDescriptorWithKey:#"creationDate" ascending:YES]];
PHFetchResult *fetchResult = [PHAsset fetchAssetsWithMediaType:PHAssetMediaTypeImage options:fetchOptions];
if (fetchResult != nil && fetchResult.count > 0) {
str = [[fetchResult lastObject] filename];
}
fileName = str;
}