how to save an image to my own gallery [duplicate] - ios

I'm creating an iOS 5 app. I want to save a photo to the device.
I want to save the photo to an album specific to my app, so I need to create the album, and then save photos to the album.
I know how to create the album:
ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init];
[library addAssetsGroupAlbumWithName:#"MY APP NAME" resultBlock:^(ALAssetsGroup *group) {
//How to get the album URL?
} failureBlock:^(NSError *error) {
//Handle the error
}];
I want add photos to the new album now, how do I do so? Sample code is greatly appreciated!

You may use the following code just change the name of album :
__weak ALAssetsLibrary *lib = self.library;
[self.library addAssetsGroupAlbumWithName:#"My Photo Album" resultBlock:^(ALAssetsGroup *group) {
///checks if group previously created
if(group == nil){
//enumerate albums
[lib enumerateGroupsWithTypes:ALAssetsGroupAlbum
usingBlock:^(ALAssetsGroup *g, BOOL *stop)
{
//if the album is equal to our album
if ([[g valueForProperty:ALAssetsGroupPropertyName] isEqualToString:#"My Photo Album"]) {
//save image
[lib writeImageDataToSavedPhotosAlbum:UIImagePNGRepresentation(image) metadata:nil
completionBlock:^(NSURL *assetURL, NSError *error) {
//then get the image asseturl
[lib assetForURL:assetURL
resultBlock:^(ALAsset *asset) {
//put it into our album
[g addAsset:asset];
} failureBlock:^(NSError *error) {
}];
}];
}
}failureBlock:^(NSError *error){
}];
}else{
// save image directly to library
[lib writeImageDataToSavedPhotosAlbum:UIImagePNGRepresentation(image) metadata:nil
completionBlock:^(NSURL *assetURL, NSError *error) {
[lib assetForURL:assetURL
resultBlock:^(ALAsset *asset) {
[group addAsset:asset];
} failureBlock:^(NSError *error) {
}];
}];
}
} failureBlock:^(NSError *error) {
}];

For anyone looking to do this as of iOS 9, things have gotten a bit more complicated since the ALAssetsLibrary is deprecated in favor of the new Photos library.
Here's some Swift code for adding UIImages to a specific album name (creating the album if it doesn't exist), you may need to do some refactoring/optimization for your needs:
func insertImage(image : UIImage, intoAlbumNamed albumName : String) {
//Fetch a collection in the photos library that has the title "albumNmame"
let collection = fetchAssetCollectionWithAlbumName(albumName)
if collection == nil {
//If we were unable to find a collection named "albumName" we'll create it before inserting the image
PHPhotoLibrary.sharedPhotoLibrary().performChanges({
PHAssetCollectionChangeRequest.creationRequestForAssetCollectionWithTitle(albumName)
}, completionHandler: {(success : Bool, error : NSError?) in
if error != nil {
print("Error: " + error!.description)
}
if success {
//Fetch the newly created collection (which we *assume* exists here)
let newCollection = self.fetchAssetCollectionWithAlbumName(albumName)
self.insertImage(image, intoAssetCollection: newCollection!)
}
}
)
} else {
//If we found the existing AssetCollection with the title "albumName", insert into it
self.insertImage(image, intoAssetCollection: collection!)
}
}
func fetchAssetCollectionWithAlbumName(albumName : String) -> PHAssetCollection? {
//Provide the predicate to match the title of the album.
let fetchOption = PHFetchOptions()
fetchOption.predicate = NSPredicate(format: "title == '" + albumName + "'")
//Fetch the album using the fetch option
let fetchResult = PHAssetCollection.fetchAssetCollectionsWithType(
PHAssetCollectionType.Album,
subtype: PHAssetCollectionSubtype.AlbumRegular,
options: fetchOption)
//Assuming the album exists and no album shares it's name, it should be the only result fetched
let collection = fetchResult.firstObject as? PHAssetCollection
return collection
}
func insertImage(image : UIImage, intoAssetCollection collection : PHAssetCollection) {
//Changes for the Photos Library must be maded within the performChanges block
PHPhotoLibrary.sharedPhotoLibrary().performChanges({
//This will request a PHAsset be created for the UIImage
let creationRequest = PHAssetCreationRequest.creationRequestForAssetFromImage(image)
//Create a change request to insert the new PHAsset in the collection
let request = PHAssetCollectionChangeRequest(forAssetCollection: collection)
//Add the PHAsset placeholder into the creation request.
//The placeholder is used because the actual PHAsset hasn't been created yet
if request != nil && creationRequest.placeholderForCreatedAsset != nil {
request!.addAssets([creationRequest.placeholderForCreatedAsset!])
}
},
completionHandler: { (success : Bool, error : NSError?) in
if error != nil {
print("Error: " + error!.description)
}
}
)
}

For those looking for Eddy's answer in Objective-C.
#import <Photos/Photos.h>
- (void)insertImage:(UIImage *)image intoAlbumNamed:(NSString *)albumName {
//Fetch a collection in the photos library that has the title "albumNmame"
PHAssetCollection *collection = [self fetchAssetCollectionWithAlbumName: albumName];
if (collection == nil) {
//If we were unable to find a collection named "albumName" we'll create it before inserting the image
[[PHPhotoLibrary sharedPhotoLibrary] performChanges:^{
[PHAssetCollectionChangeRequest creationRequestForAssetCollectionWithTitle: albumName];
} completionHandler:^(BOOL success, NSError * _Nullable error) {
if (error != nil) {
NSLog(#"Error inserting image into album: %#", error.localizedDescription);
}
if (success) {
//Fetch the newly created collection (which we *assume* exists here)
PHAssetCollection *newCollection = [self fetchAssetCollectionWithAlbumName:albumName];
[self insertImage:image intoAssetCollection: newCollection];
}
}];
} else {
//If we found the existing AssetCollection with the title "albumName", insert into it
[self insertImage:image intoAssetCollection: collection];
}
}
- (PHAssetCollection *)fetchAssetCollectionWithAlbumName:(NSString *)albumName {
PHFetchOptions *fetchOptions = [PHFetchOptions new];
//Provide the predicate to match the title of the album.
fetchOptions.predicate = [NSPredicate predicateWithFormat:[NSString stringWithFormat:#"title == '%#'", albumName]];
//Fetch the album using the fetch option
PHFetchResult *fetchResult = [PHAssetCollection fetchAssetCollectionsWithType:PHAssetCollectionTypeAlbum subtype:PHAssetCollectionSubtypeAlbumRegular options:fetchOptions];
//Assuming the album exists and no album shares it's name, it should be the only result fetched
return fetchResult.firstObject;
}
- (void)insertImage:(UIImage *)image intoAssetCollection:(PHAssetCollection *)collection {
[[PHPhotoLibrary sharedPhotoLibrary] performChanges:^{
//This will request a PHAsset be created for the UIImage
PHAssetCreationRequest *creationRequest = [PHAssetCreationRequest creationRequestForAssetFromImage:image];
//Create a change request to insert the new PHAsset in the collection
PHAssetCollectionChangeRequest *request = [PHAssetCollectionChangeRequest changeRequestForAssetCollection:collection];
//Add the PHAsset placeholder into the creation request.
//The placeholder is used because the actual PHAsset hasn't been created yet
if (request != nil && creationRequest.placeholderForCreatedAsset != nil) {
[request addAssets: #[creationRequest.placeholderForCreatedAsset]];
}
} completionHandler:^(BOOL success, NSError * _Nullable error) {
if (error != nil) {
NSLog(#"Error inserting image into asset collection: %#", error.localizedDescription);
}
}];
}

Adaptation of Eddy's answer for Swift 4:
func saveImageToAlbum(_ image: UIImage, name: String) {
if let collection = fetchAssetCollection(name) {
self.saveImageToAssetCollection(image, collection: collection)
} else {
// Album does not exist, create it and attempt to save the image
PHPhotoLibrary.shared().performChanges({
PHAssetCollectionChangeRequest.creationRequestForAssetCollection(withTitle: name)
}, completionHandler: { (success: Bool, error: Error?) in
guard success == true && error == nil else {
NSLog("Could not create the album")
if let err = error {
NSLog("Error: \(err)")
}
return
}
if let newCollection = self.fetchAssetCollection(name) {
self.saveImageToAssetCollection(image, collection: newCollection)
}
})
}
}
func fetchAssetCollection(_ name: String) -> PHAssetCollection? {
let fetchOption = PHFetchOptions()
fetchOption.predicate = NSPredicate(format: "title == '" + name + "'")
let fetchResult = PHAssetCollection.fetchAssetCollections(
with: PHAssetCollectionType.album,
subtype: PHAssetCollectionSubtype.albumRegular,
options: fetchOption)
return fetchResult.firstObject
}
func saveImageToAssetCollection(_ image: UIImage, collection: PHAssetCollection) {
PHPhotoLibrary.shared().performChanges({
let creationRequest = PHAssetCreationRequest.creationRequestForAsset(from: image)
if let request = PHAssetCollectionChangeRequest(for: collection),
let placeHolder = creationRequest.placeholderForCreatedAsset {
request.addAssets([placeHolder] as NSFastEnumeration)
}
}, completionHandler: { (success: Bool, error: Error?) in
guard success == true && error == nil else {
NSLog("Could not save the image")
if let err = error {
NSLog("Error: " + err.localizedDescription)
}
return
}
})
}

Improved version on Objective C, using blocks. It creates an album, if it doesn't exist, then saves three types of media items - photos, gifs and videos:
// Types of media, that can be saved to an album
typedef NS_ENUM(NSUInteger, AlbumMediaType) {
AlbumMediaTypePhoto,
AlbumMediaTypeGIF,
AlbumMediaTypeVideo
};
/**
Creates album if it doesn't exist and returns it in a block
*/
- (void)createCollectionOnComplete:(void (^ _Nonnull)(PHAssetCollection * _Nonnull collection))onComplete
{
NSString *albumTitle = #"YOUR_ALBUM_TITLE";
__block PHAssetCollection *collection;
__block PHObjectPlaceholder *placeholder;
// Searching for an existing album
PHFetchOptions *fetchOptions = [[PHFetchOptions alloc] init];
fetchOptions.predicate = [NSPredicate predicateWithFormat:#"title = %#", albumTitle];
collection = [PHAssetCollection fetchAssetCollectionsWithType:PHAssetCollectionTypeAlbum
subtype:PHAssetCollectionSubtypeAny
options:fetchOptions].firstObject;
// If album is not found, we create it
if (!collection)
{
[[PHPhotoLibrary sharedPhotoLibrary] performChanges:^{
PHAssetCollectionChangeRequest *createAlbum = [PHAssetCollectionChangeRequest creationRequestForAssetCollectionWithTitle:albumTitle];
placeholder = [createAlbum placeholderForCreatedAssetCollection];
} completionHandler:^(BOOL success, NSError *error) {
if (success)
{
PHFetchResult *collectionFetchResult = [PHAssetCollection fetchAssetCollectionsWithLocalIdentifiers:#[placeholder.localIdentifier]
options:nil];
collection = collectionFetchResult.firstObject;
// After creating album, we return it
onComplete(collection);
}
}];
} else {
// If album already exists, we instantly return it
onComplete(collection);
}
}
/**
Saves an item of a given mediatype, that is located in mediaURL
*/
- (void)saveToAlbumMediaItemFromURL:(NSURL *)mediaURL mediaType:(AlbumMediaType)mediaType
{
NSData *mediaData = [NSData dataWithContentsOfURL:mediaURL];
if (!mediaData) {
OWSFail(#"%# Could not load data: %#", self.logTag, [self.attachmentStream mediaURL]);
return;
}
[self createCollectionOnComplete:^(PHAssetCollection * _Nonnull collection) {
[[PHPhotoLibrary sharedPhotoLibrary] performChanges:^{
// We create a PHAsset using creationRequest
PHAssetCreationRequest *assetRequest;
switch (mediaType) {
case AlbumMediaTypePhoto: {
assetRequest = [PHAssetCreationRequest creationRequestForAssetFromImage:[UIImage imageWithData:mediaData]];
break;
}
case AlbumMediaTypeGIF: {
assetRequest = [PHAssetCreationRequest creationRequestForAsset];
PHAssetResourceCreationOptions *options = [[PHAssetResourceCreationOptions alloc] init];
[assetRequest addResourceWithType:PHAssetResourceTypePhoto data:mediaData options:options];
break;
}
case AlbumMediaTypeVideo: {
if ( !UIVideoAtPathIsCompatibleWithSavedPhotosAlbum(mediaURL.path) ) {
OWSFail(#"%# Could not save incompatible video data.", self.logTag);
break;
}
NSString *videoPath = [[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) objectAtIndex:0] stringByAppendingPathComponent:#"file.mov"];
[mediaData writeToFile:videoPath atomically:YES];
assetRequest = [PHAssetCreationRequest creationRequestForAssetFromVideoAtFileURL:[NSURL fileURLWithPath:videoPath]];
break;
}
default:
break;
}
// Creating a request to change an album
PHAssetCollectionChangeRequest *albumChangeRequest = [PHAssetCollectionChangeRequest changeRequestForAssetCollection:collection];
// PHAsset is not created yet, so we use a placeholder
PHObjectPlaceholder *placeholder = [assetRequest placeholderForCreatedAsset];
// We add a placeholder of a created item to the request of changing album
if (albumChangeRequest != nil && placeholder != nil) {
[albumChangeRequest addAssets: #[placeholder]];
}
} completionHandler:^(BOOL success, NSError *error) {
if (success) {
NSLog(#"Media item saved!");
} else {
NSLog(#"Error saving media item - %#", error ? error.localizedDescription : #"");
}
}];
}];
}
We can use these methods to save media items this way:
[self saveToAlbumMediaItemFromURL:[self.attachmentStream mediaURL] mediaType:AlbumMediaTypeGIF];

Related

Multiple images not getting saved in Photo Library by using UIActivityViewController

I need to save multiple images in the photo library, the user can multiple selects the images from the app gallery then can save them in iPhone Photo Gallery. I am showing the UIActivityViewController for the purpose.
Suppose a user selects 10 or more images and choose to save them into photo library then only 7-8 images are saved.
Is there any way by which i can save array of images in the photo library without any failure ?
Thanks
let images = Generic.fetchImagesFromMediaFiles(self.selectedMediaObj) // to fetch selected images
let activityViewController = UIActivityViewController(activityItems: images, applicationActivities: nil)
self.present(activityViewController, animated: true, completion: nil);
if let popoverPresentationController = activityViewController.popoverPresentationController {
popoverPresentationController.sourceView = self.shareAllView
}
iOS system write photo save to album use single thread, one by one to do.
if you want to save more photos same time, it maybe loss some data.
-(void)saveBtn
{
[SSGOTools againRequestPhotoWithblock:^(BOOL isAgree) {
if (isAgree) {
self.listOfImages = [NSMutableArray new];
int photoNum ;
photoNum = (int)_photoArray.count;
if (_photoArray.count > 9) {
photoNum = 9;
}
for (int i = 0; i < photoNum; i++) {
NSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString:_photoArray[i]]];
UIImage *myImage = [UIImage imageWithData:data];
//[self.listOfImages addObject:myImage];
[self loadImageFinished:myImage];
}
}
}];
}
- (void)loadImageFinished:(UIImage *)image
{
[[PHPhotoLibrary sharedPhotoLibrary] performChanges:^{
//write photo save to album
[PHAssetChangeRequest creationRequestForAssetFromImage:image];
} completionHandler:^(BOOL success, NSError * _Nullable error) {
NSLog(#"success = %d, error = %#", success, error);
if(success){
dispatch_async(dispatch_get_main_queue(), ^{
[SSGOTools showInfoPopHint:#"Success"];
});
}
}];
}
you will need to use the completion block here for ensuring all images are saved.. try this :
-(void)saveBtn{
[SSGOTools againRequestPhotoWithblock:^(BOOL isAgree) {
if (isAgree) {
self.listOfImages = [NSMutableArray new];
int photoNum ;
photoNum = (int)_photoArray.count;
if (_photoArray.count > 9) {
photoNum = 9;
}
for (int i = 0; i < photoNum; i++) {
NSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString:_photoArray[i]]];
UIImage *myImage = [UIImage imageWithData:data];
[self.listOfImages addObject:myImage];
// [self loadImageFinished:myImage];
}
[self saveAllImages:self.listOfImages];
}
}];
}
-(void)saveAllImages:(NSMutableArray *)images {
UIImage *image = [images firstObject];
[images removeObject:image];
[self loadImageFinished:image :^(bool success) {
if (success){
if (images.count > 0){
[self saveAllImages:images];
}else{
// all images saved do whatever you want;
}
}else{
NSLog(#"failed saving image");
}
}];
}
- (void)loadImageFinished:(UIImage *)image :(void(^)(bool success))completion{
[[PHPhotoLibrary sharedPhotoLibrary] performChanges:^{
//write photo save to album
[PHAssetChangeRequest creationRequestForAssetFromImage:image];
} completionHandler:^(BOOL success, NSError * _Nullable error) {
NSLog(#"success = %d, error = %#", success, error);
if(success){
dispatch_async(dispatch_get_main_queue(), ^{
[SSGOTools showInfoPopHint:#"Success"];
});
}
completion(success);
}];
}

Check given PHAsset is iCloud asset?

I'm trying to get PhAsset object. I want to segregate iCloud assets. Here is my code,
PHFetchResult *cloudAlbums = [PHAssetCollection fetchAssetCollectionsWithType:PHAssetCollectionTypeAlbum subtype:PHAssetCollectionSubtypeAny options:nil];
[cloudAlbums enumerateObjectsUsingBlock:^(PHAssetCollection *collection, NSUInteger idx, BOOL *stop){
if(collection != nil){
PHFetchResult *result = [PHAsset fetchAssetsInAssetCollection:collection options:fetchOptions];
[result enumerateObjectsUsingBlock:^(PHAsset *asset, NSUInteger idx, BOOL *stop)
{
// check asset is iCloud asset
}];
}
}];
Please tell me how to find the PHAsset is iCloud asset?
It's a bit kind of hack, where I had to dig out the resource array and debug to find out my required information. But it works. Although this is an undocumented code and I'm not sure whether apple will reject the app because of this or not. Give it a try and see what happens!
// asset is a PHAsset object for which you want to get the information
NSArray *resourceArray = [PHAssetResource assetResourcesForAsset:asset];
BOOL bIsLocallayAvailable = [[resourceArray.firstObject valueForKey:#"locallyAvailable"] boolValue]; // If this returns NO, then the asset is in iCloud and not saved locally yet
You can also get some other useful information from asset resource, such as - original filename, file size, file url, etc.
There are actually 2 kinds of situations:
1. The photo is captured by this device, and is uploaded to iCloud. Then, you can use the progressHandler to check whether it needs iCloud download.
__block BOOL isPhotoInICloud = NO;
PHImageRequestOptions *options = [[PHImageRequestOptions alloc] init];
options.networkAccessAllowed = YES;
options.deliveryMode = PHImageRequestOptionsDeliveryModeHighQualityFormat;
options.progressHandler = ^(double progress, NSError *error, BOOL *stop, NSDictionary *info){
isPhotoInICloud = YES;
});
[[PHImageManager defaultManager] requestImageForAsset:asset targetSize:PHImageManagerMaximumSize contentMode:PHImageContentModeAspectFit options:options resultHandler:^(UIImage * _Nullable result, NSDictionary * _Nullable info) {
if (isPhotoInICloud) {
// Photo is in iCloud.
}
});
The photo is in iCloud but uploaded from other device. And you did not save it to your local photo library. So the progressHandler block will never ever be invoked. I don't know why but it's true, and I think it's kind of a bug of PhotoKit framework.
For this situation, if you use the PHImageResultIsInCloudKey, that is also difficult. Because you can know the PHImageResultIsInCloudKey value just in the requestImageForAsset's resultHandler block. But that's the time after the photo request is initiated.
So, at least, in my opinion, there is no way to check whether photo is stored in iCloud.
Maybe there is other better way, please let me know.
Thanks very much!
When you request for an image you get a key in info dictionary which tells you if the asset is present in iCloud.
[cloudAlbums enumerateObjectsUsingBlock:^(PHAssetCollection *collection, NSUInteger idx, BOOL *stop)
{
PHFetchResult *result = [PHAsset fetchAssetsInAssetCollection:collection options:fetchOptions];
[result enumerateObjectsUsingBlock:^(PHAsset *asset, NSUInteger idx, BOOL *stop)
{
PHImageRequestOptions *options = [[PHImageRequestOptions alloc] init];
options.resizeMode = PHImageRequestOptionsResizeModeFast;
options.synchronous = YES;
__block BOOL isICloudAsset = NO;
[[PHImageManager defaultManager] requestImageForAsset:asset targetSize:imageSize contentMode:PHImageContentModeAspectFit options:options resultHandler:^(UIImage *result, NSDictionary *info)
{
if ([info objectForKey: PHImageResultIsInCloudKey].boolValue)
{
isICloudAsset = YES;
}
}];
}];
}];
Here is the Swift 3 version
func checkVideoType(){
if selectedAsset != nil {
guard (selectedAsset.mediaType == .video) else {
print("Not a valid video media type")
return
}
requestID = checkIsiCloud(assetVideo:selectedAsset, cachingImageManager: catchManager)
}
}
func checkIsiCloud(assetVideo:PHAsset,cachingImageManager:PHCachingImageManager) -> PHImageRequestID{
let opt=PHVideoRequestOptions()
opt.deliveryMode = .mediumQualityFormat
opt.isNetworkAccessAllowed=true //iCloud video can play
return cachingImageManager.requestAVAsset(forVideo:assetVideo, options: opt) { (asset, audioMix, info) in
DispatchQueue.main.async {
if (info!["PHImageFileSandboxExtensionTokenKey"] != nil) {
self.iCloudStatus=false
self.playVideo(videoAsset:asset!)
}else if((info![PHImageResultIsInCloudKey]) != nil) {
self.iCloudStatus=true
}else{
self.iCloudStatus=false
self.playVideo(videoAsset:asset!)
}
}
}
}
Following is a method you can implement to acquire all videos in the Videos folder of the Photos app, which uses a predicate with the PHFetchRequest to filter only videos stored on the iPhone itself, and not in iCloud:
// Collect all videos in the Videos folder of the Photos app
- (PHFetchResult *)assetsFetchResults {
__block PHFetchResult *i = self->_assetsFetchResults;
if (!i) {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
PHFetchOptions *fetchOptions = [PHFetchOptions new];
fetchOptions.predicate = [NSPredicate predicateWithFormat:#"(sourceType & %d) != 0", PHAssetSourceTypeUserLibrary];
PHFetchResult *smartAlbums = [PHAssetCollection fetchAssetCollectionsWithType:PHAssetCollectionTypeSmartAlbum subtype:PHAssetCollectionSubtypeSmartAlbumVideos options:fetchOptions];
PHAssetCollection *collection = smartAlbums.firstObject;
if (![collection isKindOfClass:[PHAssetCollection class]]) collection = nil;
PHFetchOptions *allPhotosOptions = [[PHFetchOptions alloc] init];
allPhotosOptions.sortDescriptors = #[[NSSortDescriptor sortDescriptorWithKey:#"creationDate" ascending:NO]];
i = [PHAsset fetchAssetsInAssetCollection:collection options:allPhotosOptions];
self->_assetsFetchResults = i;
});
}
return i;
}
Apple's documentation on PHFetchResult states that only a subset of attributes can be used with a predicate; so, if the above code does not work for you, remove the PHFetchOptions predicate, and replace the corresponding reference in the PHFetchRequest to nil:
// Collect all videos in the Videos folder of the Photos app
- (PHFetchResult *)assetsFetchResults {
__block PHFetchResult *i = self->_assetsFetchResults;
if (!i) {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
PHFetchResult *smartAlbums = [PHAssetCollection fetchAssetCollectionsWithType:PHAssetCollectionTypeSmartAlbum subtype:PHAssetCollectionSubtypeSmartAlbumVideos options:nil];
PHAssetCollection *collection = smartAlbums.firstObject;
if (![collection isKindOfClass:[PHAssetCollection class]]) collection = nil;
PHFetchOptions *allPhotosOptions = [[PHFetchOptions alloc] init];
allPhotosOptions.sortDescriptors = #[[NSSortDescriptor sortDescriptorWithKey:#"creationDate" ascending:NO]];
i = [PHAsset fetchAssetsInAssetCollection:collection options:allPhotosOptions];
self->_assetsFetchResults = i;
});
}
return i;
}
Then, add this line:
// Filter videos that are stored in iCloud
- (NSArray *)phAssets {
NSMutableArray *assets = [NSMutableArray arrayWithCapacity:self.assetsFetchResults.count];
[[self assetsFetchResults] enumerateObjectsUsingBlock:^(PHAsset *asset, NSUInteger idx, BOOL *stop) {
if (asset.sourceType == PHAssetSourceTypeUserLibrary)
[assets addObject:asset];
}];
return [NSArray arrayWithArray:(NSArray *)assets];
}
this code should be work.
If call this code very frequently, make sure cancel useless request by PHImageRequestID.
- (PHImageRequestID)checkIsCloud:(PHAsset *)asset cachingImageManager:(PHCachingImageManager *)cachingImageManager {
if (asset.mediaType == PHAssetMediaTypeVideo) {
PHVideoRequestOptions *options = [PHVideoRequestOptions new];
options.deliveryMode = PHVideoRequestOptionsDeliveryModeMediumQualityFormat;
return [cachingImageManager requestAVAssetForVideo:asset options:options resultHandler:^(AVAsset * _Nullable avAsset, AVAudioMix * _Nullable audioMix, NSDictionary * _Nullable info) {
if (asset != self.asset) return;
dispatch_async(dispatch_get_main_queue(), ^{
if (info[#"PHImageFileSandboxExtensionTokenKey"]) {
self.iCloudStatus = KICloudStatusNone;
} else if ([info[PHImageResultIsInCloudKey] boolValue]) {
self.iCloudStatus = KICloudStatusNormal;
} else {
self.iCloudStatus = KICloudStatusNone;
}
});
}];
} else {
return [cachingImageManager requestImageDataForAsset:asset options:nil resultHandler:^(NSData * _Nullable imageData, NSString * _Nullable dataUTI, UIImageOrientation orientation, NSDictionary * _Nullable info) {
if (asset != self.asset) return;
dispatch_async(dispatch_get_main_queue(), ^{
if ([info[PHImageResultIsInCloudKey] boolValue]) {
self.iCloudStatus = KICloudStatusNormal;
} else {
self.iCloudStatus = KICloudStatusNone;
}
});
}];
}
}

use PhotoEditing Extension to make effects on images

I want to set cropped image in PhotoEditing Extension
I provided that facility for cropping and rotate facility now I want to make that effect on Photos of simulator
// Adjustment data
PHContentEditingOutput *contentEditingOutput = [[PHContentEditingOutput alloc] initWithContentEditingInput:self.input];
NSData *archivedData = [NSKeyedArchiver archivedDataWithRootObject:self.strSelectedFilterName];
PHAdjustmentData *adjustmentData = [[PHAdjustmentData alloc] initWithFormatIdentifier:#"com.test.PhotoEditingExtensionDemo"
formatVersion:#"1.0"
data:archivedData];
contentEditingOutput.adjustmentData = adjustmentData;
switch (self.input.mediaType)
{
case PHAssetMediaTypeImage:
{
// Get full size image
NSURL *url = self.input.fullSizeImageURL;
int orientation = self.input.fullSizeImageOrientation;
// Generate rendered JPEG data
UIImage *image = [UIImage imageWithContentsOfFile:url.path];
image = [self transformedImage:image withOrientation:orientation usingFilter:self.ciFilter];
NSData *renderedJPEGData = UIImageJPEGRepresentation(image, 0.9f);
// Save JPEG data
NSError *error = nil;
BOOL success = [renderedJPEGData writeToURL:contentEditingOutput.renderedContentURL options:NSDataWritingAtomic error:&error];
if (success) {
completionHandler(contentEditingOutput);
} else {
NSLog(#"An error occured: %#", error);
completionHandler(nil);
}
break;
}
case PHAssetMediaTypeVideo: {
// Get AV asset
AAPLAVReaderWriter *avReaderWriter = [[AAPLAVReaderWriter alloc] initWithAsset:self.input.avAsset];
avReaderWriter.delegate = self;
// Save filtered video
[avReaderWriter writeToURL:contentEditingOutput.renderedContentURL
progress:^(float progress) {
}
completion:^(NSError *error) {
if (!error) {
completionHandler(contentEditingOutput);
} else {
NSLog(#"An error occured: %#", error);
completionHandler(nil);
}
}];
break;
}
default:
break;
}

UIImagePickerControllerReferenceURL always returns nill

I am trying to get the name of the image which I have just captured from camera with following code. But [info objectForKey:#"UIImagePickerControllerReferenceURL"] always returning nil. How can I get the URL?
- (void)imagePickerController:(UIImagePickerController *)picker
didFinishPickingMediaWithInfo:(NSDictionary *)info {
self.myinfo = info;
NSLog(#"Dismissing camera ui...");
[self.cameraUI dismissViewControllerAnimated:YES completion:nil];
NSLog(#"Getting media url...");
NSString *mediaURL = [info objectForKey:UIImagePickerControllerMediaURL];
NSLog(#"Media url = %#", mediaURL);
NSLog(#"Getting media type...");
NSString *mediaType = [info objectForKey:UIImagePickerControllerMediaType];
NSLog(#"Selected mediaType: %#", mediaType);
if(mediaURL) {
NSLog(#"This is a video = %#", mediaURL);
if (![mediaType isEqualToString:(NSString*)kUTTypeVideo]) {
UISaveVideoAtPathToSavedPhotosAlbum(mediaURL, self, #selector(video:didFinishSavingWithError:contextInfo:), NULL);
}
} else {
NSLog(#"This is a photo...");
self.originalImage = (UIImage *) [info objectForKey:UIImagePickerControllerOriginalImage];
if (self.source == UIImagePickerControllerSourceTypeCamera && [mediaType isEqualToString:(NSString*)kUTTypeImage]) {
// Image captured from camera
NSLog(#"Saving new image...");
if (self.source != UIImagePickerControllerSourceTypePhotoLibrary) {
UIImageWriteToSavedPhotosAlbum(self.originalImage, self,
#selector(image:didFinishSavingWithError:usingContextInfo:), nil);
}
}
// Image selected from previous images.
else {
NSLog(#"Getting reference url...");
self.referenceURL = [info objectForKey:#"UIImagePickerControllerReferenceURL"];
NSLog(#"Reference url = %#", [self.referenceURL absoluteString]);
[self saveAssetData:self.originalImage :info];
}
}
}
- (void)image:(UIImage *)image
didFinishSavingWithError:(NSError *)error
usingContextInfo:(void*)ctxInfo {
if (error) {
NSLog(#"Resim kaydedilemedi: %#", [error localizedDescription]);
NSString *title = #"Resim kaydedilemedi!";
NSString* message = #"Resim kaydedilirken hata oluştu!";
[self alertStatus:message:title];
} else {
NSLog(#"Save asset data...");
[self saveAssetData:image :self.myinfo];
}
}
- (void)saveAssetData:(UIImage*)originalImage :(NSDictionary*)info {
self.assetLibrary = [[ALAssetsLibrary alloc] init];
NSURL *url = [info objectForKey:#"UIImagePickerControllerReferenceURL"];
ALAssetsLibraryAssetForURLResultBlock resultblock = ^(ALAsset *asset)
{
ALAssetRepresentation *assetRep = [asset defaultRepresentation];
NSString *filename = [assetRep filename];
NSLog(#"File name = %#", filename);
if(self.selectedMediaNames == nil)
self.selectedMediaNames = [[NSMutableArray alloc] init];
[self.selectedMediaNames addObject:filename];
[self.tableView reloadData];
[self.activitIndicator stopAnimating];
[self.activitIndicator setHidden:true];
HMXSharedDataManager *sharedDataManager =
[HMXSharedDataManager sharedManager];
[sharedDataManager.uploaMedias addObject:originalImage];
[sharedDataManager.uploaMediaNames addObject:filename];
};
ALAssetsLibraryAccessFailureBlock failureblock = ^(NSError *error)
{
NSLog(#"%#", error);
};
[self.assetLibrary assetForURL:url resultBlock:resultblock failureBlock:failureblock];
}
UPDATE:
It is a little bit late but here how I get the name of the image or video:
Check UIImagePickerControllerMediaURL, if it is null the media is an image if not it is a video
If the image or the video is just taken or recorded save it to photos album
Use ALAssetsLibrary to query file name.
Here is the code for saving and getting media:
- (void)imagePickerController:(UIImagePickerController *)picker
didFinishPickingMediaWithInfo:(NSDictionary *)info {
#try {
[self.cameraUI dismissViewControllerAnimated:YES completion:nil];
mediaURL = [info objectForKey:UIImagePickerControllerMediaURL];
// If mediaURL is not null this should be a video
if(mediaURL) {
// This video is new just recorded with camera
if (self.source == UIImagePickerControllerSourceTypeCamera) {
// First save the video to photos album
ALAssetsLibrary *library = [ALAssetsLibrary new];
[library writeVideoAtPathToSavedPhotosAlbum:mediaURL completionBlock:^(NSURL *assetURL, NSError *error){
if (error) {
DDLogDebug(#"Failed to save the photo to photos album...");
} else {
// Get the name of the video
[self getMediaName:nil url:assetURL];
}
}];
} else { // This is a video that recorded before
// Get the name of the video
[self getMediaName:nil url:[info objectForKey:UIImagePickerControllerReferenceURL]];
}
}
// This is an image
else {
self.originalImage = (UIImage*)[info objectForKey:UIImagePickerControllerOriginalImage];
// This image is new just taken with camera
if (self.source == UIImagePickerControllerSourceTypeCamera) {
// First save the image to photos album
ALAssetsLibrary *library = [ALAssetsLibrary new];
[library writeImageToSavedPhotosAlbum:[self.originalImage CGImage]
orientation:(ALAssetOrientation)[self.originalImage imageOrientation]
completionBlock:^(NSURL *assetURL, NSError *error){
if (error) {
DDLogDebug(#"Failed to save the vide to photos album...");
} else {
// Get the name of the image
[self getMediaName:self.originalImage url:assetURL];
}
}];
} else { // This is an image that taken before
// Get the name of the image
[self getMediaName:self.originalImage
url:[info objectForKey:#"UIImagePickerControllerReferenceURL"]];
}
}
}
#catch (NSException *exception) {
DDLogError(#"%#", [exception description]);
}
}
Actual method that gets the media name:
- (void)getMediaName:(UIImage*)originalImage url:(NSURL*)url {
#try {
ALAssetsLibraryAssetForURLResultBlock resultblock = ^(ALAsset *asset) {
if (asset == nil) return;
ALAssetRepresentation *assetRep = [asset defaultRepresentation];
NSString *fileName = [assetRep filename];
// Do what you need with the file name here
};
ALAssetsLibraryAccessFailureBlock failureblock = ^(NSError *error) {
DDLogError(#"Failed to get image or video name : %#", error);
};
ALAssetsLibrary *library = [ALAssetsLibrary new];
[library assetForURL:url resultBlock:resultblock failureBlock:failureblock];
}
#catch (NSException *exception) {
DDLogError(#"%#", [exception description]);
}
}
The image that you capture with the camera from within the application has no name. It is always nil. You have to programmatically save that image in the photo gallery and you can save with any name you want.
Put the following code in didFinishPickingMediaWithInfo:
NSURL *mediaUrl;
NSString *imageURLString;
self.selectImage = [info valueForKey:UIImagePickerControllerEditedImage];
if (mediaUrl == nil) {
if (self.selectImage == nil) {
self.selectImage = [info valueForKey:UIImagePickerControllerOriginalImage];
DebugLog(#"Original image picked.");
}else {
DebugLog(#"Edited image picked.");
}
}
mediaUrl = (NSURL *)[info valueForKey:UIImagePickerControllerMediaURL];
imageURLString=[mediaUrl absoluteString];
DebugLog(#"Hi Image URL STRING : - %#",imageURLString);
if ([StringUtils string:imageURLString contains:#"PNG"] || [StringUtils string:imageURLString contains:#"png"]) {
self.isJPG = NO;
self.profileImageName = #"profileImageName.png";
} else if ([StringUtils string:imageURLString contains:#"JPG"] || [StringUtils string:imageURLString contains:#"jpg"]) {
self.isJPG = YES;
self.profileImageName = #"profileImageName.jpg";
}
When you set camera for kUTTypeMovie , then only you will get referenceurl and mediaurl. It will return null for kUTTypeImage.
For Xamarin.iOS developers: store image capture from camera and get its data using ALAssetsLibrary
var originalImage = e.Info[UIImagePickerController.OriginalImage] as UIImage;
var meta = e.Info[UIImagePickerController.MediaMetadata] as NSDictionary;
//Get image bytes
if (originalImage != null)
{
using (NSData imageData = originalImage.AsPNG())
{
myByteArray = new Byte[imageData.Length];
System.Runtime.InteropServices.Marshal.Copy(imageData.Bytes, myByteArray, 0, Convert.ToInt32(imageData.Length));
}
//This bit of code saves image to the Photo Album with metadata
ALAssetsLibrary library = new ALAssetsLibrary();
library.WriteImageToSavedPhotosAlbum(originalImage.CGImage, meta, (assetUrl, error) =>
{
library.AssetForUrl(assetUrl, delegate (ALAsset asset)
{
ALAssetRepresentation representation = asset.DefaultRepresentation;
if (representation != null)
{
string fileName = representation.Filename;
var filePath = assetUrl.ToString();
var extension = filePath.Split('.')[1].ToLower();
var mimeData = string.Format("image/{0}", extension);
var mimeType = mimeData.Split('?')[0].ToLower();
var documentName = assetUrl.Path.ToString().Split('/')[1];
}
}, delegate (NSError err) {
Console.WriteLine("User denied access to photo Library... {0}", err);
});
});
}

How set images to many UIImageView asynchronously?

We try asynchronously load images from photo album to different UIImageView. But now, after big delay all images load together.
- (void)loadAllAssetWithHandler:(void (^)(ALAsset *))hanlderAssetDidLoad
{
ALAssetsLibraryAccessFailureBlock blockFailure = ^(NSError *error){
NSLog(#"ERROR = %#", error.description);
};
ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init];
void (^assetGroupEnumerator)(ALAssetsGroup *, BOOL *) = ^(ALAssetsGroup *group, BOOL *stop)
{
if (group == nil) {
return;
}
if([[group valueForProperty:ALAssetsGroupPropertyName] isEqualToString: #"album"])
{
[group enumerateAssetsUsingBlock:^(ALAsset *asset, NSUInteger index, BOOL *stop)
{
if(asset == nil) {
return;
}
hanlderAssetLoad(asset);
}];
return;
}
};
// Enumerate Albums
[library enumerateGroupsWithTypes: ALAssetsGroupAll
usingBlock: assetGroupEnumerator
failureBlock: blockFailure];
[library release];
}
And
[self loadAllAssetsWithHandlert:^(ALAsset *asset) {
UIImageView *imageView = [self nextImageVIew];
imageView.image = [UIImage imageWithCGImage: asset.defaultRepresentation.fullResolutionImage]; //or thumbnail
}];
So, how do we make pictures uploaded to the UIImageView by turns (immediately after each upload) ?

Resources