swift 相册PHAssetCollection,PHAsset

import Foundation
import Photos
/**
 *  相册公用方法类
 */
class JYAlbumHelpModel: NSObject {
    
    /// 获取所有相册
    ///
    /// - Returns: 返回相册列表集合
    static func getAllAlbumList() -> [PHAssetCollection] {
        
        let smartAlbums: PHFetchResult = PHAssetCollection.fetchAssetCollections(with: .smartAlbum, subtype: .albumRegular, options: nil)
        guard smartAlbums.count > 0 else {
            return []
        }
        var tempArr: [PHAssetCollection] = []
        
        
        ///创建的相册文件夹
        let topLeveUserCollections = PHCollectionList.fetchTopLevelUserCollections(with: nil)
        if topLeveUserCollections.count > 0 {
            for i in 0 ... topLeveUserCollections.count - 1 {
                let collection = topLeveUserCollections[i]
                if collection.isKind(of: PHAssetCollection.self) , let assetCollection = collection as? PHAssetCollection {
                    let fetchResult = PHAsset.fetchAssets(in: assetCollection, options: nil)
                    
                    var isContains: Bool = false
                    if fetchResult.count > 0 {
                        for i in 0 ... fetchResult.count - 1 {
                            let asste = fetchResult[i]
                            if asste.mediaType != .video {
                                isContains = true
                                break
                            }
                        }
                    }
                    if isContains {
                        tempArr.append(assetCollection)
                        DDLOG(message:"11111 assetCollectionSubtype =( String(describing: assetCollection.localizedTitle)), assetCollectionType = (assetCollection.assetCollectionType.rawValue), assetCollectionSubtype = (assetCollection.assetCollectionSubtype.rawValue)")
                    }
                }
            }
        }
        ///得到的结果 和我的相薄 是反的, 需要倒序 排列一下
        tempArr = tempArr.reversed()
        
        
        ///系统创建的文件夹
        for i in 0 ... smartAlbums.count - 1 {
            let collection = smartAlbums[i] as PHCollection
            if collection.isKind(of: PHAssetCollection.self) , let assetCollection = collection as? PHAssetCollection , assetCollection.assetCollectionType != .moment {
                let fetchResult = PHAsset.fetchAssets(in: assetCollection, options: nil)
                var isContains: Bool = false
                if fetchResult.count > 0 {
                    for i in 0 ... fetchResult.count - 1 {
                        let asste = fetchResult[i]
                        if asste.mediaType != .video {
                            isContains = true
                            break
                        }
                    }
                }
                
                ///最近项目/相机胶卷/所有照片放到第一位
                if isContains {
                    if assetCollection.localizedTitle == "相机胶卷" || assetCollection.localizedTitle == "所有照片" || assetCollection.localizedTitle == "最近项目" {
                        tempArr.insert(assetCollection, at: 0)
                        
                        ///不添加 已删除和已隐藏
                    }else if assetCollection.localizedTitle == "最近删除" || assetCollection.localizedTitle == "已隐藏"{
                        
                    }else{
                        tempArr.append(assetCollection)
                        DDLOG(message:"22222 localizedTitle =( String(describing: assetCollection.localizedTitle)), assetCollectionType = (assetCollection.assetCollectionType.rawValue), assetCollectionSubtype = (assetCollection.assetCollectionSubtype.rawValue)")
                    }
                }
            }
        }
        
        ///个人收藏放到第二位
        if tempArr.count > 2 , let index = tempArr.firstIndex(where: {$0.localizedTitle == "个人收藏"}) , index != 1 {
            let temp = tempArr.remove(at: index)
            tempArr.insert(temp, at: 1)
        }
        
        ///最近项目和最近添加一样的, 删除最近添加
        for (index, assetCollection) in tempArr.enumerated(){
            if assetCollection.localizedTitle == "最近添加",
                let firstTitle = tempArr.first?.localizedTitle,
                firstTitle == "最近项目"{
                tempArr.remove(at: index)
            }
        }
        
        tempArr.forEach { (assetCollection) in
            DDLOG(message:"reversed tempArr444 =( String(describing: assetCollection.localizedTitle))")
        }
        return tempArr
    }
    
    //// 获取多张图片
    static func asyncGetImageArr(by assetArr: [PHAsset] ,tageSize: CGSize = CGSize( JYScreenWidth * 3 , height: JYScreenHeight * 3), resultHandle:((_ imageArr: [UIImage]) -> Void)? , progressHandle: ((_ progress: Double , _ err: String?) -> Void)?) {
        let quenueGroup = DispatchGroup()
        let semphore = DispatchSemaphore(value: 1)
        let quenue = DispatchQueue.global(qos: DispatchQoS.QoSClass.background)
        var temImageArr: [UIImage] = []
        for asset in assetArr {
            quenueGroup.enter()
            quenue.async{
                semphore.wait()
                DDLOG(message: "开始获取")
                asyncGetImage(by: asset, tageSize: tageSize, resultHandle: { (image) in
                    if let res = image{
                        temImageArr.append(res)
                    }else {
                        DispatchQueue.main.async {
                            progressHandle?(0, "获取图片失败")
                        }
                    }
                    DDLOG(message: "获取成功")
                    semphore.signal()
                    quenueGroup.leave()
                }, progressHandle: { (progress, err) in
                    DispatchQueue.main.async {
                        progressHandle?(progress , err?.localizedDescription)
                    }
                })
            }
        }
        quenueGroup.notify(queue: .main) {
            DDLOG(message: Thread.current)
            resultHandle?(temImageArr)
        }
    }
    
    /// 获取单张指定大小的图片
    static func asyncGetImage(by asset: PHAsset ,tageSize: CGSize , resultHandle:((_ imageArr: UIImage?) -> Void)? , progressHandle: ((_ progress: Double , _ err: Error?) -> Void)?) {
        let option = PHImageRequestOptions()
        option.resizeMode = .fast
        option.deliveryMode = .highQualityFormat
        option.isNetworkAccessAllowed = true
        option.progressHandler = { (progress ,err , stop , info) in
            progressHandle?(progress,err)
        }
        PHImageManager.default().requestImage(for: asset, targetSize: tageSize, contentMode: PHImageContentMode.aspectFit, options: option) { (result, info) in
            if let degrade = info?[PHImageResultIsDegradedKey] as? Bool , degrade == false , let image = result {
                resultHandle?(image)
            }else if result == nil {
                resultHandle?(nil)
                JYLogsModel.JYLog(logType: JYLogsModel.JYLogType.errorType, logStr: "获取指定大小本地相册图片失败")
            }
        }
    }
    
    /// 获取单张原图data
    static func asynGetOriginImageData(asset: PHAsset , resulrHandle:((_ data: Data?) -> Void)?) {
        let option = PHImageRequestOptions()
        option.resizeMode = .fast
        option.deliveryMode = .highQualityFormat
        option.isNetworkAccessAllowed = true
        PHImageManager.default().requestImageData(for: asset, options: option) { (data, dataUTI, orientation, info) in
            if let degrade = info?[PHImageResultIsDegradedKey] as? Bool , degrade == false {
                if let _data = data, UIImage(data: _data) == nil {
                    asyncGetImage(by: asset, tageSize: CGSize( JYScreenWidth * 2, height: JYScreenHeight * 2), resultHandle: { (image) in
                        if let data = image?.jpegData(compressionQuality: 1.0) {
                            resulrHandle?(data)
                        }else {
                            resulrHandle?(nil)
                        }
                    }, progressHandle: nil)
                }else {
                    resulrHandle?(data)
                }
            }else {
                resulrHandle?(data)
                JYLogsModel.JYLog(logType: JYLogsModel.JYLogType.errorType, logStr: "获取单张原图失败")
            }
        }
    }
    
    
    /// 处理imageData(heic)
    ///
    /// - Parameter imageData: 图片二进制流
    /// - Returns: 压缩后的图片二进制流
    static func handleHEICImageData(imageData: Data , type: JYSelectPhotoType) -> Data {
        if #available(iOS 11.0, *) {
            if let sour = CGImageSourceCreateWithData(imageData as CFData, nil) ,  let _type = CGImageSourceGetType(sour) as String? {
                if _type == AVFileType.heic.rawValue || _type == AVFileType.heif.rawValue {
                    if let ciimage = CIImage(data: imageData) , let color = ciimage.colorSpace {
                        let context = CIContext()
                        if let jpgData = context.jpegRepresentation(of: ciimage, colorSpace: color, options:[: ]) {
                            return scaleImage(imageData: jpgData , type: type)
                        }
                    }else {
                        if let image = UIImage(data: imageData) , let _jpgData = image.jpegData(compressionQuality: 1.0) {
                            return scaleImage(imageData: _jpgData ,  type: type)
                        }
                    }
                }
            }
        }
        return scaleImage(imageData: imageData , type: type)
    }
    
    
    /// 不同图片压缩的大小不一致
    ///
    /// - Parameter imageData: 图片二进制流
    /// - Returns: 压缩后的图片
    private static func scaleImage(imageData: Data , type: JYSelectPhotoType) -> Data {
        guard type != .uploadCertificateOriginType else {
            // 压缩证件
            return JYAlbumHelpModel.handleCerImage(data: imageData)
        }
        let imageCount = Double(imageData.count)
        if imageCount > 1.5 * 1024 * 1024 , imageCount <= 3.0 * 1024 * 1024 {
            /// 压缩到1.0M
            let data = compressBySizeWithMaxLength(maxCount: 1024 * 1024, imageData: imageData)
            DDLOG(message: "压缩1后的大小为:(data.count)")
            return data
        }else if imageCount > 3.0 * 1024 * 1024 , imageCount <= 8 * 1024 * 1024 {
            /// 压缩到1.2M
            let data = compressBySizeWithMaxLength(maxCount: Int64(1.2 * 1024 * 1024), imageData: imageData)
            DDLOG(message: "压缩2后的大小为:(data.count)")
            return data
        }else if imageCount > 8 * 1024 * 1024 {
            // 压缩到1.5M
            let data = compressBySizeWithMaxLength(maxCount: Int64(1.5 * 1024 * 1024), imageData: imageData)
            DDLOG(message: "压缩3后的大小为:(data.count)")
            return data
        }
        return imageData
    }
    
    /// 二分法压缩图片
    private static func compressBySizeWithMaxLength(maxCount: Int64 , imageData: Data) -> Data {
        guard imageData.count > maxCount else {
            return imageData
        }
        var data = imageData
        if let resultImage = UIImage(data: imageData) {
            var min: CGFloat = 0.0 ; var max: CGFloat = 1.0 ; var compression: CGFloat = 1.0
            for _ in 0 ... 6 {
                compression = (min + max)/2
                data = resultImage.jpegData(compressionQuality: compression) ?? data
                // 此处设置误差范围为0 - 0.1
                if Double(data.count) > Double(maxCount) * 1.1 {
                    max = compression
                }else if Double(data.count) < Double(maxCount) {
                    min = compression
                }else {
                    break
                }
            }
        }
        return data
    }
    
    /// 处理证件图片大小
    private static func handleCerImage(data: Data) -> Data{
        guard data.count > 1024 * 1024 else {
            return data
        }
        let s = CGFloat(sqrtf(Float(data.count)/Float((1024 * 1024))))
        if let image = UIImage(data: data) , let newImage = image.jy.imageWithScale( image.size.width/s){
            DDLOG(message: "原大小:(data.count) , 尺寸压缩:(s) ,原图尺寸:(image.size) , 新图片尺寸:(newImage.size)")
            if let newData = newImage.jpegData(compressionQuality: 1.0) {
                DDLOG(message: "新图片大小:(newData.count)")
                return compressBySizeWithMaxLength(maxCount: 1024 * 1024, imageData: newData)
            }
            
        }
        return data
    }
    
}
原文地址:https://www.cnblogs.com/qingzZ/p/13594518.html