When using ALAssetsLibrary, I used to save image to photo library with proper exif using the code below:
NSInteger orientation = 2;// Or whatever
NSData *jpegData = [AVCaptureStillImageOutput jpegStillImageNSDataRepresentation:imageDataSampleBuffer];
CMSetAttachment(imageDataSampleBuffer, kCGImagePropertyOrientation,
[NSNumber numberWithInt: orientation],
kCMAttachmentMode_ShouldPropagate);
ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init];
CFDictionaryRef attachments = CMCopyDictionaryOfAttachments(kCFAllocatorDefault, imageDataSampleBuffer, kCMAttachmentMode_ShouldPropagate);
[library writeImageDataToSavedPhotosAlbum:jpegData metadata:(id)attachments completionBlock:^(NSURL *assetURL, NSError *error) {
...
...
}
It's not clear how to translate that code when using PHPhotoLibrary. Can anyone provide the right way to save attachments along with the jpeg image?
Use ImageIO to add Metadata to your JPEG/PNG image as described in the following article:
Save the exif metadata using the new PHPhotoLibrary
Related
Even though it looks like a simple procedure, it's by now 3 hours I'm trying without success. I am probably missing something really stupid.
So, I have this app downloading videos from the Internet. The videos are correctly stored locally because I can play them providing the local url. But, I can't succeed in copying the videos to the camera roll. Here is what I do:
ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init];
ALAssetsLibraryWriteVideoCompletionBlock videoWriteCompletionBlock =
^(NSURL *newURL, NSError *error) {
if (error) {
NSLog( #"Error writing image with metadata to Photo Library: %#", error );
} else {
NSLog( #"Wrote image with metadata to Photo Library %#", newURL.absoluteString);
}
};
NSLog(#"file %#", localPath);
NSURL *url = [NSURL fileURLWithPath:localPath isDirectory:NO];
[library writeVideoAtPathToSavedPhotosAlbum:url
completionBlock:videoWriteCompletionBlock];
But the output I get is:
2013-07-24 00:13:32.094 App[1716:907] file /var/mobile/Applications/70C18C4E-9F97-4A6A-B63E-1BD19961F010/Documents/downloaded_video.mp4
2013-07-24 00:13:32.374 App[1716:907] Wrote image with metadata to Photo Library (null)
And of course the file is not saved in the camera roll. It's a simple mp4, compatible with the device I'm using (i.e. it should be possible to save it).
I honestly have no idea what to do. Any hint will be highly appreciated. Thanks
I may have found a workaround for you. Have you tried an AVAssetExportSession?
In the sample below, I built a simple app that has two buttons on the screen. One calls onSaveBtn:, which simply grabs the URL of a video I have in my app's resource bundle and saves it to the user's saved photos album. (Though, in my case my videos do return YES from videoAtPathIsCompatibleWithSavedPhotosAlbum:. I didn't have any videos that don't return otherwise.)
The second button is wired to onExportBtn:, which takes the video we want to save, creates an AVAssetExportSession, exports the video to a temp directory, and then copies the exported video to the saved photos album. Due to the export time, this method does take longer than a simple copy, but maybe this could be an alternate path - check the results of videoAtPathIsCompatibleWithSavedPhotosAlbum:, and if YES, copy directly to the album. Otherwise, export the video, then copy.
Without having a video file that doesn't return NO to the compatibility call, I'm not 100% sure this would work for you, but it's worth a shot.
You may also want to check out this question, which explores what video formats are compatible on the device you may be using.
#import <AVFoundation/AVFoundation.h>
#import <AssetsLibrary/AssetsLibrary.h>
- (IBAction)onSaveBtn:(id)sender
{
NSURL *srcURL = [[NSBundle mainBundle] URLForResource:#"WP_20121214_001" withExtension:#"mp4"];
[self saveToCameraRoll:srcURL];
}
- (IBAction)onExportBtn:(id)sender
{
NSURL *srcURL = [[NSBundle mainBundle] URLForResource:#"WP_20121214_001" withExtension:#"mp4"];
AVAsset *srcAsset = [AVAsset assetWithURL:srcURL];
// create an export session
AVAssetExportSession *exportSession = [[AVAssetExportSession alloc] initWithAsset:srcAsset presetName:AVAssetExportPresetHighestQuality];
// Export the file to a tmp dir
NSString *fileName = [srcURL lastPathComponent];
NSString *tmpDir = NSTemporaryDirectory();
NSURL *tmpURL = [NSURL fileURLWithPath:[tmpDir stringByAppendingPathComponent:fileName]];
exportSession.outputURL = tmpURL;
exportSession.outputFileType = AVFileTypeQuickTimeMovie;
[exportSession exportAsynchronouslyWithCompletionHandler:^{
// now copy the tmp file to the camera roll
switch ([exportSession status]) {
case AVAssetExportSessionStatusFailed:
NSLog(#"Export failed: %#", [[exportSession error] localizedDescription]);
break;
case AVAssetExportSessionStatusCancelled:
NSLog(#"Export canceled");
break;
case AVAssetExportSessionStatusCompleted:
NSLog(#"Export successful");
[self saveToCameraRoll:exportSession.outputURL];
break;
default:
break;
}
}];
}
- (void) saveToCameraRoll:(NSURL *)srcURL
{
NSLog(#"srcURL: %#", srcURL);
ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init];
ALAssetsLibraryWriteVideoCompletionBlock videoWriteCompletionBlock =
^(NSURL *newURL, NSError *error) {
if (error) {
NSLog( #"Error writing image with metadata to Photo Library: %#", error );
} else {
NSLog( #"Wrote image with metadata to Photo Library %#", newURL.absoluteString);
}
};
if ([library videoAtPathIsCompatibleWithSavedPhotosAlbum:srcURL])
{
[library writeVideoAtPathToSavedPhotosAlbum:srcURL
completionBlock:videoWriteCompletionBlock];
}
}
Where are you providing the URL to the block.
I think you need to do this way..
NSString *mediaType = [info objectForKey:UIImagePickerControllerMediaType];
NSURL *videoURL = [info objectForKey:UIImagePickerControllerMediaURL];
ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init];
[library writeVideoAtPathToSavedPhotosAlbum:videoURL completionBlock:^(NSURL *assetURL, NSError *error){
/*notify of completion*/
NSLog(#"AssetURL: %#",assetURL);
NSLog(#"Error: %#",error);
if (!error) {
//video saved
}else{
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Error" message:error.domain delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil, nil];
[alert show];
[alert release];
}
}];
You can change the url here, I have used for the imagePickerController..
See if its helps you..
Here's a shorter answer.
In my case, I've used AFNetworking to download a video from a URL and in the downloadCompletedBlock of the download operation, responseObject returns the download file. Logging responseObject returns me the full file path of the downloaded video.
If you are using another method to download videos, simply replace responseObject with the full file path of your video, probably with the usual NSSearchPathForDirectoriesInDomains method.
Here's the snippet I use to export videos in the application's local file directory to the Camera Roll:
NSURL *responseObjectPath = [NSURL URLWithString:responseObject];
// If video is compatible with Camera Roll
if ([[ALAssetsLibrary new] videoAtPathIsCompatibleWithSavedPhotosAlbum:responseObjectPath])
{
// Export to Camera Roll
[[ALAssetsLibrary new] writeVideoAtPathToSavedPhotosAlbum:responseObjectPath completionBlock:nil];
}
else
{
NSLog(#"Incompatible File Type");
}
Cheers!
i am working on a app that generates temporary video from the still image. But i don't want the user to view the temporary file what i have generated. But the moment when the app is generating the video file,the video is listing out by the camera roll.
my Question is How can i generate the temporary media file that could't have access to 'camera roll,iTunes and iCloud'?
please help me. thanks in advance.
Code:
[assetWriter finishWritingWithCompletionHandler:^
{
NSURL *url = _outMovieURL; ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init];
[library writeVideoAtPathToSavedPhotosAlbum:url
completionBlock:^(NSURL *assetURL, NSError *error)
{
NSLog(#"Done!");
}];
}];
This block:
[assetWriter finishWritingWithCompletionHandler:^
{
NSURL *url = _outMovieURL; ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init];
[library writeVideoAtPathToSavedPhotosAlbum:url
completionBlock:^(NSURL *assetURL, NSError *error)
{
NSLog(#"Done!");
}];
}];
Is to write file in camera roll. So don't use this while you have only created temporary video. Write that temporary video file in documentDirectory instead, (or probably it's already in documentDirectory, while you are creating it, all you need to do is to not write that file in camera roll with this code).
You should use NSTemporaryDirectory() and append your own affix at the end for any temporary files. Files in that directory will be cleaned by the OS or you can delete right after you are done with it.
When I try to save video by ALAssetLibrary method writeVideoAtPathToSavedPhotosAlbum the video's will be saved by name which will generated by AssetLibrary e.g. IMG_0111, IMG_0123 etc. How can I save these video's by specific name like "myAppName1.mov"
Following is the code snippet.
ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init];
[library writeVideoAtPathToSavedPhotosAlbum:tempURL
completionBlock:^(NSURL *assetURL, NSError *error)
{
if(error)
{
}
else
{
NSLog(#"Saved video at %#\n", [assetURL path]);
}
}];
[library release], library = nil;
There is no way to achieve this at the moment. You can't specify a file name, the Photolibrary assigns as you described filenames conforming to the pattern "IMG_XXX.ext" automatically.
The only case, when the file name is preserved is when photos get imported through the camera connection kit.
Cheers,
Hendrik
I am writing an image in iPad using ALAssets. When it finish I try to create an UIImage with the returned URL but it won't load. This is the code:
LAssetsLibrary *library = [[ALAssetsLibrary alloc] init];
[library writeImageToSavedPhotosAlbum:[anImage CGImage] orientation:(ALAssetOrientation)[anImage imageOrientation] completionBlock:^(NSURL *assetURL, NSError *error){
if (!error) {
CGImageSourceRef src = CGImageSourceCreateWithURL((CFURLRef) [NSURL fileURLWithPath:[assetURL absoluteString]], NULL);
My purpose is to save an image to the device, then convert it to another format using ImageIO and finally send it to a web service. CGImageSourceRef is null, I also tried with standard UIImage with the same result.
What I am doing wrong here?
EDIT: The problem is when creating the CFURLRef.
If I do
CGImageSourceCreateWithURL((CFURLRef) assetURL, NULL);
I got this error
ImageIO: CGImageSourceCreateWithURL CFURLCreateDataAndPropertiesFromResource failed with error code -11.
But if I try to convert the URL with
[NSURL fileURLWithPath:[assetURL absoluteString]]
the path is changed to
assets-library:/asset/asset.JPG%3Fid=57BBBA99-E7BF-4DB7-839E-F915005E6DFA&ext=JPG -- file://localhost/
I cannot find how to properly create the CFURLRef needed by the method. I tried printing all the conversions I could think of and this are the results
[assetURL relativePath]
[assetURL relativeString]
[assetURL absoluteURL]
[assetURL absoluteString]
/asset.JPG ,
assets-library://asset/asset.JPG?id=57BBBA99-E7BF-4DB7-839E-F915005E6DFA&ext=JPG
assets-library://asset/asset.JPG?id=57BBBA99-E7BF-4DB7-839E-F915005E6DFA&ext=JPG
assets-library://asset/asset.JPG?id=57BBBA99-E7BF-4DB7-839E-F915005E6DFA&ext=JPG
[NSURL fileURLWithPath:[assetURL relativePath]]
[NSURL fileURLWithPath:[assetURL relativeString]]
[NSURL fileURLWithPath:[assetURL absoluteString]]
file://localhost/asset.JPG
assets-library:/asset/asset.JPG%3Fid=57BBBA99-E7BF-4DB7-839E-F915005E6DFA&ext=JPG -- file://localhost/
assets-library:/asset/asset.JPG%3Fid=57BBBA99-E7BF-4DB7-839E-F915005E6DFA&ext=JPG -- file://localhost/
Help please, I am stuck with this :-(
This is what I did for my case.
UIImage* anImage; //this is the original image
NSData * imgData = UIImageJPEGRepresentation(anImage, 0.7);
CGImageSourceRef src = CGImageSourceCreateWithData((CFDataRef) imgData, NULL);
NSMutableData *data = [NSMutableData data];
CFStringRef imageType = CFSTR("com.microsoft.bmp");
CGImageDestinationRef myImageDest = CGImageDestinationCreateWithData((CFMutableDataRef) data, imageType, 1, nil);
//Convert!
CGImageDestinationAddImageFromSource(myImageDest, src, 0, myOptions);
CGImageDestinationFinalize(myImageDest);
//Freeing things
CFRelease(myImageDest);
CFRelease(src);
But this just converts the image, it doesn't store it in any file... Not sure this should be an answer to the original question.
If you already have an ALAsset and your goal is a CGImageRef you can do something like this.
ALAssetRepresentation* rep = [asset defaultRepresentation];
NSDictionary* options = [[NSDictionary alloc] initWithObjectsAndKeys:
(id)kCFBooleanTrue, (id)kCGImageSourceCreateThumbnailWithTransform,
(id)kCFBooleanTrue, (id)kCGImageSourceCreateThumbnailFromImageAlways,
(id)[NSNumber numberWithDouble:400], (id)kCGImageSourceThumbnailMaxPixelSize,
nil];
CGImageRef image = [rep CGImageWithOptions:options];
i have a Video file as NSData.how can i write the NSData file as Video in to Photolibrary/SavedPhotosAlbum?
i done it with UIimage through the following code. i had a UiImage as myNsData(NSData)
UIImage *viewImage = [UIImage imageWithData:myNsData];
ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init];
// Request to save the image to camera roll
[library writeImageToSavedPhotosAlbum:[viewImage CGImage] orientation:(ALAssetOrientation)[viewImage imageOrientation] completionBlock:^(NSURL *assetURL, NSError *error){
}
how can i do it the same functionality for Video.
i searched in NSData calss .
i found only two ways.
they are
(void)writeVideoAtPathToSavedPhotosAlbum:(NSURL *)videoPathURL completionBlock:(ALAssetsLibraryWriteVideoCompletionBlock)completionBlock;
- (BOOL)videoAtPathIsCompatibleWithSavedPhotosAlbum:(NSURL *)videoPathURL;
two of them are using URL.actually i didn't want to write the NSData file any where except in Photolibrary/SavedPhotosAlbum.
i need to write the NSData file directly in to the Photolibrary/SavedPhotosAlbum like i saved an image.How can do that?can any one Help me?
You need to create an AVAssetWriter with a video AVAssetWriterInput and add your data into the input.
When you create the AVAssetWriter, you need to specify an URL for the asset.
After you can use the ALAssetsLibrary (writeVideoAtPathToSavedPhotosAlbum:completionBlock:) to write the asset to the photo library, with the url of the asset created above.