Obj-C Check if image already exists in Photos gallery - ios

In my app I have to implement save image feature. I have managed saving like this:
UIImage *image = [UIImage imageNamed:actualBackground];
UIImageWriteToSavedPhotosAlbum(
image, self,
#selector(thisImage:hasBeenSavedInPhotoAlbumWithError:usingContextInfo:),
nil);
/* ... */
- (void)thisImage:(UIImage *)image
hasBeenSavedInPhotoAlbumWithError:(NSError *)error
usingContextInfo:(void *)ctxInfo {
if (!error){
UIImagePickerController *picker = [[UIImagePickerController alloc] init];
[self presentViewController:picker animated:YES completion:nil];
}
}
Unfortunately I have to check if file already exists to prevent redundant saving. Also this is necessary because saving multiple times the same image don't override one file, but it creates copy of it...
Do you know how to solve that problem?
SOLUTION:
According to Shravya Boggarapu answer I'm storing assetUrl in my NSUserDefaults. Complete code:
- (IBAction)onDownloadClick:(UIButton *)sender {
UIImage *image = [UIImage imageNamed:actualBackground];
NSString *key = [NSString stringWithFormat:#"assetsUrl %#", actualBackground];
NSString *savedValue =
[[NSUserDefaults standardUserDefaults] stringForKey:key];
NSURL *url = [NSURL URLWithString:savedValue];
if (url != nil) {
PHFetchResult *fetch =
[PHAsset fetchAssetsWithALAssetURLs:[NSArray arrayWithObject:url]
options:nil];
if ([fetch count]) {
UIAlertView *myAlert = [[UIAlertView alloc]
initWithTitle:nil
message:NSLocalizedString(#"Already downloaded", nil)
delegate:self
cancelButtonTitle:#"OK"
otherButtonTitles:nil];
[myAlert show];
return;
}
}
ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init];
[library
writeImageToSavedPhotosAlbum:image.CGImage
orientation:(ALAssetOrientation)image.imageOrientation
completionBlock:^(NSURL *assetURL, NSError *error) {
[library assetForURL:assetURL
resultBlock:^(ALAsset *asset) {
NSLog(#"assetURL %#", assetURL);
NSString *ass = [assetURL absoluteString];
[[NSUserDefaults standardUserDefaults]
setObject:ass
forKey:key];
[[NSUserDefaults standardUserDefaults] synchronize];
UIAlertView *myAlert = [[UIAlertView alloc]
initWithTitle:nil
message:NSLocalizedString(
#"Image downloaded", nil)
delegate:self
cancelButtonTitle:#"OK"
otherButtonTitles:nil];
[myAlert show];
}
failureBlock:^(NSError *error){
}];
}];
}
Hope it will help somebody.

I have a solution but not one that applies to every situation.
The thing about saving image to camera roll is that there is an assetURL created when you add the image to camera roll. Also, this asset URL is new every time, so if you save to camera roll, it will create a copy. The name of the image is also not retained.
If the image is added to the camera roll through your app in the first place, then you can store the assetURL as part of image information.
In my app, a dictionary is maintained for every image containing some critical info. This includes the assetURL of the image if it is saved to camera roll.
Once you have the URL, you can check its existence by using fetchAssetsWithALAssetURLs:options: function.
If the URL is nil or the asset when fetched is nil, it means that the image does not exist in the camera roll. So you can add anew.

There is no easy way to compare two images and if you found one that will surly a heavy task, instead of this we can compare image's meta data which we can write it to image and also read it from images.
You can use this repo for that
And ALAssetLibrary also have some properties to access an images meta info. If you google with this you will surly get some.
Like this one

Related

memory increase use UIImagePickerController to take photo and save to user's album

I'm using MWPhotoBrowser to display my photos taken by UIImagePickerController.
Here is my code for saving to user's album.
-(void)imagePickerController:(UIImagePickerController *)pickerdidFinishPickingMediaWithInfo:(NSDictionary *)info
{
// NSDictionary* metadata=info[UIImagePickerControllerMediaMetadata];
// [[PHPhotoLibrary sharedPhotoLibrary]performChanges:^{
// NSURL* url=info[UIImagePickerControllerReferenceURL];
// PHAssetChangeRequest* assetChangeReques= [PHAssetChangeRequest creationRequestForAssetFromImageAtFileURL:url];
// PHAssetCollectionChangeRequest* request=[PHAssetCollectionChangeRequest changeRequestForAssetCollection:self.assetCollection];
// [request addAssets:#[[assetChangeReques placeholderForCreatedAsset]]];
// }completionHandler:^(BOOL success,NSError* error){
// if (success) {
// // self.previewImgView.image=image;
// }
// }];
ALAssetsLibrary* alassetsLibary=[[ALAssetsLibrary alloc] init];
[alassetsLibary saveImageData:UIImageJPEGRepresentation(info[UIImagePickerControllerOriginalImage], 1.0f) toAlbum:self.assetCollection.localizedTitle metadata:info[UIImagePickerControllerMediaMetadata] completion:^(NSURL* assetUrl,NSError* error)
{
}failure:^(NSError* error){
}];
self.previewImgView.image=[info[UIImagePickerControllerOriginalImage] getThumbnailWithSize:self.previewImgView.bounds] ;
alassetsLibary=nil;
info=nil;
}
I have used to ways to save the photo above. But it can't handle the problem same as yours.
In the second method. I have tried to change the UIImageJPEGRepresentation parameter from 0.1 to 1.0. But it did't work.
I have try to let alassetsLibary=nil; info=nil; But when I open the photoBrowser. The memory increase so fast.
If anybody has solution,please tell me!!
And I wondering how Apple handle with this issue in native camera app as well.
Gratitude.
I always use this to save pics to the album:
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info {
ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init];
[library writeImageToSavedPhotosAlbum:((UIImage *)[info objectForKey:UIImagePickerControllerEditedImage]).CGImage
metadata:[info objectForKey:UIImagePickerControllerMediaMetadata]
completionBlock:^(NSURL *assetURL, NSError *error) {
NSLog(#"assetURL %#", assetURL);
imageURL=[assetURL absoluteString];
//save URL for future use
[[NSUserDefaults standardUserDefaults] setObject:imageURL forKey:#"imageurl"];
}];
[picker dismissViewControllerAnimated:YES completion:NULL];
}

how could i download an image into document file in iphone simulator and display it again by it's path in UIImageView?

i wanna download an image in my document file and display it again using image path in the document file
how could i download an image into document file in iphone simulator and display it again by it's path in UIImageView?
For downloading the image you can use this code
- (IBAction) downloadImg : (id) sender {
UIImageWriteToSavedPhotosAlbum(largeImg.image, self, #selector(image:didFinishSavingWithError:contextInfo:), nil);
}
- (void) image:(UIImage*)image didFinishSavingWithError:(NSError *)error contextInfo:(NSDictionary*)info
{
if (error != NULL)
{
[[[UIAlertView alloc] initWithTitle:nil message:#"Some error has been occured.\n Please try again later" delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil] show];
}
else
{
[[[UIAlertView alloc] initWithTitle:nil message:#"Image saved successfully\n in your gallery." delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil] show];
}
}
}
Try this code may be it's help you.
NSString * documentsDirectoryPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSData * data = [NSData dataWithContentsOfURL:[NSURL URLWithString:#"http://www.webdesignmash.com/trial/wp-content/uploads/2010/06/why-i-love-typography1.jpg"]]; // it's just example url no use to personally.
UIImage *imageFromURL = [UIImage imageWithData:data];
[UIImagePNGRepresentation(imageFromURL) writeToFile:[documentsDirectoryPath stringByAppendingPathComponent:[NSString stringWithFormat:#"%#.png", #"Test"]] options:NSAtomicWrite error:nil];
UIImage * imageFromWeb = [UIImage imageWithContentsOfFile:[NSString stringWithFormat:#"%#/%#.png", documentsDirectoryPath, #"Test"]];
img.image=imageFromWeb; // img is your imageview
Some information to help you to understood this code like:
1) Test : You can change your image name insted of "Test".
2). Image URL :- You can add your image URL.
3). img : it's your UIImageView name Like this (IBOutlet UIImageView *img;)
Note:- Show image in your UIImageview may be take few times so wait for it. or integrate Loader.

Sharing video with airdrop

I am having some trouble in sharing videos with airdrop. So, i am using the AssetLibrary like this :
else if (conformsToVideo) {
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Asset Loaded" message:#"Video One Loaded"
delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil];
[alert show];
self.mediaAsset = [AVAsset assetWithURL:[info objectForKey:UIImagePickerControllerMediaURL]];
UIActivityViewController * controller = [[UIActivityViewController alloc] initWithActivityItems:#[self.mediaAsset] applicationActivities:nil];
[self presentViewController:controller animated:YES completion:nil];
}
Maybe this is just not the way to do it, I don't know and I didn't find any tutorial about it so if you have one, I will gladly take it.
Now my problem is that when i select a video everything works fine until the UIActivityViewController pops out , i don't have any error but I can't use airdrop (nor any other service BTW) the only thing I can do is press the Cancel button of the UIAVController.
I am using iOS 8.3.
Thanks for your help
Ok, eventually I found an answer, maybe not the best but I put it there in case it helps someone cause I didn't find much on sharing video with airdrop :
NSURL * path = [info objectForKey:UIImagePickerControllerReferenceURL];
BOOL conformsToVideo = (UTTypeConformsTo((__bridge_retained CFStringRef) mediaType, kUTTypeAudiovisualContent));
if (conformsToVideo) {
[self.library assetForURL:path
resultBlock:^(ALAsset *asset) {
ALAssetRepresentation* assetRepresentation = [asset defaultRepresentation];
NSString* outputDirectory = [NSString stringWithFormat:#"%#", NSTemporaryDirectory()];
NSString* pathToCopy = [outputDirectory stringByAppendingPathComponent:[NSString stringWithFormat:#"%#", assetRepresentation.filename]];
NSUInteger size = (NSUInteger)assetRepresentation.size;
NSMutableData* data = [NSMutableData dataWithLength:size];
NSUInteger bytesRead = [assetRepresentation getBytes:data.mutableBytes fromOffset:0 length:size error:nil];
NSURL * url = nil;
if ([data writeToFile:pathToCopy atomically:YES])
{
NSLog(#"Ok");
url = [NSURL fileURLWithPath:pathToCopy];
UIActivityViewController * controller = [[UIActivityViewController alloc] initWithActivityItems:#[url] applicationActivities:nil];
[self presentViewController:controller animated:YES completion:nil];
}
} failureBlock:^(NSError *error) {
NSLog(#"Failure to use the ALAsset");
}
];
}
I found the solution using this question : Share a video from asset library with AirDrop fails
I am merely adding the previous steps to the code given there, hope it can be useful.

Can't edit photo metadata using AssetsLibrary in iOS 8.3 (worked in 8.2)

My app takes pictures, saves them to the camera roll, and allows the modification of the EXIF metadata.
I use the AssetsLibrary to save and modify the photo (I can't use the new PhotoKit api because I need to modify the underlying EXIF, plus it's a legacy app and would require a lot of refactoring to change it).
I am using Xcode 6.3.1, with the iOS 8.3 SDK, deployment target of 6.1.
In iOS 8.2, all this worked.
In iOS 8.3, the editing of the metadata fails.
The app has permission in the Privacy settings to access Photos.
When a user modifies the photos, and the app tries to rewrite the photo, iOS 8.3 now shows the "Allow App to modify this photo" dialog. This dialog did not appear in iOS 8.2. If I click "Modify", the photo is saved, but the metadata is wiped. There is also no error returned from setImageData, and I check if the photo is editable.
Here is the code:
-(void)savePhoto:(ALAsset*)asset
{
ALAssetRepresentation* rep = [asset defaultRepresentation];
CGImageRef imageRef = [rep fullResolutionImage];
UIImage *image = [UIImage imageWithCGImage:imageRef];
NSData *imageData = UIImageJPEGRepresentation(image, 1.0);
if ([asset isEditable])
{
[asset setImageData:imageData metadata:self.getMetadataDictionary completionBlock:^(NSURL *assetURL, NSError *error)
{
if (error!=nil)
[self showErrorDialog:error title:#"Error saving photo" ];
[self closeSaveDialog];
}];
}
else
{
[self closeSaveDialog];
UIAlertView* alertView = [[UIAlertView alloc] initWithTitle:#"Error saving photo" message:#"Photo is not editable" delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil];
[alertView show];
}
}
When debugging this, I noticed a bug in my code where the photo size was being increased by 4x by the UIImageJPEGRepresentation, because it was resampling the photo, so I changed the code to grab the original image bytes, and just rewrite the metadata. But interestingly, I get a different error back, this time setImageData returns this error.
Description : "User denied access".
Underlying error : "ALAssetsLibraryErrorDomain" Code -3311.
FailureReason : "The user has denied the application access to their media".
Which is strange, because the app created the asset, and it has acccess to the camera roll.
Again, this code works in iOS 8.2:
-(void)savePhoto:(ALAsset*)asset
{
ALAssetRepresentation* rep = [asset defaultRepresentation];
// New way handling updating photos, doesn't modify image data at all, only metadata
Byte *buffer = (Byte*)malloc((unsigned long)rep.size);
NSUInteger buffered = [rep getBytes:buffer fromOffset:0.0 length:(NSUInteger)rep.size error:nil];
NSData *imageData = [NSData dataWithBytesNoCopy:buffer length:buffered freeWhenDone:YES];
if ([asset isEditable])
{
[asset setImageData:imageData metadata:self.getMetadataDictionary completionBlock:^(NSURL *assetURL, NSError *error)
{
if (error!=nil)
[self showErrorDialog:error title:#"Error saving photo" ];
[self closeSaveDialog];
}];
}
else
{
[self closeSaveDialog];
UIAlertView* alertView = [[UIAlertView alloc] initWithTitle:#"Error saving photo" message:#"Photo is not editable" delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil];
[alertView show];
}
}
I submitted a bug report to Apple, but havn't heard anything back.
This is similar to this question : setImageData fails in iOS 8.3
Does anyone know of a fix for this?
Thanks,

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! ;-)

Resources