При использовании различных расширений UIView для создания снимка UIView результат может казаться больше (как бы увеличенным), чем должен быть.
Я делаю снимки 2 UIViews, которые в дальнейшем мы можем назвать viewA и viewB.
видА: Представление добавляется в иерархию представлений при создании моментального снимка.
видБ:
Полностью определен, но еще не добавлено для иерархии представлений при создании моментального снимка. Затем снимок обрезается x раз, и результат добавляется в некоторые UIView для отображения.
Я протестировал 3 разных кода, чтобы получить результат, который я ищу: один обеспечивает нужные снимки снимков, но с низким качеством рендеринга; два других обеспечивают лучшее качество рендеринга изображения и правильный результат для видА, но для видБ, хотя снимок имеет правильный прямоугольник (я проверил прямоугольники), показанные изображения кажутся слишком большими (как если бы они были увеличены вдвое).
Расширение №1: дает правильные результаты, но с изображением низкого качества.
extension UIView {
func takeSnapshot() -> UIImage? {
UIGraphicsBeginImageContext(self.frame.size)
self.layer.render(in: UIGraphicsGetCurrentContext()!)
let snapshot = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return snapshot
}
}
Расширение №2: Обеспечивает правильное качество изображения, но обрезанные изображения viewB отображаются в два раза больше.
extension UIView {
func snapshot(of rect: CGRect? = nil, afterScreenUpdates: Bool = true) -> UIImage {
return UIGraphicsImageRenderer(bounds: rect ?? bounds).image { _ in
drawHierarchy(in: bounds, afterScreenUpdates: true)
}
}
}
Расширение №3: Аналогично, обеспечивает правильное качество изображения, но обрезанные изображения viewB отображаются в два раза больше.
extension UIView {
func takeScreenshot() -> UIImage {
UIGraphicsBeginImageContextWithOptions(self.bounds.size, false, UIScreen.main.scale)
drawHierarchy(in: self.bounds, afterScreenUpdates: true)
let image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
if (image != nil) { return image! }
return UIImage()
}
}
И последнее, но не менее важное: (упрощенный) код для извлечения обрезанных изображений из снимка.
for i in (0...numberOfCroppedImages) {
let rect = CGRect(x: CGFloat(i) * snapshot!.size.width / CGFloat(numberOfCroppedImages), y: 0, width: snapshot!.size.width / CGFloat(numberOfCroppedImages), height:snapshot!.size.height)
// defines the container view for the fragmented snapshots
let view = UIView()
view.frame = rect
// defines the layer with the fragment of the snapshot
let layer = CALayer()
layer.frame.size = rect.size
let img = snapshot?.cgImage?.cropping(to: rect)
layer.contents = img
view.layer.addSublayer(layer)
}
Я дважды проверил все CGRect и не обнаружил никаких проблем с ними: прямоугольники просмотра, а также размеры снимков кажутся ожидаемыми, тем не менее, у меня по-прежнему слишком большие визуализированные изображения с расширениями № 2 и № 3. для видБ (viewA отображается правильно), в то время как расширение № 1 дает изображения нужных размеров, но слишком низкого качества для адекватного использования.
Может проблема в drawInHierarchy(in: afterScreenUpdates:)? или, альтернативно, преобразование в cgImage с помощью
let img = snapshot?.cgImage?.cropping(to: rect) ?
Я был бы очень благодарен за любые указатели!





Я публикую решение, которое я нашел, которое работает для меня:
Во-первых, расширение моментального снимка, которое отображает (в моем случае) ожидаемые результаты (как по качеству, так и по размеру), независимо от того, добавлено ли представление в иерархию или нет, обрезано или нет:
extension UIView {
func takeSnapshot(of rect: CGRect? = nil, afterScreenUpdates: Bool = true) -> UIImage {
return UIGraphicsImageRenderer(bounds: rect ?? bounds).image { (context) in
self.layer.render(in: context.cgContext)
}
}
}
Затем обновленная версия кода, который делает снимок прямоугольника в представлении:
let view = UIView()
view.frame = rect
let img = self.takeSnapshot(of: rect, afterScreenUpdates: true).cgImage
view.layer.contents = img
Отличие здесь состоит в том, что делается снимок прямоугольника в представлении, а не кадрируется снимок всего вида.
Надеюсь, это поможет.