在 iOS 8.3 中向 PHImageManager 请求图像会导致错误的图像

Posted

技术标签:

【中文标题】在 iOS 8.3 中向 PHImageManager 请求图像会导致错误的图像【英文标题】:Requesting images to PHImageManager results in wrong image in iOS 8.3 【发布时间】:2015-05-17 15:46:38 【问题描述】:

上下文

我正在使用Photos framework 在我正在开发的 ios 应用程序中显示用户图片。

作为参考,我将一些图像上传到 imgur,您可以在其中找到我正在测试的原始图像,以及我拍摄的带有粉红色背景的 UIImageView 的屏幕截图,其中显示了使用“Aspect Fit”配置获取的图像。这是链接:http://imgur.com/a/VPJ9J

我正在使用两个测试场景:第一个是横向图像,其imageOrientationUIImageOrientation.Up (0);其次,肖像图像,带有UIImageOrientation.Right (3)。您可以查看文档(我会将链接放在这里,但我没有足够的声誉,抱歉)。

问题

iPhone 4S (iOS 8.1.2) 在粉红色的 UIImageView 内以横向布局显示横向图像,而在纵向布局中显示纵向图像,正如预期的那样。但 iPhone 5 和 6 Plus(均为 iOS 8.3)以横向布局显示这两个图像。

代码

这是我用来请求图像的代码:

var targetSize = CGSizeMake(1000, (CGFloat(asset.pixelHeight) / CGFloat(asset.pixelWidth)) * 1000)

var options = PHImageRequestOptions()
options.version = PHImageRequestOptionsVersion.Current
options.deliveryMode =  PHImageRequestOptionsDeliveryMode.HighQualityFormat
options.resizeMode = PHImageRequestOptionsResizeMode.Exact
options.networkAccessAllowed = true

PHImageManager.defaultManager().requestImageForAsset(asset, targetSize: targetSize, contentMode: PHImageContentMode.AspectFill, options: options)  (result: UIImage!, info) -> Void in
    if !info[PHImageResultIsDegradedKey]!.boolValue 
        println("asset.pixelWidth: \(asset.pixelWidth)")
        println("asset.pixelHeight: \(asset.pixelHeight)")
        println("targetSize: \(targetSize)")
        println("result.size: \(result.size)")
        println("result.imageOrientation: \(result.imageOrientation.rawValue)")

        completion(result)
    

测试

以下是我在使用这两个图像执行测试时得到的日志:

案例 1:iPhone 4S (8.1.2)

风景:

asset.pixelWidth: 3264
asset.pixelHeight: 2448
targetSize: (1000.0, 750.0)
result.size: (1000.0, 750.0)
result.imageOrientation: 0

肖像:

asset.pixelWidth: 2448
asset.pixelHeight: 3264
targetSize: (1000.0, 1333.33)
result.size: (1000.0, 1332.0)
result.imageOrientation: 3

案例 2:iPhone 5 (8.3)

风景:

asset.pixelWidth: 3264
asset.pixelHeight: 2448
targetSize: (1000.0, 750.0)
result.size: (1000.0, 750.0)
result.imageOrientation: 0

肖像:

asset.pixelWidth: 2448
asset.pixelHeight: 3264
targetSize: (1000.0, 1333.33)
result.size: (1334.0, 1000.0)
result.imageOrientation: 3

案例 3:iPhone 6 Plus (8.3)

风景:

asset.pixelWidth: 3264
asset.pixelHeight: 2448
targetSize: (1000.0, 750.0)
result.size: (1000.0, 750.0)
result.imageOrientation: 0

肖像:

asset.pixelWidth: 2448
asset.pixelHeight: 3264
targetSize: (1000.0, 1333.33333333333)
result.size: (1334.0, 1000.0)
result.imageOrientation: 3

结论

您可以从日志中看到 iOS 8.1.2 版本尊重为两个图像指定的targetSize,但 8.3 版本正在获取具有倒置尺寸的图像(请求 (1000.0, 1333.33) 但收到 (1334.0, 1000.0))。

现在,似乎我唯一的选择是检查正在运行的 iOS 版本,然后在请求具有旋转方向的图像时反转参数(我只测试了 UIImageOrientation.Right,但也有 .Left,@ 987654338@ 和 .RightMirrored)。

很遗憾,PHAsset 不包含图像的方向。我只能在向PHImageManager 请求图像后才能知道它,所以我必须对这些图像发出两次请求,一个获取方向,另一个获取正确的图像。

问题

我的逻辑有问题吗?或者这是iOS中的错误?如果这是一个错误,哪一个是正确的行为,iOS 8.3 还是旧版本?谁能提供其他选项来处理这个问题?

抱歉,帖子太长,英语不好。提前致谢!

【问题讨论】:

PHImageContentMode.AspectFill 你可以试试 PHImageContentMode.AspectFit 吗? 你解决过这个问题吗? 【参考方案1】:

我做了一个奇怪的解决方法:

func getAssetImage(asset: PHAsset, completion: (UIImage?) -> Void) 
    getAssetImage(asset, firstTry: true, completion: completion)


private func getAssetImage(asset: PHAsset, firstTry: Bool, completion: (UIImage?) -> Void) 
    let targetSize = CGSizeMake(1000, (CGFloat(asset.pixelHeight) / CGFloat(asset.pixelWidth)) * 1000)

    let options = PHImageRequestOptions()
    options.version = PHImageRequestOptionsVersion.Current
    options.deliveryMode =  PHImageRequestOptionsDeliveryMode.HighQualityFormat
    options.resizeMode = PHImageRequestOptionsResizeMode.Exact
    options.networkAccessAllowed = true

    PHImageManager.defaultManager().requestImageForAsset(asset, targetSize: targetSize, contentMode: PHImageContentMode.AspectFill, options: options)  (result: UIImage?, info) -> Void in
        let degraded = info?[PHImageResultIsDegradedKey] as? NSNumber

        if degraded != nil && !degraded!.boolValue 
            print("asset.pixelWidth: \(asset.pixelWidth)")
            print("asset.pixelHeight: \(asset.pixelHeight)")
            print("targetSize: \(targetSize)")
            print("result.size: \(result!.size)")
            print("result.imageOrientation: \(result!.imageOrientation.rawValue)")

            if (targetSize.width - targetSize.height) * (result!.size.width - result!.size.height) < 0 
                if firstTry 
                    print("Resulting image's dimensions are not in accordance with target size. Reversing dimensions!")
                    self.getAssetImage(asset, firstTry: false, completion: completion)
                 else 
                    print("Resulting image's dimensions are still not in accordance with target size. Giving up!")
                    completion(nil)
                

             else 
                completion(result)
            
        
    

这个解决方案的性能很值得怀疑,但它是处理这个问题的最可靠的方法之一。

【讨论】:

以上是关于在 iOS 8.3 中向 PHImageManager 请求图像会导致错误的图像的主要内容,如果未能解决你的问题,请参考以下文章

在 iOS 8.3 上获取 CellID、LAC、...

当设备连接由 iOS 8.3 供电时,设备在 Xcode 6.1 中不合格

自动布局在 ios 8.3 上无法正常工作

iOS 8.3:UIActivityViewController 显示无关的行

iOS 8.3:UIActivityViewController 显示无关的行

iOS 8.3 UIAlertController 在尝试添加文本字段时崩溃