We are making a chat app and for video thumbnail we use the following code. But it crashes in random cases.
NSArray *arrjid = [jid componentsSeparatedByString:#"#"];
NSDateFormatter *dateFormatter=[[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:#"yyyyMMddHHmmss"];
NSString *strdate = [dateFormatter stringFromDate:[NSDate date]];
NSString *strname = [NSString stringWithFormat:#"%#_%#_file.mov",arrjid[0],strdate];
NSString *videoPath = [[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) objectAtIndex:0] stringByAppendingPathComponent:strname];
[videoData writeToFile:videoPath atomically:YES];
if([[NSFileManager defaultManager] fileExistsAtPath:videoPath])
{
ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init];
[library writeVideoAtPathToSavedPhotosAlbum:[NSURL fileURLWithPath:videoPath] completionBlock:^(NSURL *assetURL, NSError *error) {
}];
}
Every time it crashes on the writeVideoAtPathToSavedPhotosAlbum line and it gives only "bad access error".
Does anyone have an idea related to this?
ALAssetsLibrary library method writeVideoAtPathToSavedPhotosAlbum:completionBlock: is deprecated, you can use PHPhotoLibrary instead.
try this
[[PHPhotoLibrary sharedPhotoLibrary] performChanges:^{
[PHAssetChangeRequest creationRequestForAssetFromVideoAtFileURL: yourVideoURlHere];
} completionHandler:^(BOOL success, NSError *error) {
if (success) {
//Do Something
}
}];
Also check if you have Photo Library usage description in info plist with following key
NSPhotoLibraryUsageDescription
UPDATE
For fetching thumbnail from video you can use AVAssetImageGenerator class from AVFoundation framework
- (UIImage *) thumbnailFromVideoAtURL:(NSURL *) contentURL {
AVURLAsset *asset = [[AVURLAsset alloc] initWithURL:contentURL options:nil];
AVAssetImageGenerator *generator = [[AVAssetImageGenerator alloc] initWithAsset:asset];
generator.appliesPreferredTrackTransform = YES;
NSError *err = NULL;
CMTime time = CMTimeMake(1, 60);
CGImageRef imgRef = [generator copyCGImageAtTime:time actualTime:NULL error:&err];
UIImage *thumbnail = [[UIImage alloc] initWithCGImage:imgRef];
CGImageRelease(imgRef);
return thumbnail;
}
Make sure you have permission to save to the photo gallery.
Import the Photos class:
#import <Photos/Photos.h>
Then check for Photo Library Authorization
PHAuthorizationStatus status = [PHPhotoLibrary authorizationStatus];
if (status == PHAuthorizationStatusAuthorized) {
//OK to save your video
[self ContinueDownload];
}
else if (status == PHAuthorizationStatusDenied) {
// Access has been denied.
[self ShowAlert];
}
else if (status == PHAuthorizationStatusNotDetermined) {
// Access has not been determined.
[PHPhotoLibrary requestAuthorization:^(PHAuthorizationStatus status) {
if (status == PHAuthorizationStatusAuthorized) {
//OK to save your video
[self ContinueDownload];
}
else {
// Access has been denied.
[self ShowAlert];
}
}];
}
else if (status == PHAuthorizationStatusRestricted) {
// Restricted access
}
//Show an alert if access is denied
-(void)ShowAlert {
UIAlertController * alert = [UIAlertController
alertControllerWithTitle:#"Gallery Access denied"
message:#"You can grant access in\nSettings/Privacy/Photos\nif you change your mind."
preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction* OKButton = [UIAlertAction
actionWithTitle:#"OK"
style:UIAlertActionStyleDefault
handler:^(UIAlertAction * action) {
//[self dismissViewControllerAnimated:YES completion:nil];
}];
[alert addAction:OKButton];
[self presentViewController:alert animated:YES completion:nil];
}
Related
In my app I used edit pic and saved in custom folder in Gallery called "Fab". now is there anything to delete that image from folder? I have found different solution but they require asset URL. I used Photos framework so how to get asset url for particular image for deletion ?
PHAsset *tempPhasset = [_arrImageForAssetCameraRoll objectAtIndex:index]; // here pass your PHasset that you want to delete .
NSString *localStr=tempPhasset.localIdentifier;
NSRange range = [localStr rangeOfString:#"/"];
NSString *newString = [localStr substringToIndex:range.location];
NSString *appendedString=[NSString stringWithFormat:#"%#%#%#",#"assets-library://asset/asset.JPG?id=",newString,#"&ext=JPG"];
NSLog(#"%# phasset ",appendedString);
NSURL *deleteurl = [NSURL URLWithString:appendedString];
NSArray *arrDelete = [[NSArray alloc] initWithObjects:deleteurl , nil];
PHFetchResult *asset = [PHAsset fetchAssetsWithALAssetURLs:arrDelete options:nil];
[asset enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
NSLog(#"%#",[obj class]);
[[PHPhotoLibrary sharedPhotoLibrary] performChanges:^{
BOOL req = [obj canPerformEditOperation:PHAssetEditOperationDelete];
if (req) {
NSLog(#"true");
[PHAssetChangeRequest deleteAssets:#[obj]];
}
} completionHandler:^(BOOL success, NSError *error) {
NSLog(#"Finished Delete asset. %#", (success ? #"Success." : error));
if (success) {
NSLog(#"delete successfully");
}else{
NSLog(#"delete Cancel");
}
}];
Any query about my code then put comment .
Happy Coding.
Try this below code
ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init];
[library writeImageToSavedPhotosAlbum:[viewImage CGImage] orientation:(ALAssetOrientation)[viewImage imageOrientation] completionBlock:^(NSURL *assetURL, NSError *error){
if (error) {
NSLog(#"error");
} else {
NSLog(#"url %#", assetURL);
}
}];
will return url for saved image.
I'm saving a video obtained from AVCaptureVideoDataOutput with AVAsset using writeVideoAtPathToSavedPhotosAlbum like below.
NSString* filename = [NSString stringWithFormat:#"capture%d.mp4", _currentFile];
NSString* path = [NSTemporaryDirectory() stringByAppendingPathComponent:filename];
NSURL* url = [NSURL fileURLWithPath:path];
dispatch_async(dispatch_get_main_queue(), ^{
[_encoder finishWithCompletionHandler:^{
ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init];
[library writeVideoAtPathToSavedPhotosAlbum:url completionBlock:^(NSURL *assetURL, NSError *error){
NSLog(#"save completed");
}];
}];
});
However after saving the video I want to get the 'saved videos info' back like we get with following when using UIImagePickerController.
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info {
[picker dismissViewControllerAnimated:YES completion:NULL];
NSLog(#"there");
// Handle a movie capture
NSString *type = info[UIImagePickerControllerMediaType];
NSURL *videoURL = info[UIImagePickerControllerMediaURL];
//do things with that info
}
Here is the code to save the video and add that video in custom album, and then inform where it has been saved.
[library writeVideoAtPathToSavedPhotosAlbum:videoInputUrl completionBlock:^(NSURL *assetURL, NSError *error){
if (error) {
NSLog(#"Video could not be saved");
}
else{
[library assetForURL:assetURL
resultBlock:^(ALAsset *asset) {
// assign the photo to the album
[groupToAddTo addAsset:asset];
NSLog(#"Added Successfully %# to %#", [[asset defaultRepresentation] filename], albumName);
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Success" message:#"Video Saved to xyz Album." delegate:nil cancelButtonTitle:#"Ok" otherButtonTitles: nil, nil];
[alert show];
}
failureBlock:^(NSError* error) {
NSLog(#"failed to retrieve image asset:\nError: %# ", [error localizedDescription]);
}];
}
}];
Hope this help you...:)
I am using UIImagePickerController in my application to pick up the image. I need to delete this image synchronously from iOS PhotoLibrary after picking it up in my application.
- (BOOL)createAndInsertNewElementFromDictionary:(NSDictionary*)dict
{
AlbumElement *newElement;
if ([dict[UIImagePickerControllerMediaType]
isEqualToString:(NSString*)kUTTypeMovie])
{
NSURL *mediaUrl = dict[UIImagePickerControllerMediaURL];
newElement = [AlbumElement createElementWithMediaUrl:mediaUrl
inAlbum:_album.name];
}
else if ([dict[UIImagePickerControllerMediaType]
isEqualToString:(NSString*)kUTTypeImage])
{
UIImage *image = [dict[UIImagePickerControllerOriginalImage] copy];
newElement = [AlbumElement createElementWithImage:image
inAlbum:_album.name];
}
if (newElement != nil)
{
[_album.elements insertObject:newElement atIndex:0];
UIImage *icon = [UIImage imageWithContentsOfFile:[newElement iconFullPath]];
[AlbumElement writeImageToFileWithImage:icon
atFullPath:_album.albumIconPath];
}
else
{
NSLog(#"Element was NOT added!");
return NO;
}
return YES;
}
NSURL *url = [dict objectForKey:#"UIImagePickerControllerReferenceURL"] ;
PHPhotoLibrary *library = [PHPhotoLibrary sharedPhotoLibrary];
[library performChanges:^{
// Here assetsURLs is array of url's you want to delete
PHFetchResult *assetsToBeDeleted = [PHAsset fetchAssetsWithALAssetURLs:[NSArray arrayWithObject:url] options:nil];
[PHAssetChangeRequest deleteAssets:assetsToBeDeleted];
} completionHandler:^(BOOL success, NSError *error)
{
// Check error and success here
}];
You can do something like this,
-(void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary<NSString *,id> *)info{
NSURL *imgURL = info[UIImagePickerControllerReferenceURL];
[[PHPhotoLibrary sharedPhotoLibrary]performChanges:^{
PHAsset *imageAssetTodelete = [PHAsset fetchAssetsWithALAssetURLs:imgURL options:nil];
[PHAssetChangeRequest deleteAssets:imageAssetTodelete];
} completionHandler:^(BOOL success, NSError * _Nullable error) {
if (error) {
NSLog(#"err description : %#",[error localizedDescription]);
}
if (success) {
NSLog(#"image deleted successfully");
}
}];
}
And don't forget to #import Photos; in your class.
Hope this will help :)
I use the same code like #MOHAMMAD ISHAQ but in my case that not work, the picture are not deleted, I have no any error.
Any help or suggestion please ?
PHAsset *asset = nil;
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) {
// get last photo from Photos
asset = [fetchResult lastObject];
}
if (asset) {
PHContentEditingInputRequestOptions *editOptions = [[PHContentEditingInputRequestOptions alloc] init];
[asset requestContentEditingInputWithOptions:editOptions completionHandler:^(PHContentEditingInput *contentEditingInput, NSDictionary *info) {
if (contentEditingInput.fullSizeImageURL) {
//do something with contentEditingInput.fullSizeImageURL
NSLog(#"¨PATH %#",contentEditingInput.fullSizeImageURL);
NSMutableArray *persons = [[NSMutableArray alloc]initWithCapacity:0];
[persons addObject:contentEditingInput.fullSizeImageURL];
NSArray *myArray = [[NSArray alloc]initWithArray:persons];
PHPhotoLibrary *library = [PHPhotoLibrary sharedPhotoLibrary];
[library performChanges:^{
PHFetchResult *assetsToBeDeleted = [PHAsset fetchAssetsWithALAssetURLs:myArray options:nil];
[PHAssetChangeRequest deleteAssets:assetsToBeDeleted];
} completionHandler:^(BOOL success, NSError *error)
{
//do something here
NSLog(#"DELETE IAMGE");
}];
}
}];
Thank
I am trying to save a base64 image to camera roll and return the url for the saved image. The code works in so far as I have succeeded in saving to camera roll but I am seeing an error and no URL is returned. The error is:
Error Domain=NSCocoaErrorDomain Code=-1 "(null)"
My code is:
- (void)saveImageDataToLibrary:(CDVInvokedUrlCommand*)command
{
__block CDVPluginResult* result = nil;
NSData* imageData = [NSData dataFromBase64String:[command.arguments objectAtIndex:0]];
UIImage* image = [[[UIImage alloc] initWithData:imageData] autorelease];
__block PHObjectPlaceholder *placeholderAsset = nil;
[[PHPhotoLibrary sharedPhotoLibrary] performChanges:^{
PHAssetChangeRequest *newAssetRequest = [PHAssetChangeRequest creationRequestForAssetFromImage:image];
placeholderAsset = newAssetRequest.placeholderForCreatedAsset;
} completionHandler:^(BOOL success, NSError *error) {
if(success){
NSLog(#"worked");
PHAsset *asset = [self getAssetFromlocalIdentifier:placeholderAsset.localIdentifier];
PHContentEditingInputRequestOptions *options = [[PHContentEditingInputRequestOptions alloc] init];
options.networkAccessAllowed = YES; //download asset metadata from iCloud if needed
[asset requestContentEditingInputWithOptions:options
completionHandler:^(PHContentEditingInput *contentEditingInput, NSDictionary *info) {
NSURL *assetURL = contentEditingInput.fullSizeImageURL;
NSString* url = [assetURL absoluteString];
NSLog(#"our result is: %#", url);
result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString:url];
[self invokeCallback:command withResult:result];
}];
} else {
NSLog(#"Error: %#", error);
result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsString:error.description];
[self invokeCallback:command withResult:result];
}
}];
}
- (void) invokeCallback:(CDVInvokedUrlCommand *)command withResult:(CDVPluginResult *)result {
[self.commandDelegate sendPluginResult:result callbackId:command.callbackId];
}
Try to use:
PHContentEditingOutput
That object has a property called: renderedContentURL
Use that to get the appropriate URL of your PHAsset.
So to get the URL, your code should look like this:
PHContentEditingOutput *contentEditingOutput = [[PHContentEditingOutput alloc] initWithContentEditingInput:YOUR_PHCONTENTEDITING_INPUT];
NSURL *myPHAssetURL = [contentEditingOutput renderedContentURL];
This is my code. The file is correctly added to photos library, but in instagram app this url -> instagram://library?AssetPath=assets-library%3A%2F%2Fasset%2Fasset.mp4%3Fid=5EDBD113-FF57-476B-AABB-6A59F31170B5&ext=mp4&InstagramCaption=my%caption don't open the last video.
- (void)loadCameraRollAssetToInstagram:(NSURL*)assetsLibraryURL andMessage:(NSString*)message
{
NSString *escapedString = [self urlencodedString:assetsLibraryURL.absoluteString];
NSString *escapedCaption = [self urlencodedString:message];
NSURL *instagramURL = [NSURL URLWithString:[NSString stringWithFormat:#"instagram://library?AssetPath=%#&InstagramCaption=%#", escapedString, escapedCaption]];
NSLog(#"instagramURL ==> %#",instagramURL);
if ([[UIApplication sharedApplication] canOpenURL:instagramURL]) {
NSLog(#"Open Instagram!!");
[[UIApplication sharedApplication] openURL:instagramURL];
} else {
NSLog(#"Cant open Instagram!!");
[[[UIAlertView alloc] initWithTitle:#"Instagram" message:#"App not installed" delegate:nil cancelButtonTitle:#"Ok" otherButtonTitles:nil, nil] show];
}
}
- (NSString*)urlencodedString:(NSString *)message
{
return [message stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLHostAllowedCharacterSet]];
}
- (void)saveToCameraRoll:(NSURL *)srcURL withCurrentAction:(NSString *)action
{
ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init];
ALAssetsLibraryWriteVideoCompletionBlock videoWriteCompletionBlock = ^(NSURL *newURL, NSError *error) {
if (error) {
NSLog( #"Error writing image with metadata to Photo Library: %#", error );
[[[UIAlertView alloc] initWithTitle:#"Facebook" message:#"Pal - Currently we can't process your video. Please try again in few moments" delegate:self cancelButtonTitle:#"Cancel" otherButtonTitles:#"Sign In", nil] show];
} else {
NSLog( #"Wrote image with metadata to Photo Library: %#", newURL.absoluteString);
if ([action isEqualToString:#"instagram"])
[self loadCameraRollAssetToInstagram:newURL andMessage:#"My caption"]; //Can be any text?
}
};
if ([library videoAtPathIsCompatibleWithSavedPhotosAlbum:srcURL])
{
[library writeVideoAtPathToSavedPhotosAlbum:srcURL completionBlock:videoWriteCompletionBlock];
}
}
something very strange is that worked perfect, until I turned uninstall and then install instagram. Do not know if this has something to do
instagram://library?AssetPath=\(assetsLibraryUrl)
stopped working a while ago. Instagram developers probably moved to Photos framework and no longer use the AssetsLibrary.
Having this assumption I tried several other parameter names and found that instagram://library?LocalIdentifier=\(localID) where localId is the localIdentifier of your PHAsset works for now.
This is still as undocumented as it was so it can break in any future version of the Instagram.
Resuming this task after a long time and considering the borisgolovnev's answer and ALAssetsLibrary is deprecated, the final solution is:
- (void)saveToCameraRollOpt2:(NSURL *)srcURL
{
__block PHAssetChangeRequest *_mChangeRequest = nil;
__block PHObjectPlaceholder *placeholder;
[[PHPhotoLibrary sharedPhotoLibrary] performChanges:^{
NSData *pngData = [NSData dataWithContentsOfURL:srcURL];
UIImage *image = [UIImage imageWithData:pngData];
_mChangeRequest = [PHAssetChangeRequest creationRequestForAssetFromImage:image];
placeholder = _mChangeRequest.placeholderForCreatedAsset;
} completionHandler:^(BOOL success, NSError *error) {
if (success) {
[self loadCameraRollAssetToInstagram:[placeholder localIdentifier]];
}
else {
NSLog(#"write error : %#",error);
[self showAlert:#"Error" msg:#"Error saving in camera roll" action:nil];
}
}];
}
- (void)loadCameraRollAssetToInstagram:(NSString *)localId
{
NSURL *instagramURL = [NSURL URLWithString:[NSString stringWithFormat:#"instagram://library?LocalIdentifier=\%#", localId]];
if ([[UIApplication sharedApplication] canOpenURL:instagramURL]) {
[[UIApplication sharedApplication] openURL:instagramURL options:#{} completionHandler:nil];
} else {
[self showAlert:#"Error" msg:#"Instagram app is not installed" action:nil];
}
}
- (NSString*)urlencodedString:(NSString *)message
{
return [message stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLHostAllowedCharacterSet]];
}
Don't forget
#import <Photos/Photos.h>
Add `NSPhotoLibraryUsageDescription` and `QueriesSchemes` inside .plist file
<key>NSPhotoLibraryUsageDescription</key>
<string>Need permission to access to manage your photos library</string>
<key>LSApplicationQueriesSchemes</key>
<array>
<string>instagram</string>
</array>
#borisgolovnev's solution actually works. You can get the localIdentifier of your last saved video using the code below. Passing it with instagram://library?LocalIdentifier=(localID) opens Instagram with your video selected.
let fetchOptions = PHFetchOptions()
fetchOptions.sortDescriptors = [NSSortDescriptor(key:"creationDate", ascending:false)]
let fetchResult = PHAsset.fetchAssetsWithMediaType(.Video, options: fetchOptions)
if let lastAsset = fetchResult.firstObject as? PHAsset {
self.localIdentifier = lastAsset.localIdentifier
}
use this code
NSURL *instagramURL = [NSURL URLWithString:#"instagram://app"];
if ([[UIApplication sharedApplication] canOpenURL:instagramURL])
{
NSURL *videoFilePath = [NSURL URLWithString:[NSString stringWithFormat:#"%#",[request downloadDestinationPath]]]; // Your local path to the video
NSString *caption = #"Some Preloaded Caption";
ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init];
[library writeVideoAtPathToSavedPhotosAlbum:videoFilePath completionBlock:^(NSURL *assetURL, NSError *error) {
NSString *escapedString = [self urlencodedString:videoFilePath.absoluteString];
NSString *escapedCaption = [self urlencodedString:caption];
NSURL *instagramURL = [NSURL URLWithString:[NSString stringWithFormat:#"instagram://library?AssetPath=%#&InstagramCaption=%#",escapedString,escapedCaption]];
if ([[UIApplication sharedApplication] canOpenURL:instagramURL]) {
[[UIApplication sharedApplication] openURL:instagramURL];
}
}];
}
Instagram will only shows those iamges/videos which are saved at path which you set in instagramURL. That path should be absolute.
If it still not shows then add LSApplicationQueriesSchemes in info.plist file of array, add its item0 as instagram.
Replace
- (NSString*)urlencodedString:(NSString *)message{
return [message stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLHostAllowedCharacterSet]];
}
With
- (NSString*)urlencodedString:(NSString *)message{
return [message stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet alphanumericCharacterSet]];
}
This worked for me!
swift 3 get the latest Identifier simple and fast
var lastIdentifier = ""
let fetchOptions = PHFetchOptions()
fetchOptions.sortDescriptors = [NSSortDescriptor(key:"creationDate", ascending:false)]
let fetchResult = PHAsset.fetchAssets(with: .video, options: fetchOptions)
if let lastAsset: PHAsset = fetchResult.lastObject {
lastIdentifier = lastAsset.localIdentifier
}
Here is code for sharing video on instagram :
May be you need to add condition for substringFromIndex but its working.
- (void)ShareAssetURLvideoToInstagram:(NSURL*)assetsLibraryURL
{
NSMutableDictionary *queryStringDictionary = [[NSMutableDictionary alloc] init];
NSString *strParamater = [assetsLibraryURL.absoluteString substringFromIndex:[assetsLibraryURL.absoluteString rangeOfString:#"?"].location+1];
NSArray *urlComponents = [strParamater componentsSeparatedByString:#"&"];
for (NSString *keyValuePair in urlComponents)
{
NSArray *pairComponents = [keyValuePair componentsSeparatedByString:#"="];
NSString *key = [[pairComponents firstObject] stringByRemovingPercentEncoding];
NSString *value = [[pairComponents lastObject] stringByRemovingPercentEncoding];
[queryStringDictionary setObject:value forKey:key];
}
NSString *mediaId = [queryStringDictionary valueForKey:#"id"];
if (mediaId.length > 0) {
NSURL *instagramURL = [NSURL URLWithString:[NSString stringWithFormat:#"instagram://library?LocalIdentifier=%#",mediaId]];
if ([[UIApplication sharedApplication] canOpenURL:instagramURL]) {
[[UIApplication sharedApplication] openURL:instagramURL];
}
}
}
if ([[UIApplication sharedApplication] canOpenURL:instagramURL]) {
NSLog(#"Open Instagram!!"); //enter code here
[[UIApplication sharedApplication/*<enter your code here>*/] openURL:instagramURL];