Thumbnail from filepicker on iOS - ios

When using the built in UIImagePicker from iOS the developer has access to the thumbnail image used in the picker. Is it possible to access the thumbnail used by Filepicker or otherwise access the ALAsset library URL used by Filepicker?

This how I did it, but I must warn you it is slow(ish) and frameworks needed to to this are memory intensive as it iterates over the ALAssetsLibrary looking for posterimages.
This on the background thread, so UI changes are sent to the main thread for rendering.
self.assetsLibrary = [[ALAssetsLibrary alloc] init];
NSUInteger groupTypes = ALAssetsGroupAlbum | ALAssetsGroupSavedPhotos | ALAssetsGroupPhotoStream;
[self.assetsLibrary enumerateGroupsWithTypes:groupTypes
usingBlock:^(ALAssetsGroup *group, BOOL *stop) {
if (group.posterImage != nil) {
dispatch_async(dispatch_get_main_queue(), ^{
self.pictureLayer.contents = (__bridge_transfer id) CGImageCreateCopy(group.posterImage);
[self.layer setNeedsDisplay];
self.assetsLibrary = nil;
*stop = YES;
});
}
}
failureBlock:^(NSError *error) {
self.assetsLibrary = nil;
NSLog(#"AssetLib error:%#",error);
}];

Related

saving metadata to a video in savedPhotoAlbum Xcode

When I take a video using UIImagePickerController and save it to SavedPhotosAlbum using
ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init];
[library writeVideoAtPathToSavedPhotosAlbum:(NSURL *)movieURL
completionBlock:^(NSURL *assetURL, NSError *error){
if (error) {
NSLog(#"Save video fail:%#",error);
} else {
NSLog(#"Save video succeed.");
[self getsavedvideo];
}}];
the saved file contains a name and creation date but not the GPS info. I am surprised by this since I am using the built in camera and the imagePicker. Why wouldn't Apple just include the GPS coordinates (even if I had to ask users permission to use location services).
anyway I digress
I have not found anyway to add the GPS coordinates to the video as it is being saved and I haven't been able to find anyway to add the this information in the completionBlock.
If someone knows how please let me know.
So I wrote a bit of code that is called after the video is saved [self getsavedvideo]; above which gets the saved video and I can get the movie name and creation date and it shows there is no location info.
-(void) getsavedvideo;{
ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init];
// Enumerate just the photos and videos group by using ALAssetsGroupSavedPhotos.
[library enumerateGroupsWithTypes:ALAssetsGroupSavedPhotos usingBlock:^(ALAssetsGroup *group, BOOL *stop) {
// Within the group enumeration block, filter to enumerate just photos.
[group setAssetsFilter:[ALAssetsFilter allVideos]];
// Chooses the photo at the last index
[group enumerateAssetsWithOptions:NSEnumerationReverse usingBlock:^(ALAsset *alAsset, NSUInteger index, BOOL *innerStop) {
// The end of the enumeration is signaled by asset == nil.
if (alAsset) {
ALAssetRepresentation *representation = [alAsset defaultRepresentation];
// Stop the enumerations
*stop = YES; *innerStop = YES;
// Do something interesting with the AV asset.
NSString *fileName = [representation filename];
NSDate *myDate = [alAsset valueForProperty:ALAssetPropertyDate];
CLLocation *location = [alAsset valueForProperty:ALAssetPropertyLocation];
NSLog(#"fileName!!!!,%#",fileName);
NSDateFormatter * dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:mad:"dd-MM-yyyy 'at' HH:mm"];
NSLog( #"date for this file is %# %#", [[[alAsset defaultRepresentation] url] absoluteString], [dateFormatter stringFromDate: myDate] );
NSLog (#"locate!!!!%#",location);
} }];
} failureBlock: ^(NSError *error) {
NSLog(#"No groups");}];}
so does anyone know how to append this with the GPS information and save it back to the video's metadata.
I have been wracking my brains out on this for a few days and haven't really found anything helpful.
Plz help
So I figured this out for a device running ios8 or newer anyway.
add this code in the -(void) getsavedvideo that was in the completionBlock above.
Make sure you have
import
if ([PHAsset class]) { // If this class is available, we're running iOS 8
PHFetchOptions *fetchOptions = [PHFetchOptions new];
fetchOptions.sortDescriptors = #[[NSSortDescriptor sortDescriptorWithKey:#"creationDate" ascending:NO]];
fetchOptions.fetchLimit = 1;
PHFetchResult *fetchResult = [PHAsset fetchAssetsWithMediaType:PHAssetMediaTypeVideo options:fetchOptions];
PHAsset *lastImageAsset = [fetchResult lastObject];
[[PHImageManager defaultManager]requestImageForAsset:lastImageAsset targetSize:PHImageManagerMaximumSize contentMode:PHImageContentModeDefault options:nil resultHandler:^(UIImage *result, NSDictionary *info){
if ([info objectForKey:PHImageErrorKey] == nil && ![[info objectForKey:PHImageResultIsDegradedKey] boolValue]) {
NSArray *resources = [PHAssetResource assetResourcesForAsset:lastImageAsset];
NSString *orgFilename = ((PHAssetResource*)resources[0]).originalFilename;
[lastImageAsset requestContentEditingInputWithOptions:nil
completionHandler:^(PHContentEditingInput *contentEditingInput, NSDictionary *info) {
NSURL *imageURL = contentEditingInput.fullSizeImageURL;
NSString *urlstring = [imageURL absoluteString];
NSLog(#"urlstring%#",urlstring);
}];
CLLocationCoordinate2D locationNew = CLLocationCoordinate2DMake( currentLocation.coordinate.latitude, currentLocation.coordinate.longitude) ;
NSDate *nowDate = [NSDate date];
CLLocation *myLocation = [[CLLocation alloc ]initWithCoordinate:locationNew altitude:0.0 horizontalAccuracy:1.0 verticalAccuracy:1.0 timestamp:nowDate];
[[PHPhotoLibrary sharedPhotoLibrary] performChanges:^{
// Create a change request from the asset to be modified.
PHAssetChangeRequest *request = [PHAssetChangeRequest changeRequestForAsset:lastImageAsset];
// Set a property of the request to change the asset itself.
request.location = myLocation;
} completionHandler:^(BOOL success, NSError *error) {
NSLog(#"Finished updating asset. %#", (success ? #"Success." : error));
}];
}
}];
}
else {
//if you aren't running ios8 or newer I haven't found a way to add/change metadata but I will keep looking.So if you leave this blank no new metadata is added.
}
You can add other metadata just create the data in the form needed and then use request.(what you want to change) = new data.
you can check to see if the data already exist and if there is a metadata for it by putting in something like
lastImageAsset (which was the PHAsset fetch result above) and then the property like
NSDate *originalFileDate = [lastImageAsset creationDate]; etc.
there is a list at
https://developer.apple.com/reference/photos/phasset

How to get image from asset library iOS?

I am iOS developer i want to get all images from library, without UIImagepickercontroller,and take first 10 images
Any ideas?
There are lots of example out der which will guide you how to get images from ALAssetLibrary
https://www.cocoacontrols.com/search?q=image+picker.
Below is example to get the latest image from ImagePicker
- (void)latestPhotoWithCompletion:(void (^)(UIImage *photo))completion
{
ALAssetsLibrary *library=[[ALAssetsLibrary alloc] init];
// Enumerate just the photos and videos group by using ALAssetsGroupSavedPhotos.
[library enumerateGroupsWithTypes:ALAssetsGroupSavedPhotos usingBlock:^(ALAssetsGroup *group, BOOL *stop) {
// Within the group enumeration block, filter to enumerate just photos.
[group setAssetsFilter:[ALAssetsFilter allPhotos]];
// For this example, we're only interested in the last item [group numberOfAssets]-1 = last.
if ([group numberOfAssets] > 0) {
[group enumerateAssetsAtIndexes:[NSIndexSet indexSetWithIndex:[group numberOfAssets]-1] options:0
usingBlock:^(ALAsset *alAsset, NSUInteger index, BOOL *innerStop) {
// The end of the enumeration is signaled by asset == nil.
if (alAsset) {
ALAssetRepresentation *representation = [alAsset defaultRepresentation];
// Do something interesting with the AV asset.
UIImage *img = [UIImage imageWithCGImage:[representation fullScreenImage]];
// completion
completion(img);
// we only need the first (most recent) photo -- stop the enumeration
*innerStop = YES;
}
}];
}
} failureBlock: ^(NSError *error) {
// Typically you should handle an error more gracefully than this.
}];
}
Usage
__weak __typeof(self)wSelf = self;
[self latestPhotoWithCompletion:^(UIImage *photo) {
UIImageRenderingMode renderingMode = YES ? UIImageRenderingModeAlwaysOriginal : UIImageRenderingModeAlwaysTemplate;
[wSelf.switchCameraBut setImage:[photo imageWithRenderingMode:renderingMode] forState:UIControlStateNormal];
}];

How to create and save specific photo album using UIActivityViewController in iOS

I want to create custom photo album and save photo to specific album in iOS 7. and I found iOS save photo in an app specific album using ALAssetsLibrary.
But I don't know how to do it using UIActivityViewController.
NSArray* actItems = [NSArray arrayWithObjects: image, nil];
UIActivityViewController *activityView = [[UIActivityViewController alloc]
initWithActivityItems:actItems
applicationActivities:nil];
[activityView setCompletionHandler:^(NSString *activityType, BOOL completed)
{
if ([activityType isEqualToString:UIActivityTypeSaveToCameraRoll])
{
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:NSLocalizedString(#"#Saved_title", nil)
message:NSLocalizedString(#"#Saved_message2", nil)
delegate:self
cancelButtonTitle:NSLocalizedString(#"OK", nil)
otherButtonTitles: nil];
[alert show];
}
}];
I realize the question is a few months old and that the OP may have moved on, but I needed to do exactly this, but didn't find another solution, and needed to come up with my own.
It's not fool-proof, as if there are multiple copies of the video/image in Camera Roll that you're wanting to copy, it will copy all of them, which may or may not be desired. Also, for my purposes, I'm considering maintaining a persistent list of asset URLs that I've written to the custom album so that I skip that asset in the future, but I haven't yet coded it because, if the user removes the video/image from the custom album, it'd be nearly impossible to update that list without more iteration through asset groups: something I'd like to avoid.
Last disclaimer: I haven't tested this a whole ton yet, but it works for my purposes, so hopefully someone else out there can benefit from it.
I augmented Marin Todorov's ALAssetsLibrary+CustomPhotoAlbum category, which I found here: https://github.com/yusenhan/Smooth-Line-View/tree/master/ALAssetsLibrary%2BCustomPhotoAlbum. Note: there is no license information provided there, so I'm assuming that modifying the source for this category is ok.
Here is my method which sets up and displays the UIActivityViewController:
- (void)showActivitySheet:(NSString *)path {
NSURL *newURL = [NSURL fileURLWithPath:path];
NSArray *itemsToShare = #[newURL];
UIActivityViewController *activityVC = [[UIActivityViewController alloc] initWithActivityItems:itemsToShare applicationActivities:nil];
activityVC.excludedActivityTypes = #[UIActivityTypePrint, UIActivityTypeAssignToContact, UIActivityTypeAddToReadingList];
// Once the OS has finished with whatever the user wants to do with it,
// we'll begin figuring out if we need to save it to the Album, too!
[activityVC setCompletionHandler:^(NSString *activityType, BOOL completed) {
// If the user selected "Save to Camera Roll"
if ([activityType isEqualToString:UIActivityTypeSaveToCameraRoll]) {
ALAssetsLibrary *lib = [[ALAssetsLibrary alloc] init];
NSURL *tempUrl = [NSURL fileURLWithPath:path];
// saveMovie: below is a method I added to the category, but you can use saveImage:,
// which you'll also likely want to add some kind of parameter to so, in the category,
// you know when you only want to copy to the Album instead of the Album AND Camera Roll
[lib saveMovie:tempUrl toAlbum:#"CUSTOM ALBUM NAME"
withCompletionBlock:^(NSURL *url, NSError *error) {
if (error) {
NSLog(#"Error writing movie to custom album: %#", error.debugDescription);
}
}
onlyWriteToCustomAlbum:YES];
}
}];
[self presentViewController:activityVC animated:YES completion:nil];
}
Here is code you can add to the saveImage: method in the ALAssetsLibrary+CustomPhotoAlbum category so you can save it to your custom Album, too! You could execute this portion only on the YES case of the BOOL which you'll want to add to the category.
NSData *dataToCompareTo = [NSData dataWithContentsOfURL:url]; // This data represents the image/movie which you want to save into the custom album. The one you handed to the UIActivityViewController.
// Note use of self, as this is a category on ALAssetsLibrary; also, this
// assumes that you've already written the photo to the Camera Roll, which
// should be automatically handled by the OS, if the user hit the "Save" button
// on the UIActivityViewController.
// Enumerate through Camera Roll/Saved Photos group.
[self enumerateGroupsWithTypes:ALAssetsGroupSavedPhotos
usingBlock:^(ALAssetsGroup *group, BOOL *stop) {
// Enumerate the assets in each group.
[group enumerateAssetsUsingBlock:^(ALAsset *result, NSUInteger index, BOOL *stop) {
ALAssetRepresentation *rep = [result defaultRepresentation];
// If the asset isn't the same size as the source image/movie
// it shouldn't be the same. Check the size first, since it
// is a less costly operation than byte checking the data itself.
if ([rep size] == [dataToCompareTo length]) {
Byte *buffer = malloc([NSNumber numberWithLongLong:rep.size].unsignedLongValue);
NSUInteger buffered = [rep getBytes:buffer fromOffset:0.0 length:[NSNumber numberWithLongLong:rep.size].unsignedLongValue error:nil];
NSData *data = [NSData dataWithBytesNoCopy:buffer length:buffered freeWhenDone:YES];
// If the buffer has more than the null-termination char, free it! I'm doing this in case the above call to dataWithBytesNoCopy fails to free() the buffer.
if (sizeof(buffer) > 4) {
free(buffer);
}
// Ensure they are the same by comparing the NSData instances.
if ([data isEqualToData:dataToCompareTo]) {
NSLog(#"they are the same!!");
[self addAssetURL:[rep url]
toAlbum:albumName
withMovieCompletionBlock:completionBlock];
} else {
NSLog(#"they are different");
}
}
}];
} failureBlock:^(NSError *error) {
NSLog(#"Failed to write to custom album!");
}];
Hope it helps! TLDR? Thought so! ;-)

ALAsset - access thumbnail later

I use ALAssetsLibrary to enumerate assets from the photo library but there is one problem. If I'm inside the block (the one for enumeration) I can access the thumbnail image without problem. However if I store the ALAsset in a collection and try to access the thumbnail image at some point later its 0x00000000.
Why this? Is there a better way to access individual images later?
My code works like this:
assets = [[NSMutableArray alloc] init];
ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init];
[library enumerateGroupsWithTypes:ALAssetsGroupAll
usingBlock:assetGroupEnumerator
failureBlock:^(NSError *error) {NSLog(#"bla bla bla ... problem");}];
with
void (^assetGroupEnumerator) (ALAssetsGroup *, BOOL *) = ^(ALAssetsGroup *group, BOOL *stop)
{
if(group != nil)
{
// extract every asset from goup
[group enumerateAssetsUsingBlock:assetEnumerator];
}
};
and
void (^assetEnumerator) (ALAsset *, NSUInteger, BOOL *) = ^(ALAsset *result, NSUInteger index, BOOL *stop) {
[assets addObject:result];
}
I found the problem being the (all to early) release of the ALAssetsLibrary. I should not give it up as long as I need the thumbnails and whatever else and simply keep its reference.

ALAssetLibrary for audio

I am trying to load all the files(audio, video and images) in my application using ALAssetLibrary by this piece of code:
ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init];
[library enumerateGroupsWithTypes:ALAssetsGroupAll usingBlock:^(ALAssetsGroup *group, BOOL *stop) {
// Within the group enumeration block, filter to enumerate everything.
[group setAssetsFilter:[ALAssetsFilter allAssets]];
// Accessing all the assets.
for (int i = 0;i<[group numberOfAssets] ; i++) {
[group enumerateAssetsAtIndexes:[NSIndexSet indexSetWithIndex:i] options:0 usingBlock:^(ALAsset *alAsset, NSUInteger index, BOOL *innerStop) {
// The end of the enumeration is signaled by asset == nil
if (alAsset) {
ALAssetRepresentation *representation = [alAsset defaultRepresentation];
NSURL *url = [representation url];
NSLog(#"%#",url);
AVAsset *avAsset = [AVURLAsset URLAssetWithURL:url options:nil];
//Doing some stuff with assets
}
}];
}
}
failureBlock: ^(NSError *error) {
NSLog(#"No groups");
}];
However, this only loads video and images, not the audio files. How can I do that?
Regarding Apple.Developer ALAsset documentaion ,An ALAsset object represents a photo or a video managed by the Photo application.
Assets can have multiple representations, for example a photo which was captured in RAW and JPG. Different representations of the same asset may have different dimensions.
So i think ,ALAssetsLibrary will not retrieve what you need :)

Resources