ios 使用 phimagemanager 将图像保存到自定义相册?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/27008641/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-31 03:41:07  来源:igfitidea点击:

Save images with phimagemanager to custom album?

iosswiftuiimageios8phasset

提问by Jonovono

I am making an app that takes pictures with AVFoundation and I want to save them to a custom album that I can then query and show in my app. (I'd prefer to not have them in the general photo roll, unless the user wants that) I can't really find anything showing how to do this in Swift... or at all. Is there a different way I am supposed to do this?

我正在制作一个使用 AVFoundation 拍照的应用程序,我想将它们保存到一个自定义相册中,然后我可以在我的应用程序中查询和显示。(我宁愿不在一般照片胶卷中使用它们,除非用户需要)我真的找不到任何显示如何在 Swift 中执行此操作的内容……或者根本找不到。有没有不同的方式我应该这样做?

I found this example on SO but it doesn't make sense to me and I can't get it to work.

我在 SO 上找到了这个例子,但对我来说没有意义,我无法让它工作。

    func savePhoto() {
    var albumFound : Bool = false
    var assetCollection: PHAssetCollection!
    var photosAsset: PHFetchResult!
    var assetThumbnailSize:CGSize!

    // Create the album if does not exist (in viewDidLoad)
    if let first_Obj:AnyObject = collection.firstObject{
        //found the album
        self.albumFound = true
        self.assetCollection = collection.firstObject as PHAssetCollection
    }else{
        //Album placeholder for the asset collection, used to reference collection in completion handler
        var albumPlaceholder:PHObjectPlaceholder!
        //create the folder
        NSLog("\nFolder \"%@\" does not exist\nCreating now...", albumName)
        PHPhotoLibrary.sharedPhotoLibrary().performChanges({
            let request = PHAssetCollectionChangeRequest.creationRequestForAssetCollectionWithTitle(albumName)
            albumPlaceholder = request.placeholderForCreatedAssetCollection
            },
            completionHandler: {(success:Bool, error:NSError!)in
                NSLog("Creation of folder -> %@", (success ? "Success":"Error!"))
                self.albumFound = (success ? true:false)
                if(success){
                    let collection = PHAssetCollection.fetchAssetCollectionsWithLocalIdentifiers([albumPlaceholder.localIdentifier], options: nil)
                    self.assetCollection = collection?.firstObject as PHAssetCollection
                }
        })
    }



    let bundle = NSBundle.mainBundle()
    let myFilePath = bundle.pathForResource("highlight1", ofType: "mov")
    let videoURL:NSURL = NSURL.fileURLWithPath(myFilePath!)!

    let priority = DISPATCH_QUEUE_PRIORITY_DEFAULT
    dispatch_async(dispatch_get_global_queue(priority, 0), {
        PHPhotoLibrary.sharedPhotoLibrary().performChanges({
            //let createAssetRequest = PHAssetChangeRequest.creationRequestForAssetFromImage
            let createAssetRequest = PHAssetChangeRequest.creationRequestForAssetFromVideoAtFileURL(videoURL)
            let assetPlaceholder = createAssetRequest.placeholderForCreatedAsset
            let albumChangeRequest = PHAssetCollectionChangeRequest(forAssetCollection: self.assetCollection, assets: self.photosAsset)
            albumChangeRequest.addAssets([assetPlaceholder])
            }, completionHandler: {(success, error)in
                dispatch_async(dispatch_get_main_queue(), {
                    NSLog("Adding Image to Library -> %@", (success ? "Sucess":"Error!"))
                    //picker.dismissViewControllerAnimated(true, completion: nil)
                })
        })

    })
}

Any help/explanations would be great!

任何帮助/解释都会很棒!

回答by Jonovono

This is how I do:

这就是我的做法:

At the top:

在顶部:

import Photos

var image: UIImage!
var assetCollection: PHAssetCollection!
var albumFound : Bool = false
var photosAsset: PHFetchResult!
var assetThumbnailSize:CGSize!
var collection: PHAssetCollection!
var assetCollectionPlaceholder: PHObjectPlaceholder!

Creating the album:

创建相册:

func createAlbum() {
    //Get PHFetch Options
    let fetchOptions = PHFetchOptions()
    fetchOptions.predicate = NSPredicate(format: "title = %@", "camcam")
    let collection : PHFetchResult = PHAssetCollection.fetchAssetCollectionsWithType(.Album, subtype: .Any, options: fetchOptions)
    //Check return value - If found, then get the first album out
    if let _: AnyObject = collection.firstObject {
        self.albumFound = true
        assetCollection = collection.firstObject as! PHAssetCollection
    } else {
        //If not found - Then create a new album
        PHPhotoLibrary.sharedPhotoLibrary().performChanges({
            let createAlbumRequest : PHAssetCollectionChangeRequest = PHAssetCollectionChangeRequest.creationRequestForAssetCollectionWithTitle("camcam")
            self.assetCollectionPlaceholder = createAlbumRequest.placeholderForCreatedAssetCollection
            }, completionHandler: { success, error in
                self.albumFound = success

                if (success) {
                    let collectionFetchResult = PHAssetCollection.fetchAssetCollectionsWithLocalIdentifiers([self.assetCollectionPlaceholder.localIdentifier], options: nil)
                    print(collectionFetchResult)
                    self.assetCollection = collectionFetchResult.firstObject as! PHAssetCollection
                }
        })
    }
}

When saving the photo:

保存照片时:

func saveImage(){
        PHPhotoLibrary.sharedPhotoLibrary().performChanges({
            let assetRequest = PHAssetChangeRequest.creationRequestForAssetFromImage(self.image)
            let assetPlaceholder = assetRequest.placeholderForCreatedAsset
            let albumChangeRequest = PHAssetCollectionChangeRequest(forAssetCollection: self.assetCollection, assets: self.photosAsset)
            albumChangeRequest!.addAssets([assetPlaceholder!])
            }, completionHandler: { success, error in
                print("added image to album")
                print(error)

                self.showImages()
        })
    }

Showing the images from that album:

显示该相册中的图像:

func showImages() {
        //This will fetch all the assets in the collection

        let assets : PHFetchResult = PHAsset.fetchAssetsInAssetCollection(assetCollection, options: nil)
        print(assets)

        let imageManager = PHCachingImageManager()
        //Enumerating objects to get a chached image - This is to save loading time
        assets.enumerateObjectsUsingBlock{(object: AnyObject!,
            count: Int,
            stop: UnsafeMutablePointer<ObjCBool>) in

            if object is PHAsset {
                let asset = object as! PHAsset
                print(asset)

                let imageSize = CGSize(width: asset.pixelWidth, height: asset.pixelHeight)

                let options = PHImageRequestOptions()
                options.deliveryMode = .FastFormat

                imageManager.requestImageForAsset(asset, targetSize: imageSize, contentMode: .AspectFill, options: options, resultHandler: {(image: UIImage?,
                    info: [NSObject : AnyObject]?) in
                    print(info)
                    print(image)
                })
            }
        }

回答by cschandler

Answer in Objective-C and cleaned up a bit.

在Objective-C中回答并清理了一下。

__block PHFetchResult *photosAsset;
__block PHAssetCollection *collection;
__block PHObjectPlaceholder *placeholder;

// Find the album
PHFetchOptions *fetchOptions = [[PHFetchOptions alloc] init];
fetchOptions.predicate = [NSPredicate predicateWithFormat:@"title = %@", @"YOUR_ALBUM_TITLE"];
collection = [PHAssetCollection fetchAssetCollectionsWithType:PHAssetCollectionTypeAlbum
                                                      subtype:PHAssetCollectionSubtypeAny
                                                      options:fetchOptions].firstObject;
// Create the album
if (!collection)
{
    [[PHPhotoLibrary sharedPhotoLibrary] performChanges:^{
        PHAssetCollectionChangeRequest *createAlbum = [PHAssetCollectionChangeRequest creationRequestForAssetCollectionWithTitle:@"YOUR_ALBUM_TITLE"];
        placeholder = [createAlbum placeholderForCreatedAssetCollection];
    } completionHandler:^(BOOL success, NSError *error) {
        if (success)
        {
            PHFetchResult *collectionFetchResult = [PHAssetCollection fetchAssetCollectionsWithLocalIdentifiers:@[placeholder.localIdentifier]
                                                                                                            options:nil];
            collection = collectionFetchResult.firstObject;
        }
    }];
}

// Save to the album
[[PHPhotoLibrary sharedPhotoLibrary] performChanges:^{
    PHAssetChangeRequest *assetRequest = [PHAssetChangeRequest creationRequestForAssetFromImage:[UIImage imageWithData:imageData]];
    placeholder = [assetRequest placeholderForCreatedAsset];
    photosAsset = [PHAsset fetchAssetsInAssetCollection:collection options:nil];
    PHAssetCollectionChangeRequest *albumChangeRequest = [PHAssetCollectionChangeRequest changeRequestForAssetCollection:collection
                                                                                                                  assets:photosAsset];
    [albumChangeRequest addAssets:@[placeholder]];
} completionHandler:^(BOOL success, NSError *error) {
    if (success)
    {
        NSString *UUID = [placeholder.localIdentifier substringToIndex:36];
        self.photo.assetURL = [NSString stringWithFormat:@"assets-library://asset/asset.PNG?id=%@&ext=JPG", UUID];
        [self savePhoto];
    }
    else
    {
        NSLog(@"%@", error);
    }
}];

The bit at the end with the UUID was something I found on another StackOverflow threadfor creating a replacement for AssetURL property from an ALAsset.

UUID 末尾的部分是我在另一个 StackOverflow 线程上发现的,用于从 ALAsset 创建 AssetURL 属性的替换。

Note: See chris' comment below for more complete answer.

注意:有关更完整的答案,请参阅下面的克里斯评论。

回答by ricardopereira

I like to reuse the code I write so I decided to create an extension for PHPhotoLibrary where it is possible to use it like:

我喜欢重用我编写的代码,所以我决定为 PHPhotoLibrary 创建一个扩展,可以像这样使用它:

PHPhotoLibrary.saveImage(photo, albumName: "Trip") { asset in
    guard let asset = asset else {
        assert(false, "Asset is nil")
        return
    }
    PHPhotoLibrary.loadThumbnailFromAsset(asset) { thumbnail in
        print(thumbnail)
    }
}

Here is the code: https://gist.github.com/ricardopereira/636ccd0a3c8a327c43d42e7cbca4d041

这是代码:https: //gist.github.com/ricardopereira/636ccd0a3c8a327c43d42e7cbca4d041

回答by ColossalChris

As updated for Swift 2.1+ and for Video in case you are trying to do that and ended up here. Compare to the other answers for slight differences (such as using for Images rather than Video)

针对 Swift 2.1+ 和视频进行了更新,以防您尝试这样做并在此处结束。与其他答案的细微差别进行比较(例如用于图像而不是视频)

var photosAsset: PHFetchResult!
var collection: PHAssetCollection!
var assetCollectionPlaceholder: PHObjectPlaceholder!

//Make sure we have custom album for this app if haven't already
let fetchOptions = PHFetchOptions()
fetchOptions.predicate = NSPredicate(format: "title = %@", "MY_APP_ALBUM_NAME")
self.collection = PHAssetCollection.fetchAssetCollectionsWithType(.Album, subtype: .Any, options: fetchOptions).firstObject as! PHAssetCollection

//if we don't have a special album for this app yet then make one
if self.collection == nil {
     PHPhotoLibrary.sharedPhotoLibrary().performChanges({
        let createAlbumRequest : PHAssetCollectionChangeRequest = PHAssetCollectionChangeRequest.creationRequestForAssetCollectionWithTitle("MY_APP_ALBUM_NAME")
        self.assetCollectionPlaceholder = createAlbumRequest.placeholderForCreatedAssetCollection
             }, completionHandler: { success, error in
                if success {
                    let collectionFetchResult = PHAssetCollection.fetchAssetCollectionsWithLocalIdentifiers([self.assetCollectionPlaceholder.localIdentifier], options: nil)
                    print(collectionFetchResult)
                    self.collection = collectionFetchResult.firstObject as! PHAssetCollection
                }
            })
 }

//save the video to Photos                     
PHPhotoLibrary.sharedPhotoLibrary().performChanges({
     let assetRequest = PHAssetChangeRequest.creationRequestForAssetFromVideoAtFileURL(self.VIDEO_URL_FOR_VIDEO_YOU_MADE!)
     let assetPlaceholder = assetRequest!.placeholderForCreatedAsset
     self.photosAsset = PHAsset.fetchAssetsInAssetCollection(self.collection, options: nil)
     let albumChangeRequest = PHAssetCollectionChangeRequest(forAssetCollection: self.collection, assets: self.photosAsset)
     albumChangeRequest!.addAssets([assetPlaceholder!])
         }, completionHandler: { success, error in
               if success {
                  print("added video to album")
               }else if error != nil{
                  print("handle error since couldn't save video")
               }
         }
 })

回答by stackOverFlew

I improved on @ricardopereira and @ColossalChris code. Added video to the extension, and added another extension on top of PHAsset to get rid of the compilation errors. Works in Swift 2.1.

我改进了 @ricardopereira 和 @ColossalChris 代码。在扩展中添加了视频,并在 PHAsset 之上添加了另一个扩展以消除编译错误。适用于 Swift 2.1。

Sample usage:

示例用法:

#import "Yourtargetname-Swift.h"//important!
NSURL *videoURL = [[NSURL alloc] initFileURLWithPath:PATH_TO_VIDEO];

[PHPhotoLibrary saveVideo:videoURL albumName:@"my album" completion:^(PHAsset * asset) {
    NSLog(@"success");
    NSLog(@"asset%lu",(unsigned long)asset.pixelWidth);
}];

Import both swift files: https://github.com/kv2/PHPhotoLibrary-PhotoAsset.swift

导入两个 swift 文件:https: //github.com/kv2/PHPhotoLibrary-PhotoAsset.swift

It is usable in objective-c as long as you import the swift header for your target (see the ViewController.mfile).

只要您为目标导入 swift 标头,它就可以在 Objective-c 中使用(请参阅ViewController.m文件)。