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

Requesting images to PHImageManager results in wrong image in iOS 8.3

上下文

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

作为参考,我上传了几张图片到 imgur,在那里你可以找到我正在测试的原始图片,以及我截取的带有粉红色背景的 UIImageView 的屏幕截图,显示了 "Aspect Fit" 配置的获取图片.这是 link:http://imgur.com/a/VPJ9J

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

问题

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)
    }
}

测试

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

案例一:iPhone4S (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

案例二:iPhone5 (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:iPhone6 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.LeftMirrored.RightMirrored)。

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

问题

我的逻辑有问题吗?或者这是 iOS 中的错误?如果它是一个错误,那么哪个是正确的行为,iOS 8.3 的一个还是旧版本?任何人都可以提供其他选项来处理这个问题吗?

很抱歉 post,以及糟糕的英语。提前致谢!

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

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)
            }
        }
    }
}

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