【问题标题】:Determine largest PHAsset image size available on iOS device确定 iOS 设备上可用的最大 PHAsset 图像大小
【发布时间】:2015-11-27 08:01:10
【问题描述】:

如何确定 iOS 设备上可用的最大 PHAsset 图像大小,其中“可用”是指当前在设备上,不需要从 iCloud 照片库进行任何网络下载?

我一直在开发一个应用程序,其中一组缩略图显示在 UICollectionView 中(很像照片应用程序),然后用户可以选择一个图像来查看它的全尺寸。如有必要,将从 iCloud 下载完整大小的图像。但是,我想向用户展示图像的最大可能版本,直到完整尺寸可用。

照片框架的工作方式很奇怪:

在集合视图中,我使用PHCachingImageManagercache(以及后来的request)图像,targetSize 为 186x186 像素(由于视网膜缩放,UICollectionViewCell 尺寸翻倍)。

效果很好,滚动速度非常快,并且在用图像填充单元格时没有延迟。检查返回的图像大小,它们都是大约 342x256 像素。这是在我的 iPhone 6 上启用了 iCloud 照片库并启用了“优化存储”,因此对于大多数图像来说,设备上只存储了小缩略图。

但是,奇怪的是,如果我随后使用 PHImageRequestOptionsDeliveryMode.Opportunistic 选项使用PHCachingImageManagerPHImageManager.defaultManager() 请求任何图像的全尺寸(或更大)版本,则第一个(低质量)图像返回的是一个微小的 60x45 像素邮票,在全屏上看起来很糟糕,直到最终下载全尺寸图像来替换它。

显然 设备上已经有更大的缩略图 (342x256),因为它们刚刚显示在集合视图中!那么为什么在下载完整尺寸之前它不将它们作为第一个“低质量”图像返回?为了确保 342x256 图像确实已经在设备上,我在飞行模式下运行了代码,因此没有发生网络访问。

我发现,如果我请求最大为 256x256 的任何尺寸,我会返回 342x256 的图像。一旦我变大(甚至 1 像素),它会首先返回 60x45 的图像,然后尝试下载完整尺寸的图像。

我已将代码更改为首先发出 256x256 的请求,然后是带有 PHImageRequestOptionsDeliveryMode.HighQualityFormat 的全尺寸请求(它不会返回微小的中间图像),效果很好。这也是 iOS 照片应用程序必须做的事情,因为它在下载完整图像时会显示相对高质量的缩略图。

那么,在这样的背景下,我怎么知道PHAsset 的最大设备图像尺寸是多少? 256x256 是一个神奇的数字,还是取决于 iCloud 照片库如何优化空间(基于库的大小和可用的设备存储空间)?

当然,Photos Framework 似乎没有返回当前可用的最大图像(当要求提供比当前更大的尺寸时),并且要获得最大尺寸,您必须要求提供该尺寸,这显然是一个错误或更小,因为如果你要求更大,你会得到一个 60x45 的缩影!奇怪。

更新: 提交给 Apple 的错误报告:https://openradar.appspot.com/25181601
演示该错误的示例项目:https://github.com/mluisbrown/PhotoKitBug

【问题讨论】:

  • 在获取缩略图时,您是在使用 PHImageManager.defaultManager() 进行同步还是异步请求?
  • @ArunAmmannaya 我使用PHCachingImageManager 来获取缩略图,并且请求是异步的。
  • 那么您假设为请求的图像获得不同尺寸的单个图像的多个回调。回调被调用了多少次?
  • @ArunAmmannaya 是的,我很清楚这一点,我在问题中提到了这一点。无论如何,如果设备上已经有 342x256 的图像,返回 60x45 的图像是没有意义的,特别是如果您实际上要求更大的尺寸。正如我在问题中所说,请求高达 256x256 会返回可用的最大缩略图(至少在我的情况下),但请求 257x257(或更大)会使您突然下降到只能获得 60x45 的缩略图。
  • 我遇到了类似的问题。请求小于大小的图像返回 nil,大于该大小的图像返回全尺寸图像。我尝试了 networkAccessAllowed = true 并几乎按照要求获得了图像。

标签: ios photokit phasset icloud-photo-library


【解决方案1】:

使用问题中发布的示例项目,我能够在模拟器中重现该问题,但是当我进行以下更改时,我只会收到最大的图像:

let targetSize = PHImageManagerMaximumSize

【讨论】:

  • 使用PHImageManagerMaximumSize作为targetSize意味着给我全分辨率的图像,或者如果它不可用,什么都没有。在模拟器上,全分辨率图像始终可用。但是,在设备上,来自 iCloud 照片库的完整分辨率图像通常不可用。在示例项目中使用PHImageManagerMaximumSize 根本不会返回任何图像,因为它使用了networkAccessAllowed = false 选项。所以恐怕这无济于事:-(
  • @mluisbrown 回到这个话题。这里的协议是什么?我应该删除这个答案,还是保留它以便其他人不会发布相同的答案(显然这并没有真正起作用)?
  • 马克,我想你应该留下答案。这是一个有效的建议。当我看到它时,我跑回我的 Mac 上想“真的有那么明显吗?”事实上值得一票:)
【解决方案2】:

其实我不知道Apple为什么会返回PHImageResultIsDegradedKey=1的降级45*60图片的原因。对我来说,我一开始只是请求带有 deliveryMode PHImageRequestOptionsDeliveryModeHighQualityFormat 的 256*256 图像,然后我使用其他 PHImageRequestOptions 请求完整尺寸的图像,如下所示:

PHImageRequestOptions *options = [[PHImageRequestOptions alloc] init];
options.networkAccessAllowed = YES;
options.deliveryMode = PHImageRequestOptionsDeliveryModeHighQualityFormat;
options.progressHandler = ^(double progress, NSError *error, BOOL *stop, NSDictionary *info){
// code to update the iCloud download progress
});

[[PHImageManager defaultManager] requestImageForAsset:asset targetSize:PHImageManagerMaximumSize contentMode:PHImageContentModeAspectFit options:options resultHandler:^(UIImage * _Nullable result, NSDictionary * _Nullable info) {
// code to update UIImageView or something else.
});

我认为,Instagram 可能会使用这种类似的解决方案来处理来自 iCloud 的图像。

【讨论】:

    【解决方案3】:
    [imageManager requestImageForAsset:asset
                  targetSize: PHImageManagerMaximumSize
                  contentMode:PHImageContentModeAspectFill
                  options:nil
    resultHandler:^(UIImage *result, NSDictionary *info)
    {
        result;
    }];
    

    【讨论】:

    • 如果您费心阅读 Mark Watson 的回答,您就会知道为什么这不起作用(阅读我对该回答的评论)。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-09-23
    • 1970-01-01
    • 2023-03-31
    相关资源
    最近更新 更多