在共享扩展中旋转图像
Rotate image in 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!
}
}
}
崩溃截图:
您是否尝试过使用您在 didFinishPicking
委托方法中提供的功能?
func photoLibrary() {
if UIImagePickerController.isSourceTypeAvailable(.photoLibrary) {
let myPickerController = UIImagePickerController()
myPickerController.delegate = self
myPickerController.sourceType = .photoLibrary
self.present(myPickerController, animated: true, completion: nil)
}
}
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
picker.dismiss(animated: true)
guard let image = info[.originalImage] as? UIImage else {
print("No image found")
return
}
// Flip the image here
self.mainImageView.image = image.fixOrientation()
}
您可以尝试使用更优化的 UIGraphicsImageRendererFormat
而不是使用旧的 UIGraphicsBeginImageContextWithOptions
,您可以在此 post 中找到更多信息。所以您的代码将如下所示:
func fixOrientation() -> UIImage {
let format = UIGraphicsImageRendererFormat()
format.scale = scale
format.prefersExtendedRange = true
let renderer = UIGraphicsImageRenderer(size: size, format: format)
let image = renderer.image(actions: { context in
var workSize = size;
workSize.width = floor(workSize.width / scale)
workSize.height = floor(workSize.height / scale)
// if the orientation is already correct
// if image.imageOrientation == .up { draw image }
var transform = CGAffineTransform.identity
//TO-DO - set transform depends on current image orientation
//transform =
let ctx = context.cgContext
ctx.concatenate(transform)
guard let cgImageCopy = cgImage else {
return
}
switch imageOrientation {
case .left, .leftMirrored, .right, .rightMirrored:
ctx.draw(cgImageCopy, in: CGRect(x: 0.0, y:0.0, width: workSize.height, height: workSize.width))
break;
default:
ctx.draw(cgImageCopy, in: CGRect(origin: .zero, size: workSize))
break;
}
})
return image
}
首先很明显你的内存崩溃了。根据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。但是你可能想知道是什么占用了这么多内存。
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。
我有这个扩展程序,它在应用程序目标中运行完美,但在尝试旋转相机捕获的图像时共享扩展程序崩溃。如何在共享扩展中旋转图像?或者也许可以从照片库中以正确的方向加载图像。
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!
}
}
}
崩溃截图:
您是否尝试过使用您在 didFinishPicking
委托方法中提供的功能?
func photoLibrary() {
if UIImagePickerController.isSourceTypeAvailable(.photoLibrary) {
let myPickerController = UIImagePickerController()
myPickerController.delegate = self
myPickerController.sourceType = .photoLibrary
self.present(myPickerController, animated: true, completion: nil)
}
}
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
picker.dismiss(animated: true)
guard let image = info[.originalImage] as? UIImage else {
print("No image found")
return
}
// Flip the image here
self.mainImageView.image = image.fixOrientation()
}
您可以尝试使用更优化的 UIGraphicsImageRendererFormat
而不是使用旧的 UIGraphicsBeginImageContextWithOptions
,您可以在此 post 中找到更多信息。所以您的代码将如下所示:
func fixOrientation() -> UIImage {
let format = UIGraphicsImageRendererFormat()
format.scale = scale
format.prefersExtendedRange = true
let renderer = UIGraphicsImageRenderer(size: size, format: format)
let image = renderer.image(actions: { context in
var workSize = size;
workSize.width = floor(workSize.width / scale)
workSize.height = floor(workSize.height / scale)
// if the orientation is already correct
// if image.imageOrientation == .up { draw image }
var transform = CGAffineTransform.identity
//TO-DO - set transform depends on current image orientation
//transform =
let ctx = context.cgContext
ctx.concatenate(transform)
guard let cgImageCopy = cgImage else {
return
}
switch imageOrientation {
case .left, .leftMirrored, .right, .rightMirrored:
ctx.draw(cgImageCopy, in: CGRect(x: 0.0, y:0.0, width: workSize.height, height: workSize.width))
break;
default:
ctx.draw(cgImageCopy, in: CGRect(origin: .zero, size: workSize))
break;
}
})
return image
}
首先很明显你的内存崩溃了。根据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。但是你可能想知道是什么占用了这么多内存。
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。