使用 Core Graphics 从外部存储加载图像不起作用 iOS 13

Loading images from external storage using Core Graphics not working iOS 13

我正在尝试使用 iOS 13(测试版)中的核心显卡加载位于外部存储器(SD 卡)上的照片。当文件在设备上时,下面的代码可以正常工作。当文件在外部存储上时,它无法返回 nil,我不知道为什么。

我相信我正在使用正确的安全范围。 我根据 Providing Access to Directories

从安全范围的文件夹 url 加载了文件 URL
guard folderUrl.startAccessingSecurityScopedResource() else {
    return nil
}
defer { folderUrl.stopAccessingSecurityScopedResource() }

guard let imageSource = CGImageSourceCreateWithURL(imageURL as CFURL, options) else {
    throw Error.failedToOpenImage(message: "Failed to open image at \(imageURL)")
}

所以...对于我自己的项目,我 运行 遇到了同样的问题,我现在有以下功能可以给我一个缩略图,从优雅和快速到蛮力。

static func thumbnailForImage(at url: URL, completion: (Result<UIImage, Error>) -> Void) {
    let shouldStopAccessing = url.startAccessingSecurityScopedResource()
    defer { if shouldStopAccessing { url.stopAccessingSecurityScopedResource() } }

    let coordinator = NSFileCoordinator()
    var error: NSError?

    coordinator.coordinate(readingItemAt: url, options: .withoutChanges, error: &error) { url in

        var thumbnailImage: UIImage?
        var storedError: NSError?
        var imageSource: CGImageSource?

        print("Strategy 1: Via URL resource key")
        do {
            let resourceKeys = Set([URLResourceKey.thumbnailDictionaryKey])
            let resources = try url.resourceValues(forKeys: resourceKeys)
            if let dict = resources.thumbnailDictionary, let resource = dict[URLThumbnailDictionaryItem.NSThumbnail1024x1024SizeKey] {
                thumbnailImage = resource
            } else {
                throw "No thumbnail dictionary"
            }
        } catch let error {
            storedError = error as NSError
        }

        let options = [kCGImageSourceCreateThumbnailFromImageIfAbsent: true, kCGImageSourceShouldAllowFloat: true, kCGImageSourceCreateThumbnailWithTransform: true]

        if thumbnailImage == nil {
            print("Strategy 2: Via CGImageSourceCreateWithURL")
            imageSource = CGImageSourceCreateWithURL(url as CFURL, options as CFDictionary)
        }

        if thumbnailImage == nil && imageSource == nil {
            print("Strategy 3: Via CGImageSourceCreateWithData")

            let data = try? Data.init(contentsOf: url)
            if let data = data {
                imageSource = CGImageSourceCreateWithData(data as CFData, options as CFDictionary)
            }
        }

        if let imageSource = imageSource, thumbnailImage == nil {
            print("Attempting thumbnail creation from source created in strategy 2 or 3")

            if let image = CGImageSourceCreateThumbnailAtIndex(imageSource, 0, options as CFDictionary) {
                thumbnailImage = UIImage(cgImage: image)
            }
        }

        if let thumbnailImage = thumbnailImage {
            print("Success")
            completion(.success(thumbnailImage))
        } else {
            print("Failure")
            if let error = storedError { completion(.failure(error)) }
            else { completion(.failure("Everything just fails...")) }
        }
    }

    if let error = error { completion(.failure(error)) }
}

基本上它的工作原理是首先尝试通过 URL 资源获取缩略图。这是最快和最好的方法。如果失败,我会尝试 CGImageSourceCreateWithURL。这在大多数情况下都有效,但在远程存储上除外。我怀疑这仍然是一个错误并为此向苹果提交了反馈票。我建议你这样做。最后一次尝试,尝试使用 NSData 读取整个文件并通过 CGImageSourceCreateWithData...

创建图像源

到目前为止,如果是图像文件 I,这似乎大多数时候都会生成缩略图。但是它可能会很慢,必须读取整个文件。