ios - 在共享扩展中旋转图像

标签 ios swift ios-app-extension share-extension

我有这个扩展,它在应用程序目标中运行完美,但在尝试旋转相机捕获的图像时在共享扩展中崩溃。如何在共享扩展中旋转图像?或者也许可以从照片库中以正确的方向加载图像。

extension UIImage {

    func fixOrientation() -> UIImage {
        switch imageOrientation {
        case .up:
            return self
        default:
            UIGraphicsBeginImageContextWithOptions(size, false, scale)
            draw(in: CGRect(origin: .zero, size: size)) //Thread 1: EXC_RESOURCE RESOURCE_TYPE_MEMORY (limit=120 MB, unused=0x0)
            let result = UIGraphicsGetImageFromCurrentImageContext()
            UIGraphicsEndImageContext()
            return result!
        }
    }
}


崩溃截图:

crash screenshot #1 crash screenshot #2

最佳答案

首先很明显你遇到了内存崩溃。根据App Extension Programming Guide :

Memory limits for running app extensions are significantly lower than the memory limits imposed on a foreground app. On both platforms, the system may aggressively terminate extensions because users want to return to their main goal in the host app.

从错误中可以明显看出您超过了 120 MB。但您可能想知道是什么占用了这么多内存。

根据 Optimizing Images Written by Jordan Morgan :

iOS essentially derives its memory hit from an image’s dimensions - whereas the actual file size has much less to do with it.

因此,如果我们计算尺寸或 4032 x 3024 照片,它将是……4 位颜色为 46mb,8 位颜色为 79mb。相当大,但还不到极限......

事情是 - 你有你的图像的两个副本。一个是原始的,第二个是旋转的。

要解决此问题,您只需将旋转后的图像加载到内存中,而不需要原始图像。这可以通过 Image I/O Framework 来完成:

extension UIImage {
    static func imageWithFixedOrientation(at url: URL) -> UIImage? {
        guard let imageSource = CGImageSourceCreateWithURL(url as CFURL, nil) else { return nil }

        guard let imageProperties = CGImageSourceCopyPropertiesAtIndex(imageSource, 0, nil) as? Dictionary<CFString, Any> else { return nil }

        guard
            let width = imageProperties[kCGImagePropertyPixelWidth] as? CGFloat,
            let height = imageProperties[kCGImagePropertyPixelHeight] as? CGFloat
            else { return nil }

        let options: [NSString: Any] = [
            kCGImageSourceThumbnailMaxPixelSize: max(width, height),
            kCGImageSourceCreateThumbnailFromImageAlways: true,
            kCGImageSourceCreateThumbnailWithTransform: true
        ]

        guard let cgImage = CGImageSourceCreateThumbnailAtIndex(imageSource, 0, options as CFDictionary) else { return nil }

        return UIImage(cgImage: cgImage)
    }
}

在示例应用中:

extension ViewController: UIImagePickerControllerDelegate & UINavigationControllerDelegate {
    func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
        picker.dismiss(animated: true)
        guard let url = info[.imageURL] as? URL else { return }

        let image = UIImage.imageWithFixedOrientation(at: url)
    }
}

它将内存峰值从 180+mb 减少到仅 80mb。

关于ios - 在共享扩展中旋转图像,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57008915/

相关文章:

ios - 如何为 Google VR iOS pod 添加触摸手势?

swift - 你能帮我理解这个 Swift 方法吗?

ios - 使用 AVPlayer 实现流畅的视频擦洗

ios - 如何从应用程序中删除 ios Today 扩展

ios - 暂时禁用键盘扩展的旋转

ios - iOS 键盘扩展中的 Coredata

ios - 开始Skype通话时如何处理UI?

ios - 如何在不阻止用户与 UIWebView 交互的情况下在 UIWebView 上显示覆盖

ios - GCD : How to check if the task is runnig

ios - 无法在 Swift 上设置/获取映射对象数组到 userDefaults