如何使用 Photo Kit 获取专辑海报图片?

Posted

技术标签:

【中文标题】如何使用 Photo Kit 获取专辑海报图片?【英文标题】:How to fetch album poster image using Photo Kit? 【发布时间】:2015-01-27 06:49:35 【问题描述】:

使用资产库时,您可以从 ALAssetsGroup 获取专辑的海报图片。使用 Photos Framework (Photo kit) 时如何实现同样的效果?

【问题讨论】:

你尝试过什么?发布代码,以便其他用户可以检查。 查看 Apple 的示例代码:developer.apple.com/documentation/photokit/… 【参考方案1】:

我是这样做的。在方法 cellForRowAtIndexPath: 中,在相册 tableView 中添加以下代码。

目标 C:

    PHFetchOptions *fetchOptions = [[PHFetchOptions alloc] init];
    fetchOptions.sortDescriptors = @[[NSSortDescriptor sortDescriptorWithKey:@"creationDate" ascending:YES]];
    PHFetchResult *fetchResult = [PHAsset fetchKeyAssetsInAssetCollection:[self.assetCollections objectAtIndex:indexPath.row] options:fetchOptions];
        PHAsset *asset = [fetchResult firstObject];
        PHImageRequestOptions *options = [[PHImageRequestOptions alloc] init];
        options.resizeMode = PHImageRequestOptionsResizeModeExact;

        CGFloat scale = [UIScreen mainScreen].scale;
        CGFloat dimension = 78.0f;
        CGSize size = CGSizeMake(dimension*scale, dimension*scale);

        [[PHImageManager defaultManager] requestImageForAsset:asset targetSize:size contentMode:PHImageContentModeAspectFill options:options resultHandler:^(UIImage *result, NSDictionary *info) 
        dispatch_async(dispatch_get_main_queue(), ^
            cell.imageView.image = result;
        );

        ];

斯威夫特 3:

let fetchOptions = PHFetchOptions()
let descriptor = NSSortDescriptor(key: "creationDate", ascending: true)
fetchOptions.sortDescriptors = [descriptor]

let fetchResult = PHAsset.fetchKeyAssets(in: assets[indexPath.row], options: fetchOptions)

guard let asset = fetchResult?.firstObject else 
    return


let options = PHImageRequestOptions()
options.resizeMode = .exact

let scale = UIScreen.main.scale
let dimension = CGFloat(78.0)
let size = CGSize(width: dimension * scale, height: dimension * scale)


PHImageManager.default().requestImage(for: asset, targetSize: size, contentMode: .aspectFill, options: options)  (image, info) in
    DispatchQueue.main.async 
        cell.imageView.image = image
    

编辑: 看起来 fetchKeyAssetsInAssetCollection 并不总是返回正确的结果(最近捕获的图像/视频)。 keyAssets 的定义由apple 模糊定义。更好用

+ (PHFetchResult *)fetchAssetsInAssetCollection:(PHAssetCollection *)assetCollection options:(PHFetchOptions *)options

获取获取结果数组,然后如前所述从获取结果中获取 firstObject。这肯定会返回正确的结果。 :)

【讨论】:

你能比“并不总是返回正确的结果”更具体吗? cell.imageView.image = image 需要在主线程中发生。您不能从非主线程修改 UI 元素。 感谢您指出主线程问题。编辑代码。此外,关于您关于“正确结果”的问题,基本上 fetchKeyAssetsInAssetCollection 不会返回相册中最顶部的图像。 API 文档非常模糊。另一个 API fetchAssetsInAssetCollection 是从相册中获取最高图像的可靠方法。希望这可以澄清任何疑问。 我无法让它工作。因为单元格是在requestImageForAsset 完成块与图像一起返回之前从cellForRowAtIndexPath: 返回的,所以单元格的 imageView 框架为 0,0,0,0。这意味着您看不到图像。如果您在完成块中手动设置 imageView 的框架,它不会将标签移开。我目前正在重新加载表格视图之前检索所有缩略图。 phphotos 给我留下了深刻的印象 - ALAssets 更容易与 IMO 一起使用。 @mashers 为什么没有虚拟图像可以在检索时用原始图像替换。这样,您将拥有正确大小的 imageView(我相信您的 imageView 是固定大小的)。照片框架有它的痛苦。我已经为缺少的功能提出了一些雷达。【参考方案2】:

这是我现在使用的。它处理不同类型的照片集和关键资产丢失的情况。

static func fetchThumbnail(collection: PHCollection, targetSize: CGSize, completion: @escaping (UIImage?) -> ()) 

    func fetchAsset(asset: PHAsset, targetSize: CGSize, completion: @escaping (UIImage?) -> ()) 
        let options = PHImageRequestOptions()
        options.deliveryMode = PHImageRequestOptionsDeliveryMode.highQualityFormat
        options.isSynchronous = false
        options.isNetworkAccessAllowed = true

        // We could use PHCachingImageManager for better performance here
        PHImageManager.default().requestImage(for: asset, targetSize: targetSize, contentMode: .default, options: options, resultHandler:  (image, info) in
            completion(image)
        )
    

    func fetchFirstImageThumbnail(collection: PHAssetCollection, targetSize: CGSize, completion: @escaping (UIImage?) -> ()) 
        // We could sort by creation date here if we want
        let assets = PHAsset.fetchAssets(in: collection, options: PHFetchOptions())
        if let asset = assets.firstObject 
            fetchAsset(asset: asset, targetSize: targetSize, completion: completion)
         else 
            completion(nil)
        
    

    if let collection = collection as? PHAssetCollection 
        let assets = PHAsset.fetchKeyAssets(in: collection, options: PHFetchOptions())

        if let keyAsset = assets?.firstObject 
            fetchAsset(asset: keyAsset, targetSize: targetSize)  (image) in
                if let image = image 
                    completion(image)
                 else 
                    fetchFirstImageThumbnail(collection: collection, targetSize: targetSize, completion: completion)
                
            
         else 
            fetchFirstImageThumbnail(collection: collection, targetSize: targetSize, completion: completion)
        
     else if let collection = collection as? PHCollectionList 
        // For folders we get the first available thumbnail from sub-folders/albums
        // possible improvement - make a "tile" thumbnail with 4 images
        let inner = PHCollection.fetchCollections(in: collection, options: PHFetchOptions())
        inner.enumerateObjects  (innerCollection, idx, stop) in
            self.fetchThumbnail(collection: innerCollection, targetSize: targetSize, completion:  (image) in
                if image != nil 
                    completion(image)
                    stop.pointee = true
                 else if idx >= inner.count - 1 
                    completion(nil)
                
            )
        
     else 
        // We shouldn't get here
        completion(nil)
    

【讨论】:

非常适合从 PHCollection 获取拇指。【参考方案3】:

这是一件很简单的事情……

    PHFetchOptions *userAlbumsOptions = [PHFetchOptions new];
    userAlbumsOptions.predicate = [NSPredicate predicateWithFormat:@"estimatedAssetCount > 0"];

    PHFetchResult *userAlbums = [PHAssetCollection fetchAssetCollectionsWithType:PHAssetCollectionTypeAlbum subtype:PHAssetCollectionSubtypeAny options:userAlbumsOptions];

    [userAlbums enumerateObjectsUsingBlock:^(PHAssetCollection *collection, NSUInteger idx, BOOL *stop) 
    NSLog(@"album title %@", collection.localizedTitle);
    PHFetchResult *assetsFetchResult = [PHAsset fetchAssetsInAssetCollection:collection options:nil];
    PHAsset *asset = [assetsFetchResult objectAtIndex:0];
    NSInteger retinaMultiplier = [UIScreen mainScreen].scale;
    CGSize retinaSquare = CGSizeMake(80 * retinaMultiplier, 80 * retinaMultiplier);

    [[SDWebImageManager sharedManager] downloadImageWithURL:[NSURL URLWithString:asset.localIdentifier] options:SDWebImageProgressiveDownload targetLocalAssetSize:retinaSquare progress:^(NSInteger receivedSize, NSInteger expectedSize) 

     completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, BOOL finished, NSURL *imageURL) 
        if (image) 
            albumCoverImg.image = image;
        
    ];
];

如果您尚未更新 SDWebImage 分类,则以正常方式加载图像。

【讨论】:

为什么这个答案会引入第三方依赖(SDWebImage)? 我不确定这是否正确。它应该使用fetchKeyAssets 而不仅仅是获取第一个对象(关键资产不一定只是返回的第一个资产)。

以上是关于如何使用 Photo Kit 获取专辑海报图片?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 iOS 中使用 Twitter Kit/Fabric 从登录用户获取用户个人资料图片

Photo Kit 框架

Android-从音频文件中获取专辑图片

Android-从音频文件中获取专辑图片

照片和二维码怎么生成海报

Facebook iOS SDK:获取专辑封面图片