iPhone - How to create a custom album and give custom names to photos in camera roll programmatically?

后端 未结 6 1344
孤城傲影
孤城傲影 2020-12-08 01:10

I am developing an iPhone photo application, so i need to create a separate album with a name \"My Album\" in camera roll and i need to save my UIImageView image with custom

相关标签:
6条回答
  • 2020-12-08 01:52

    It was working from since iOS 5.0.
    Please import AssetsLibrary/AssetsLibrary.h

    ALAssetsLibrary* libraryFolder = [[ALAssetsLibrary alloc] init];
    [libraryFolder addAssetsGroupAlbumWithName:@"My Album" resultBlock:^(ALAssetsGroup *group) 
    {
        NSLog(@"Adding Folder:'My Album', success: %s", group.editable ? "Success" : "Already created: Not Success");
    } failureBlock:^(NSError *error) 
    {
        NSLog(@"Error: Adding on Folder");
    }];
    
    0 讨论(0)
  • 2020-12-08 01:55

    Create a new album:

    /// Create album with given title
    /// - Parameters:
    ///   - title: the title
    ///   - completionHandler: the completion handler
    func createAlbum(withTitle title: String, completionHandler: @escaping (PHAssetCollection?) -> ()) {
        DispatchQueue.global(qos: .background).async {
            var placeholder: PHObjectPlaceholder?
            
            PHPhotoLibrary.shared().performChanges({
                let createAlbumRequest = PHAssetCollectionChangeRequest.creationRequestForAssetCollection(withTitle: title)
                placeholder = createAlbumRequest.placeholderForCreatedAssetCollection
            }, completionHandler: { (created, error) in
                var album: PHAssetCollection?
                if created {
                    let collectionFetchResult = placeholder.map { PHAssetCollection.fetchAssetCollections(withLocalIdentifiers: [$0.localIdentifier], options: nil) }
                    album = collectionFetchResult?.firstObject
                }
                
                completionHandler(album)
            })
        }
    }
    

    Get an album with with a specified name:

    /// Get album with given title
    /// - Parameters:
    ///   - title: the title
    ///   - completionHandler: the completion handler
    func getAlbum(title: String, completionHandler: @escaping (PHAssetCollection?) -> ()) {
        DispatchQueue.global(qos: .background).async { [weak self] in
            let fetchOptions = PHFetchOptions()
            fetchOptions.predicate = NSPredicate(format: "title = %@", title)
            let collections = PHAssetCollection.fetchAssetCollections(with: .album, subtype: .any, options: fetchOptions)
            
            if let album = collections.firstObject {
                completionHandler(album)
            } else {
                self?.createAlbum(withTitle: title, completionHandler: { (album) in
                    completionHandler(album)
                })
            }
        }
    }
    

    And save a photo to a Photos album:

    func save(photo: UIImage, toAlbum titled: String, completionHandler: @escaping (Bool, Error?) -> ()) {
        getAlbum(title: titled) { (album) in
            DispatchQueue.global(qos: .background).async {
                PHPhotoLibrary.shared().performChanges({
                    let assetRequest = PHAssetChangeRequest.creationRequestForAsset(from: photo)
                    let assets = assetRequest.placeholderForCreatedAsset
                        .map { [$0] as NSArray } ?? NSArray()
                    let albumChangeRequest = album.flatMap { PHAssetCollectionChangeRequest(for: $0) }
                    albumChangeRequest?.addAssets(assets)
                }, completionHandler: { (success, error) in
                    completionHandler(success, error)
                })
            }
        }
    }
    
    0 讨论(0)
  • 2020-12-08 02:06

    You can try My below Method for Create Album for iOS 7 and iOS 8

    #define PHOTO_ALBUM_NAME @"AlbumName Videos"
    -(void)createAlbum{
    
    // PHPhotoLibrary_class will only be non-nil on iOS 8.x.x
    Class PHPhotoLibrary_class = NSClassFromString(@"PHPhotoLibrary");
    
    if (PHPhotoLibrary_class) {
    
    
        // iOS 8..x. . code that has to be called dynamically at runtime and will not link on iOS 7.x.x ...
    
        [[PHPhotoLibrary sharedPhotoLibrary] performChanges:^{
            [PHAssetCollectionChangeRequest creationRequestForAssetCollectionWithTitle:PHOTO_ALBUM_NAME];
        } completionHandler:^(BOOL success, NSError *error) {
            if (!success) {
                NSLog(@"Error creating album: %@", error);
            }else{
                NSLog(@"Created");
            }
        }];
    }else{
        [self.library addAssetsGroupAlbumWithName:PHOTO_ALBUM_NAME resultBlock:^(ALAssetsGroup *group) {
            NSLog(@"adding album:'Compressed Videos', success: %s", group.editable ? "YES" : "NO");
    
            if (group.editable == NO) {
            }
    
        } failureBlock:^(NSError *error) {
            NSLog(@"error adding album");
        }];
    }}
    
    0 讨论(0)
  • 2020-12-08 02:07
    /// Save images or videos(保存图片或视频)(kUTTypeImage, kUTTypeMovie)
    /// Add to album if specified album name, and create album if needed
    /// @params mediaArray UIImage, fileURL for a image or video
    + (void)_saveMediaArray:(NSArray *)mediaArray
                    options:(LAImageSaverOptions *)options
                 completion:(void (^)(NSError * _Nullable err))completion
    {
        NSInteger __block count = 0;
    
        [PHPhotoLibrary.sharedPhotoLibrary performChanges:^{
    
            // Create album if needed
            PHAssetCollectionChangeRequest *assetCollectionChangeRequest = nil;
            NSMutableArray<PHObjectPlaceholder *> *assetChangeRequestPlaceholders = nil;
            if (options.targetAlbumName.length > 0) {
                assetChangeRequestPlaceholders = [NSMutableArray arrayWithCapacity:mediaArray.count];
    
                PHFetchOptions *fetchOptions = PHFetchOptions.new;
                //fetchOptions.includeAssetSourceTypes = PHAssetSourceTypeUserLibrary;
                fetchOptions.predicate = [NSPredicate predicateWithFormat:@"localizedTitle = %@", options.targetAlbumName]; // 不能用 block 形式的 predicate
                PHAssetCollection * assetCollection = [PHAssetCollection fetchAssetCollectionsWithType:PHAssetCollectionTypeAlbum subtype:PHAssetCollectionSubtypeAlbumRegular options:fetchOptions].firstObject;
                if (nil == assetCollection) {
                    assetCollectionChangeRequest = [PHAssetCollectionChangeRequest creationRequestForAssetCollectionWithTitle:options.targetAlbumName];
                } else {
                    assetCollectionChangeRequest = [PHAssetCollectionChangeRequest changeRequestForAssetCollection:assetCollection];
                }
             }
    
            // Save images
            for (id item in mediaArray) {
                PHAssetChangeRequest *assetChangeRequest = nil;
                // image object
                if ([item isKindOfClass:UIImage.class]) {
                    UIImage *image = (UIImage *)item;
                    assetChangeRequest = [PHAssetChangeRequest creationRequestForAssetFromImage:image];
                    [assetChangeRequestPlaceholders addObject:assetChangeRequest.placeholderForCreatedAsset];
                    ++count;
                    continue;
                }
    
                // file url for image or movie
                NSURL *fileURL = (NSURL *)item;
                if ([item isKindOfClass:NSURL.class] && fileURL.isFileURL) {
                    NSString *extension = fileURL.pathExtension;
                    if (extension.length == 0) {
                        NSLog(@"illegal fileURL(no path extension): %@", fileURL);
                        continue; // illegal file url
                    }
                    CFStringRef uti = UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension, (__bridge CFStringRef)extension, NULL);
                    BOOL isImage = false;
                    BOOL isVideo = false;
                    if (nil != uti && CFStringGetLength(uti) > 0) {
                        isImage = UTTypeConformsTo(uti, kUTTypeImage);
                        isVideo = UTTypeConformsTo(uti, kUTTypeMovie); // kUTTypeVideo, kUTTypeAudiovisualContent
                    }
                    if (isImage) {
                        assetChangeRequest = [PHAssetChangeRequest creationRequestForAssetFromImageAtFileURL:fileURL];
                        [assetChangeRequestPlaceholders addObject:assetChangeRequest.placeholderForCreatedAsset];
                        ++count;
                    } if (isVideo) {
                        assetChangeRequest = [PHAssetChangeRequest creationRequestForAssetFromVideoAtFileURL:fileURL];
                        [assetChangeRequestPlaceholders addObject:assetChangeRequest.placeholderForCreatedAsset];
                        ++count;
                    } else {
                        NSLog(@"illegal fileURL(neither image nor movie): %@", fileURL);
                        continue; // illegal file url
                    }
                }
            }
    
            // add to album if needed
            [assetCollectionChangeRequest addAssets:assetChangeRequestPlaceholders];
    
        } completionHandler:^(BOOL success, NSError * _Nullable error) {
    
            // not in main thread 
            dispatch_async(dispatch_get_main_queue(), ^{
                completion(error);
            });
        }];
    }
    

    By the way, you can do more about LAImageSaverOptions

    @interface LAImageSaverOptions : NSObject
    
    /// to show alert controller on the hostVC
    @property(nonatomic, weak, null_resettable) UIViewController *hostVC;
    
    
    /// total progress
    @property (nonatomic, strong, null_resettable) NSProgress *progress;
    
    // album name for saving images
    @property (nonatomic, copy, nullable) NSString *targetAlbumName;
    
    @end
    
    0 讨论(0)
  • 2020-12-08 02:08

    Since the AssetsLibrary is deprecated, please use the Photos framework instead (iOS 8 and later).

    // Deprecated!
    import AssetsLibrary
    
    // Swift 3.0
    let assetsLibrary = ALAssetsLibrary()
    assetsLibrary.addAssetsGroupAlbum(withName: "NewAlbum", resultBlock: { assetsGroup in
        print(assetsGroup == nil ? "Already created" : "Success")
    }, failureBlock: { error in
        print(error)
    })
    

    You can use the shared PHPhotoLibrary object to create new photos but you can't give them specific names because you will be working with assets that need to be managed by the Photos.app. Each asset has specific properties. You can fetch objects, request changes, asset/thumbnail loading and caching, etc.

    To create a custom album, please use the PHAssetCollectionChangeRequest.creationRequestForAssetCollection(withTitle:).

    Brief example:

    // Swift 3.0
    func createPhotoLibraryAlbum(name: String) {
        var albumPlaceholder: PHObjectPlaceholder?
        PHPhotoLibrary.shared().performChanges({
            // Request creating an album with parameter name
            let createAlbumRequest = PHAssetCollectionChangeRequest.creationRequestForAssetCollection(withTitle: name)
            // Get a placeholder for the new album
            albumPlaceholder = createAlbumRequest.placeholderForCreatedAssetCollection
        }, completionHandler: { success, error in
            if success {
                guard let placeholder = albumPlaceholder else {
                    fatalError("Album placeholder is nil")
                }
    
                let fetchResult = PHAssetCollection.fetchAssetCollections(withLocalIdentifiers: [placeholder.localIdentifier], options: nil)
                guard let album: PHAssetCollection = fetchResult.firstObject else {
                    // FetchResult has no PHAssetCollection
                    return
                }
    
                // Saved successfully!
                print(album.assetCollectionType)
            }
            else if let e = error {
                // Save album failed with error
            }
            else {
                // Save album failed with no error
            }
        })
    }
    

    Don't forget to import Photos library.

    To create a new photo asset on that album, please use the PHAssetCollectionChangeRequest.creationRequestForAssetCollection(withTitle:).

    // Swift 3.0
    func createPhotoOnAlbum(photo: UIImage, album: PHAssetCollection) {
        PHPhotoLibrary.shared().performChanges({
            // Request creating an asset from the image
            let createAssetRequest = PHAssetChangeRequest.creationRequestForAsset(from: photo)
            // Request editing the album
            guard let albumChangeRequest = PHAssetCollectionChangeRequest(for: album) else {
                // Album change request has failed
                return
            }
            // Get a placeholder for the new asset and add it to the album editing request
            guard let photoPlaceholder = createAssetRequest.placeholderForCreatedAsset else {
                // Photo Placeholder is nil
                return
            }
            albumChangeRequest.addAssets([photoPlaceholder] as NSArray)
        }, completionHandler: { success, error in
            if success {
                // Saved successfully!
            }
            else if let e = error {
                // Save photo failed with error
            }
            else {
                // Save photo failed with no error
            }
        })
    }
    

    UPDATE:

    We need to request access to be able to use the Photos library:

    PHPhotoLibrary.requestAuthorization { status in
         switch status {
         ...
    }
    

    As of iOS 10 and above we also need to add entry for access in the target .plist file for "Privacy - Photo Library Usage Description":

    <key>NSPhotoLibraryUsageDescription</key>
    <string>Access to photos is needed to provide app features</string>
    
    0 讨论(0)
  • 2020-12-08 02:15

    You can create a custom album and add an image pretty easy with these lines of code in iOS:

    // Create the new album.
    __block PHObjectPlaceholder *myAlbum;
    [[PHPhotoLibrary sharedPhotoLibrary] performChanges:^{
        PHAssetCollectionChangeRequest *changeRequest = [PHAssetCollectionChangeRequest creationRequestForAssetCollectionWithTitle:title];
        myAlbum = changeRequest.placeholderForCreatedAssetCollection;
    } completionHandler:^(BOOL success, NSError *error) {
        if (success) {
            PHFetchResult *fetchResult = [PHAssetCollection fetchAssetCollectionsWithLocalIdentifiers:@[myAlbum.localIdentifier] options:nil];
            PHAssetCollection *assetCollection = fetchResult.firstObject;
    
            [[PHPhotoLibrary sharedPhotoLibrary] performChanges:^{
                PHAssetChangeRequest *assetChangeRequest = [PHAssetChangeRequest creationRequestForAssetFromImage:image];
    
                // add asset
                PHAssetCollectionChangeRequest *assetCollectionChangeRequest = [PHAssetCollectionChangeRequest changeRequestForAssetCollection:assetCollection];
                [assetCollectionChangeRequest addAssets:@[[assetChangeRequest placeholderForCreatedAsset]]];
            } completionHandler:^(BOOL success, NSError *error) {
                if (!success) {
                    NSLog(@"Error: %@", error);
                }
            }];
        } else {
            NSLog(@"Error: %@", error);
        }
    }];
    
    0 讨论(0)
提交回复
热议问题