【问题标题】:Save images with phimagemanager to custom album?使用 phimagemanager 将图像保存到自定义相册?
【发布时间】:2015-01-16 11:41:17
【问题描述】:

我正在制作一个使用 AVFoundation 拍照的应用程序,我想将它们保存到一个自定义相册中,然后我可以在我的应用程序中查询和显示该相册。 (我宁愿不把它们放在一般的相册中,除非用户想要那样)我真的找不到任何东西来展示如何在 Swift 中做到这一点......或者根本没有。我应该以其他方式执行此操作吗?

我在 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)
                })
        })

    })
}

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

【问题讨论】:

  • 我也遇到了同样的问题..有什么解决方案吗??..任何人??
  • 嘿@AnoojKrishnanG。我让它工作了。让我在今天晚些时候或明天发布我的解决方案 - 现在有一些圣诞节的东西。
  • 嘿@AnoojKrishnanG。刚刚发布了答案。让我知道这是否适合你。我想我什么都放在那里了。

标签: ios swift uiimage ios8 phasset


【解决方案1】:

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

示例用法:

#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);
}];

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

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

【讨论】:

    【解决方案2】:

    我就是这样做的:

    在顶部:

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

    创建相册:

    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
                    }
            })
        }
    }
    

    保存照片时:

    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()
            })
        }
    

    显示该相册中的图像:

    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)
                    })
                }
            }
    

    【讨论】:

    • 看起来您在“保存照片时”部分中缺少代码
    • 感谢您的回答,但您的代码有很多错别字,并且缺少很多。你认为你可以整理你的答案吗?那真的很有帮助
    • 有人可以提供与此代码完全等效的objective-c吗?
    • 这对我有用,但我还有一件事要实现。如何获取图像的 URL/路径,以便将其存储在我的数据模型中。
    • 如何用自定义文件名保存这张图片??
    【解决方案3】:

    我喜欢重复使用我编写的代码,所以我决定为 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)
        }
    }
    

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

    【讨论】:

    • 非常感谢!我对其进行了一些改进,添加了视频,以及一个让我编译它的类别(PHAsset+identifier.swift)github.com/kv2/PHPhotoLibrary-PhotoAsset.swift
    • 类型“PHAsset”没有成员“fetchAssetsWithLocalIdentifier”。它确实有 fetchAssetsWithLocalIndentifiers 但它有一个不同的参数列表,我不知道如何编辑
    • 好的,开始工作了。需要用 PHAsset.fetchAssetsWithLocalIdentifiers([placeholder.localIdentifier], options: nil).firstObject 替换 fetchAssetWithLocalIdentifier 吗? PHAsset
    • 我将如何继续获取图像的路径以将其存储在数据库中??
    • @Xitcod13 你不需要路径。您只需要保存localIdentifier永久标识对象的唯一字符串。)。
    【解决方案4】:

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

    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")
                   }
             }
     })
    

    【讨论】:

      【解决方案5】:

      用 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);
          }
      }];
      

      UUID 末尾的位是我在 another StackOverflow thread 上找到的,用于从 ALAsset 创建 AssetURL 属性的替换。

      注意:请参阅下面的 chris 评论以获得更完整的答案。

      【讨论】:

      • @cschandler > [self savePhoto] 是做什么的;有吗?
      • 这种方法有两个异步请求(即performChanges 调用),其中一个依赖于另一个的结果是否存在问题?这不会引入竞争条件吗?
      • 你可能是对的。我想我会使用调度组来确保调用完成,或者只是将完成处理程序中的“保存到相册”部分移动到“创建相册”部分以确保完全安全。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-11-04
      • 1970-01-01
      相关资源
      最近更新 更多