Простое решение состоит в том, чтобы просто визуализировать изображение в определенном CGRect
:
func snapshot(in imageView: UIImageView, rect: CGRect) -> UIImage {
return UIGraphicsImageRenderer(bounds: rect).image { _ in
imageView.drawHierarchy(in: imageView.bounds, afterScreenUpdates: true)
}
}
Ограничение этого подхода состоит в том, что если изображение имеет значительно более высокое разрешение, чем может отображать представление изображения (как это часто бывает, когда мы используем «подгонку масштаба»), вы потеряете эту дополнительную точность.
Если вы хотите сохранить разрешение, вам следует преобразовать CGRect
в координаты с изображением, в этом случае, при условии «подгонки масштаба изображения» (а именно, по центру и масштабированию, чтобы показать все изображение):
func snapshot(in imageView: UIImageView, rect: CGRect) -> UIImage {
assert(imageView.contentMode == .scaleAspectFit)
let image = imageView.image!
// figure out what the scale is
let imageRatio = imageView.bounds.width / imageView.bounds.height
let imageViewRatio = image.size.width / image.size.height
let scale: CGFloat
if imageRatio > imageViewRatio {
scale = image.size.height / imageView.bounds.height
} else {
scale = image.size.width / imageView.bounds.width
}
// convert the `rect` into coordinates within the image, itself
let size = rect.size * scale
let origin = CGPoint(x: image.size.width / 2 - (imageView.bounds.midX - rect.minX) * scale,
y: image.size.height / 2 - (imageView.bounds.midY - rect.minY) * scale)
let scaledRect = CGRect(origin: origin, size: size)
// now render the image and grab the appropriate rectangle within
// the image’s coordinate system
let format = UIGraphicsImageRendererFormat()
format.scale = image.scale
format.opaque = false
return UIGraphicsImageRenderer(bounds: scaledRect, format: format).image { _ in
image.draw(at: .zero)
}
}
Использование этого расширения:
extension CGSize {
static func * (lhs: CGSize, rhs: CGFloat) -> CGSize {
return CGSize(width: lhs.width * rhs, height: lhs.height * rhs)
}
}
Что дает: