I'm building an iOS app that allows the user to upload videos from UIImagePickerController, either by recording or choosing them from the Camera Roll, as well as also play the chosen video. My question is, how would I go about keeping a reference to the videos that have been chosen this way? I want to do this so that if the video is still present on the device, I can use the local file rather than streaming the uploaded file.
When
imagePickerController:didFinishPickingMediaWithInfo:
returns, the URL in:
[info objectForKey:UIImagePickerControllerMediaURL];
Is in the format of: "file://localhost/private/var/mobile/Applications/ /tmp//trim.z2vLjx.MOV"
I'm lead to believe that the "/tmp/" directory is temporary, and therefore not suitable to save the URL for that location.
I can get all of the videos on the device through ALAssetsLibrary, but because I don't have a way of distinguishing them, this doesn't help me. I've been attempting to use:
[result valueForProperty:ALAssetPropertyDate];
To distinguish the videos, but I need a way of getting the creation date from UIImagePickerController for this to be useful.
I've finally managed to find a solution:
-(void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info
{
NSString* mediaType = [info objectForKey:UIImagePickerControllerMediaType];
if(CFStringCompare((CFStringRef) mediaType, kUTTypeMovie, 0) == kCFCompareEqualTo)
{
//Dismiss the media picker view
[picker dismissModalViewControllerAnimated:YES];
//Get the URL of the chosen content, then get the data from that URL
NSURL *videoURL = [info objectForKey:UIImagePickerControllerMediaURL];
NSData *webData = [NSData dataWithContentsOfURL:videoURL];
//Gets the path for the URL, to allow it to be saved to the camera roll
NSString *moviePath = [[info objectForKey:UIImagePickerControllerMediaURL] path];
if (UIVideoAtPathIsCompatibleWithSavedPhotosAlbum (moviePath))
{
ALAssetsLibrary *lib = [[ALAssetsLibrary alloc] init];
//The key UIImagePickerControllerReferenceURL allows you to get an ALAsset, which then allows you to get metadata (such as the date the media was created)
[lib assetForURL:[info objectForKey:UIImagePickerControllerReferenceURL] resultBlock:^(ALAsset *asset) {
NSLog(#"created: %#", [asset valueForProperty:ALAssetPropertyDate]);
} failureBlock:^(NSError *error) {
NSLog(#"error: %#", error);
}];
}
}
As per usual, the solution was found by reading the documentation a little more thoroughly. Hopefully this'll help someone else out at some point.
You can easily keep a record of the videos you have on the device. Either by keeping a data base (which I think would be too much) or just a file with a list of your videos. In that list, you could have the URL of the assets.
Related
I would like to know how to retrieve the filename of an image taken with the camera using UIImagePickerController.
I don't need to do anything with it, i just have to display the filename, like something you would see when you attach a file when you're sending an email.
So far, i'm using AssetsLibrary :
-(void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info{
[picker dismissViewControllerAnimated:YES completion:nil];
NSURL *refURL = [info valueForKey:UIImagePickerControllerReferenceURL];
// define the block to call when we get the asset based on the url (below)
ALAssetsLibraryAssetForURLResultBlock resultblock = ^(ALAsset *imageAsset)
{
ALAssetRepresentation *imageRep = [imageAsset defaultRepresentation];
NSLog(#"[imageRep filename] : %#", [imageRep filename]);
self.photoNameLabel.text = [imageRep filename];
};
// get the asset library and fetch the asset based on the ref url (pass in block above)
ALAssetsLibrary* assetslibrary = [[ALAssetsLibrary alloc] init];
[assetslibrary assetForURL:refURL resultBlock:resultblock failureBlock:nil];
self.photoLoaded = info[UIImagePickerControllerEditedImage];
[self viewWillLayoutSubviews];
}
But imageAsset will always be nil if it comes from the device camera, and if not, the image is named IMG_00XX.jpg, even if i downloaded it from the internet before, with a different name.
Can i get the name of a picture in an ios environment? If so, how am i supposed to do that?
There is no name when you take a photo with the camera. All there is is the in-memory UIImage instance. It's not associated with a file.
If you wish to add this camera image to an email as an attachment, give it whatever name you want such as "photo.jpg" or "picture.jpg" or anything else you wish to use.
I am working on adding video to a chat application. The users can either share a video chosen from their files or record a new one to upload.
The issue I am having is differentiating between a video which has just been recorded and a video which has been selected as I want to save a just recorded video to their album when they upload it.
Currently my code looks like this:
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info {
// This checks whether we are adding image or video (public.movie for video)
if ([[info objectForKey:UIImagePickerControllerMediaType] isEqualToString:#"public.image"]) {
UIImage * image = [info objectForKey:UIImagePickerControllerEditedImage];
[self sendImage:image];
}
else {
// SS-V
// If we are dealing with a video then we want to return to the chat view and post the video
NSURL * videoURL = (NSURL *)[info objectForKey:UIImagePickerControllerMediaURL];
// Send video to the chat view
[self sendVideo:[videoURL absoluteString]];
}
[tableView reloadData];
[picker dismissViewControllerAnimated:YES completion:Nil];
}
So I am getting the local url of the video and then uploading it to an external database.
I have also got this code:
// Save the recorded video to the iPhone
NSString * videoCompatibleString = [videoURL.absoluteString stringByReplacingOccurrencesOfString:#"file://" withString:#""];
if (UIVideoAtPathIsCompatibleWithSavedPhotosAlbum(videoCompatibleString)) {
UISaveVideoAtPathToSavedPhotosAlbum (videoCompatibleString, self, nil, nil);
}
Which will save it to my phone library.
So now my only issue is how to differentiate between a video just taken and a video selected from my library already.
I was hoping there would be an elegant way of achieving this. Seemingly there isn't and so I set up an enum to record what I loaded the image picker with, if I loaded it with the camera then I knew that I would be taking the video or picture so should add it to the album:
In the header file:
typedef enum {
bPictureTypeCamera,
bPictureTypeAlbumImage,
bPictureTypeAlbumVideo,
} bPictureType;
// This allows us to see what kind of media is being sent to know if we need to save it to album
bPictureType _pictureType;
In the main file:
// If we have just taken the media then save it to the users camera
if (_pictureType == bPictureTypeCamera) {
[self saveMediaWithInfo:info];
}
With my save function checking if it is video or image and saving it:
- (void)saveMediaWithInfo: (NSDictionary *)info {
// Save image
if ([[info objectForKey:UIImagePickerControllerMediaType] isEqualToString:#"public.image"]) {
UIImageWriteToSavedPhotosAlbum([info objectForKey:UIImagePickerControllerEditedImage], self, nil, nil);
}
// Save Video
else {
// Make sure the video is in a compatible format to save
NSURL * videoURL = (NSURL *)[info objectForKey:UIImagePickerControllerMediaURL];
NSString * videoCompatibleString = [[videoURL absoluteString] stringByReplacingOccurrencesOfString:#"file://" withString:#""];
if (UIVideoAtPathIsCompatibleWithSavedPhotosAlbum (videoCompatibleString)) {
UISaveVideoAtPathToSavedPhotosAlbum (videoCompatibleString, self, nil, nil);
}
}
}
Now the neatest answer but it does what it needs to
The current best solution:
https://stackoverflow.com/a/21888830/1786820
I am trying to do one better, by opening the Instagram app with a preselected video file from the PhotoRoll, and a preloaded caption. In the Flipagram app, they do just this. When you hit share on a video, they save it your camera roll, suggest a caption, then direct to the Instagram app photo selection screen, with the video preselected. Even if the video is not the latest media in the PhotoRoll, it correctly highlights the correct video, along the caption prepared in the Flipagram app.
Is this possibly an undocumented iPhone hook?
Any help is appreciated.
I came up with the idea to allow my app to accept the instagram:// URL schema. The hook from Flipagram opened up in my app as the following:
instagram://library?AssetPath=assets-library%3A%2F%2Fasset%2Fasset.mp4%3Fid%3D8864C466-A45C-4C48-B76F-E3C421711E9D%26ext%3Dmp4&InstagramCaption=Some%20Preloaded%20Caption
The undocumented iPhone hook that allows you to automatically select assets from the iPhones photo roll, and preload a caption for the video. This should give you the same user experience that Flipagrams app has with sharing a video to Instagram.
NSURL *videoFilePath = ...; // Your local path to the video
NSString *caption = #"Some Preloaded Caption";
ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init];
[library writeVideoAtPathToSavedPhotosAlbum:[NSURL URLWithString:videoFilePath] completionBlock:^(NSURL *assetURL, NSError *error) {
NSURL *instagramURL = [NSURL URLWithString:[NSString stringWithFormat:#"instagram://library?AssetPath=%#&InstagramCaption=%#",[assetURL absoluteString].percentEscape,caption.percentEscape]];
if ([[UIApplication sharedApplication] canOpenURL:instagramURL]) {
[[UIApplication sharedApplication] openURL:instagramURL];
}
}];
Works great!
Update:
Instagram has removed the ability to pass the caption to their app. The best solution now it to just copy the desired caption to the paste board.
The answer is that it is not pulling the video from the camera roll at all, it might just look like it is.
Documentation here: http://instagram.com/developer/mobile-sharing/iphone-hooks/
The relevant bit is the bottom section "Document Interaction".
You would do this by doing something like this:
NSString *filePath = [NSTemporaryDirectory() stringByAppendingPathComponent:#"instagram.igo"];
NSData *data = // set this yourself
NSError *error = nil;
if (! [data writeToFile:filePath options:NSDataWritingAtomic error:&error])
{
// error here
}
self.documentInteractionController = [UIDocumentInteractionController interactionControllerWithURL:[NSURL fileURLWithPath:filePath]];
self.documentInteractionController.delegate = self;
self.documentInteractionController.UTI = #"com.instagram.exclusivegram";
self.documentInteractionController.annotation = #{ #"InstagramCaption" : #"caption text here" };
const BOOL couldOpen = [self.documentInteractionController presentOpenInMenuFromRect:CGRectZero inView:myView animated:YES];
Set the data, the caption, and the view to present from yourself. Notice the UIDocumentInteractionController is also a property. It should be retained somewhere and not just a local variable in a method because it needs to exist outside of that scope when the method completes.
Hey I'm new to iPhone and I have been trying to make an gallery kind of app. Basically, what I want to do is that i need to save all the captured images into a specific folder like a new album "My_App Images" related to our app name in iPhone device gallery, it's working for me, but I am having trouble to change the image file name, i don't know that Is it possible to specify a file name? Using iPhoto, currently i am getting image file name as "IMG_0094.jpg", can we change it with any other file name like "Anyfilename.png" format programmatically?
here is my code for saving images to the specific album :
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingImage:(UIImage *)image editingInfo:(NSDictionary *)editingInfo
{
[self.library saveImage:image toAlbum:#"My_App Images" withCompletionBlock:^(NSError *error) {
if (error!=nil) {
NSLog(#"Image saving error: %#", [error description]);
}
}];
[picker dismissViewControllerAnimated:NO completion:nil];
}
Any source or link for reference is appreciated. Thanks for the help!
There is a way to kinda do that, by setting the image IPTC metadata field "Object Name". If you later import the image to iPhoto, then this name will be used as its title.
See details (and code) at http://ootips.org/yonat/how-to-set-the-image-name-when-saving-to-the-camera-roll/ .
Do you meant,
// Build NSData in memory from the btnImage...
NSData* imageData = UIImageJPEGRepresentation(image, 1.0);
// Save to the default Apple (Camera Roll) folder.
[imageData writeToFile:#"/private/var/mobile/Media/DCIM/100APPLE/customImageFilename.jpg" atomically:NO];
Now adjust the path of folder as per your folder name...
Sorry to disappoint you, but it seems that you can not change the name of the photos, before or after saving, in the photo album, custom or not. Here is a post to explain it:
iOS rename/delete albums of photos
Edit
So, to clarify my comment, use the following override:
Download the NSMutableDictionary category for metadata of image here.
Also download the sample project CustomAlbumDemo from here and modify the NSMutableDictionary+ImageMetadata.m file in the CustomAlbumDemo project as:
-(void)saveImage:(UIImage*)image toAlbum:(NSString*)albumName withCompletionBlock:(SaveImageCompletion)completionBlock
{
//write the image data to the assets library (camera roll)
NSData* imageData = UIImageJPEGRepresentation(image, 1.0);
NSMutableDictionary *metadata = [[NSMutableDictionary alloc] init];
[metadata setDescription:#"This is my special image"];
[self writeImageDataToSavedPhotosAlbum:imageData metadata:metadata 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];
}];
}
I have a simple App than you have the possibility to choose an existent video from photo library or you can take a video with UIImagePickerController.
I added the following code for when I make a new video with camera I can save it in photo Gallery if I need in the future.
-(void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info
{
// Get the selected Video.
NSURL *videoURL = [info objectForKey:UIImagePickerControllerMediaURL];
// Convert to Video data.
NSData *imageData = [NSData dataWithContentsOfURL:videoURL];
// Save Video to Photo Album
ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init];
NSURL *recordedVideoURL= [info objectForKey:UIImagePickerControllerMediaURL];
if ([library videoAtPathIsCompatibleWithSavedPhotosAlbum:recordedVideoURL]) {
[library writeVideoAtPathToSavedPhotosAlbum:recordedVideoURL
completionBlock:^(NSURL *assetURL, NSError *error){}
];
}
[library release];
[picker dismissModalViewControllerAnimated:NO];
}
Now my issue is when I select a video from Photo Library this same video is duplicated as this code save always a new video.
Is it a way to detect if you selected the video from Photo Library ?
Before saving the video, check the imagePickerController's sourceType. Only save the video if sourceType is UIImagePickerControllerSourceTypeCamera.
if (picker.sourceType == UIImagePickerControllerSourceTypeCamera) {
// Save the video
}