热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

如何将图像保存到自定义相册?

如何解决《如何将图像保存到自定义相册?》经验,为你挑选了5个好方法。

我有一个全新的iOS应用程序,可以生成图像并让用户将它们保存到Camera SavedPhotosAlbum中.但是,我想做Snapchat和Frontback之类的东西,并将这些图像也保存到自定义专辑中.

所以现在这是我的代码:

let imageToSave = self.currentPreviewImage

let softwareCOntext= CIContext(options:[kCIContextUseSoftwareRenderer: true])
let cgimg = softwareContext.createCGImage(imageToSave, fromRect:imageToSave.extent())

ALAssetsLibrary().writeImageToSavedPhotosAlbum(cgimg, metadata:imageToSave.properties(), completionBlock:nil)

我已经看过一些人在Objective-C中这样做的例子,但我没有把它翻译成Swift,我检查了writeImageToSavedPhotosAlbum方法签名,但似乎没有一个允许保存到自定义专辑.



1> scootermg..:

我想出了这个单例类来处理它:

import Photos

class CustomPhotoAlbum {

    static let albumName = "Flashpod"
    static let sharedInstance = CustomPhotoAlbum()

    var assetCollection: PHAssetCollection!

    init() {

        func fetchAssetCollectionForAlbum() -> PHAssetCollection! {

            let fetchOptiOns= PHFetchOptions()
            fetchOptions.predicate = NSPredicate(format: "title = %@", CustomPhotoAlbum.albumName)
            let collection = PHAssetCollection.fetchAssetCollectionsWithType(.Album, subtype: .Any, options: fetchOptions)

            if let firstObject: AnyObject = collection.firstObject {
                return collection.firstObject as! PHAssetCollection
            }

            return nil
        }

        if let assetCollection = fetchAssetCollectionForAlbum() {
            self.assetCollection = assetCollection
            return
        }

        PHPhotoLibrary.sharedPhotoLibrary().performChanges({
            PHAssetCollectionChangeRequest.creationRequestForAssetCollectionWithTitle(CustomPhotoAlbum.albumName)
        }) { success, _ in
            if success {
                self.assetCollection = fetchAssetCollectionForAlbum()
            }
        }
    }

    func saveImage(image: UIImage) {

        if assetCollection == nil {
            return   // If there was an error upstream, skip the save.
        }

        PHPhotoLibrary.sharedPhotoLibrary().performChanges({
            let assetChangeRequest = PHAssetChangeRequest.creationRequestForAssetFromImage(image)
            let assetPlaceholder = assetChangeRequest.placeholderForCreatedAsset
            let albumChangeRequest = PHAssetCollectionChangeRequest(forAssetCollection: self.assetCollection)
            albumChangeRequest.addAssets([assetPlaceholder])
        }, completionHandler: nil)
    }


}

首次实例化该类时,如果自定义相册尚​​不存在,则将创建该相册.您可以保存这样的图像:

CustomPhotoAlbum.sharedInstance.saveImage(image)

注意:CustomPhotoAlbum类假定应用程序已具有访问照片库的权限.处理权限有点超出了这个问题/答案的范围.因此,请在使用之前确保PHPhotoLibrary.authorizationStatus()== .Authorize.并在必要时请求授权.


实际上这个代码还有另一个错误:第一次运行应用程序时它要求对照片库进行授权,但实际创建专辑的封闭程序在获得权限之前被调用,因此它不会创建专辑(或保存任何图片),直到重新启动应用程序(如果您在应用程序设置中切换权限,也会发生这种情况).我试图添加一个便利初始化器来运行专辑创建部分,但它不起作用(因为我真的不知道我在做什么).
我想我终于搞清楚了 - 我把这行改为`albumChangeRequest!.addAssets([assetPlaceHolder!])` - 我想第二个感叹号让它继续下去并尝试将`assetPlaceHolder`作为一个`NSFastEnumeration`对象处理?

2> Jakub Průša..:

最新的Swift 3.0语法.:)

import Foundation
import Photos


class CustomPhotoAlbum: NSObject {
    static let albumName = "Album Name"
    static let sharedInstance = CustomPhotoAlbum()

    var assetCollection: PHAssetCollection!

    override init() {
        super.init()

        if let assetCollection = fetchAssetCollectionForAlbum() {
            self.assetCollection = assetCollection
            return
        }

        if PHPhotoLibrary.authorizationStatus() != PHAuthorizationStatus.authorized {
            PHPhotoLibrary.requestAuthorization({ (status: PHAuthorizationStatus) -> Void in
                ()
            })
        }

        if PHPhotoLibrary.authorizationStatus() == PHAuthorizationStatus.authorized {
            self.createAlbum()
        } else {
            PHPhotoLibrary.requestAuthorization(requestAuthorizationHandler)
        }
    }

    func requestAuthorizationHandler(status: PHAuthorizationStatus) {
        if PHPhotoLibrary.authorizationStatus() == PHAuthorizationStatus.authorized {
            // ideally this ensures the creation of the photo album even if authorization wasn't prompted till after init was done
            print("trying again to create the album")
            self.createAlbum()
        } else {
            print("should really prompt the user to let them know it's failed")
        }
    }

    func createAlbum() {
        PHPhotoLibrary.shared().performChanges({
            PHAssetCollectionChangeRequest.creationRequestForAssetCollection(withTitle: CustomPhotoAlbum.albumName)   // create an asset collection with the album name
        }) { success, error in
            if success {
                self.assetCollection = self.fetchAssetCollectionForAlbum()
            } else {
                print("error \(error)")
            }
        }
    }

    func fetchAssetCollectionForAlbum() -> PHAssetCollection? {
        let fetchOptiOns= PHFetchOptions()
        fetchOptions.predicate = NSPredicate(format: "title = %@", CustomPhotoAlbum.albumName)
        let collection = PHAssetCollection.fetchAssetCollections(with: .album, subtype: .any, options: fetchOptions)

        if let _: AnyObject = collection.firstObject {
            return collection.firstObject
        }
        return nil
    }

    func save(image: UIImage) {
        if assetCollection == nil {
            return                          // if there was an error upstream, skip the save
        }

        PHPhotoLibrary.shared().performChanges({
            let assetChangeRequest = PHAssetChangeRequest.creationRequestForAsset(from: image)
            let assetPlaceHolder = assetChangeRequest.placeholderForCreatedAsset
            let albumChangeRequest = PHAssetCollectionChangeRequest(for: self.assetCollection)
            let enumeration: NSArray = [assetPlaceHolder!]
            albumChangeRequest!.addAssets(enumeration)

        }, completionHandler: nil)
    }
}



3> Cody..:

这是一个更新版本,适用于Swift 2.1,并且避免了在第一次启动时未创建相册并且未保存图像的错误(首次请求/授予写入照片库的授权时).

class CustomPhotoAlbum: NSObject {
    static let albumName = "Name of Custom Album"
    static let sharedInstance = CustomPhotoAlbum()

    var assetCollection: PHAssetCollection!

    override init() {
        super.init()

        if let assetCollection = fetchAssetCollectionForAlbum() {
            self.assetCollection = assetCollection
            return
        }

        if PHPhotoLibrary.authorizationStatus() != PHAuthorizationStatus.Authorized {
            PHPhotoLibrary.requestAuthorization({ (status: PHAuthorizationStatus) -> Void in
                status
            })
        }

        if PHPhotoLibrary.authorizationStatus() == PHAuthorizationStatus.Authorized {
            self.createAlbum()
        } else {
            PHPhotoLibrary.requestAuthorization(requestAuthorizationHandler)
        }
    }

    func requestAuthorizationHandler(status: PHAuthorizationStatus) {
        if PHPhotoLibrary.authorizationStatus() == PHAuthorizationStatus.Authorized {
            // ideally this ensures the creation of the photo album even if authorization wasn't prompted till after init was done
            print("trying again to create the album")
            self.createAlbum()
        } else {
            print("should really prompt the user to let them know it's failed")
        }
    }

    func createAlbum() {
        PHPhotoLibrary.sharedPhotoLibrary().performChanges({
        PHAssetCollectionChangeRequest.creationRequestForAssetCollectionWithTitle(CustomPhotoAlbum.albumName)   // create an asset collection with the album name
            }) { success, error in
                if success {
                    self.assetCollection = self.fetchAssetCollectionForAlbum()
                } else {
                    print("error \(error)")
                }
        }
    }

    func fetchAssetCollectionForAlbum() -> PHAssetCollection! {
        let fetchOptiOns= PHFetchOptions()
        fetchOptions.predicate = NSPredicate(format: "title = %@", CustomPhotoAlbum.albumName)
        let collection = PHAssetCollection.fetchAssetCollectionsWithType(.Album, subtype: .Any, options: fetchOptions)

        if let _: AnyObject = collection.firstObject {
            return collection.firstObject as! PHAssetCollection
        }        
        return nil
    }

    func saveImage(image: UIImage, metadata: NSDictionary) {
        if assetCollection == nil {
            return                          // if there was an error upstream, skip the save
        }

        PHPhotoLibrary.sharedPhotoLibrary().performChanges({                                                                    
            let assetChangeRequest = PHAssetChangeRequest.creationRequestForAssetFromImage(image)                   
            let assetPlaceHolder = assetChangeRequest.placeholderForCreatedAsset             
            let albumChangeRequest = PHAssetCollectionChangeRequest(forAssetCollection: self.assetCollection)       
            albumChangeRequest!.addAssets([assetPlaceHolder!])                                                      
        }, completionHandler: nil)
    }
}


但是,它无法避免在第一次调用时未保存图像的错误.这取决于你如何使用它.如果你第一次使用这个单例是调用sharedInstance.saveImage,那么init将首次被调用,然后立即调用saveImage,但是assetCollection仍然是nil,因为init的回调稍后被调用.要解决这个问题,我建议您先前在viewDidLoad中访问sharedInstance,让_ = CustomPhotoAlbum.sharedInstance.

4> Damien..:

以前的答案非常棒,对我帮助很大,但在第一次通话时仍然存在保存图像的问题.以下解决方案并非完全干净,但解决了这个问题.适用于Swift 3/4.

import Photos

class CustomPhotoAlbum: NSObject {
    static let albumName = "Album name"
    static let shared = CustomPhotoAlbum()

    private var assetCollection: PHAssetCollection!

    private override init() {
        super.init()

        if let assetCollection = fetchAssetCollectionForAlbum() {
            self.assetCollection = assetCollection
            return
        }
    }

    private func checkAuthorizationWithHandler(completion: @escaping ((_ success: Bool) -> Void)) {
        if PHPhotoLibrary.authorizationStatus() == .notDetermined {
            PHPhotoLibrary.requestAuthorization({ (status) in
                self.checkAuthorizationWithHandler(completion: completion)
            })
        }
        else if PHPhotoLibrary.authorizationStatus() == .authorized {
            self.createAlbumIfNeeded()
            completion(true)
        }
        else {
            completion(false)
        }
    }

    private func createAlbumIfNeeded() {
        if let assetCollection = fetchAssetCollectionForAlbum() {
            // Album already exists
            self.assetCollection = assetCollection
        } else {
            PHPhotoLibrary.shared().performChanges({
                PHAssetCollectionChangeRequest.creationRequestForAssetCollection(withTitle: CustomPhotoAlbum.albumName)   // create an asset collection with the album name
            }) { success, error in
                if success {
                    self.assetCollection = self.fetchAssetCollectionForAlbum()
                } else {
                    // Unable to create album
                }
            }
        }
    }

    private func fetchAssetCollectionForAlbum() -> PHAssetCollection? {
        let fetchOptiOns= PHFetchOptions()
        fetchOptions.predicate = NSPredicate(format: "title = %@", CustomPhotoAlbum.albumName)
        let collection = PHAssetCollection.fetchAssetCollections(with: .album, subtype: .any, options: fetchOptions)

        if let _: AnyObject = collection.firstObject {
            return collection.firstObject
        }
        return nil
    }

    func save(image: UIImage) {
        self.checkAuthorizationWithHandler { (success) in
            if success, self.assetCollection != nil {
                PHPhotoLibrary.shared().performChanges({
                    let assetChangeRequest = PHAssetChangeRequest.creationRequestForAsset(from: image)
                    let assetPlaceHolder = assetChangeRequest.placeholderForCreatedAsset
                    let albumChangeRequest = PHAssetCollectionChangeRequest(for: self.assetCollection)
                    let enumeration: NSArray = [assetPlaceHolder!]
                    albumChangeRequest!.addAssets(enumeration)

                }, completionHandler: nil)
            }
        }
    }
}



5> jbouaziz..:

我发现这里提出了一些建议的解决方案,但是我想重写它的可重用版本。使用方法如下:

let image = // this is your image object

// Use the shared instance that has the default album name
CustomPhotoAlbum.shared.save(image)

// Use a custom album name
let album = CustomPhotoAlbum("some title")
album.save(image)

保存图像时,它会请求用户进行照片访问(如果事先获得授权,则会立即返回),如果还不存在,则尝试创建相册。以下是用Swift 3编写并与Objective-C兼容的完整源代码。

//
//  CustomPhotoAlbum.swift
//
//  Copyright © 2017 Et Voilapp. All rights reserved.
//

import Foundation
import Photos

@objc class CustomPhotoAlbum: NSObject {

  /// Default album title.
  static let defaultTitle = "Your title"

  /// Singleton
  static let shared = CustomPhotoAlbum(CustomPhotoAlbum.defaultTitle)

  /// The album title to use.
  private(set) var albumTitle: String

  /// This album's asset collection
  internal var assetCollection: PHAssetCollection?

  /// Initialize a new instance of this class.
  ///
  /// - Parameter title: Album title to use.
  init(_ title: String) {
    self.albumTitle = title
    super.init()
  }

  /// Save the image to this app's album.
  ///
  /// - Parameter image: Image to save.
  public func save(_ image: UIImage?) {
    guard let image = image else { return }

    // Request authorization and create the album
    requestAuthorizationIfNeeded { (_) in

      // If it all went well, we've got our asset collection
      guard let assetCollection = self.assetCollection else { return }

      PHPhotoLibrary.shared().performChanges({

        // Make sure that there's no issue while creating the request
        let request = PHAssetChangeRequest.creationRequestForAsset(from: image)
        guard let placeholder = request.placeholderForCreatedAsset,
          let albumChangeRequest = PHAssetCollectionChangeRequest(for: assetCollection) else {
            return
        }

        let enumeration: NSArray = [placeholder]
        albumChangeRequest.addAssets(enumeration)

      }, completionHandler: nil)
    }
  }
}

internal extension CustomPhotoAlbum {

  /// Request authorization and create the album if that went well.
  ///
  /// - Parameter completion: Called upon completion.
  func requestAuthorizationIfNeeded(_ completion: @escaping ((_ success: Bool) -> Void)) {

    PHPhotoLibrary.requestAuthorization { status in
      guard status == .authorized else {
        completion(false)
        return
      }

      // Try to find an existing collection first so that we don't create duplicates
      if let collection = self.fetchAssetCollectionForAlbum() {
        self.assetCollection = collection
        completion(true)

      } else {
        self.createAlbum(completion)
      }
    }
  }


  /// Creates an asset collection with the album name.
  ///
  /// - Parameter completion: Called upon completion.
  func createAlbum(_ completion: @escaping ((_ success: Bool) -> Void)) {

    PHPhotoLibrary.shared().performChanges({

      PHAssetCollectionChangeRequest.creationRequestForAssetCollection(withTitle: self.albumTitle)

    }) { (success, error) in
      defer {
        completion(success)
      }

      guard error == nil else {
        print("error \(error!)")
        return
      }

      self.assetCollection = self.fetchAssetCollectionForAlbum()
    }
  }


  /// Fetch the asset collection matching this app's album.
  ///
  /// - Returns: An asset collection if found.
  func fetchAssetCollectionForAlbum() -> PHAssetCollection? {

    let fetchOptiOns= PHFetchOptions()
    fetchOptions.predicate = NSPredicate(format: "title = %@", albumTitle)

    let collection = PHAssetCollection.fetchAssetCollections(with: .album, subtype: .any, options: fetchOptions)
    return collection.firstObject
  }
}


推荐阅读
author-avatar
呀yuan-
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有