Как захватить UIView в UIImage без потери качества на дисплее сетчатки

Мой код работает нормально для обычных устройств, но создает размытые изображения на сетчатых устройствах.

Кто-нибудь знает решение моей проблемы?

+ (UIImage *) imageWithView:(UIView *)view { UIGraphicsBeginImageContext(view.bounds.size); [view.layer renderInContext:UIGraphicsGetCurrentContext()]; UIImage * img = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); return img; } 

    Переключитесь с использования UIGraphicsBeginImageContext в UIGraphicsBeginImageContextWithOptions (как UIGraphicsBeginImageContextWithOptions на этой странице ). Пропустите 0.0 для шкалы (третий аргумент), и вы получите контекст с коэффициентом масштабирования, равным коэффициенту масштабирования экрана.

    UIGraphicsBeginImageContext использует фиксированный коэффициент масштабирования 1,0, поэтому вы фактически получаете точно такое же изображение на iPhone 4, как и на других iPhone. Я буду держать пари, что iPhone 4 применяет фильтр, когда вы неявно масштабируете его или просто ваш мозг набирает на него менее резкое, чем все вокруг.

    Так что я думаю:

     #import  + (UIImage *)imageWithView:(UIView *)view { UIGraphicsBeginImageContextWithOptions(view.bounds.size, view.opaque, 0.0); [view.layer renderInContext:UIGraphicsGetCurrentContext()]; UIImage * img = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); return img; } 

    И в быстрой 4:

     func image(with view: UIView) -> UIImage? { UIGraphicsBeginImageContextWithOptions(view.bounds.size, view.isOpaque, 0.0) defer { UIGraphicsEndImageContext() } if let context = UIGraphicsGetCurrentContext() { view.layer.render(in: context) let image = UIGraphicsGetImageFromCurrentImageContext() return image } return nil } 

    Текущий принятый ответ теперь устарел, по крайней мере, если вы поддерживаете iOS 7.

    Вот что вы должны использовать, если поддерживаете только iOS7 +:

     + (UIImage *) imageWithView:(UIView *)view { UIGraphicsBeginImageContextWithOptions(view.bounds.size, view.opaque, 0.0f); [view drawViewHierarchyInRect:view.bounds afterScreenUpdates:NO]; UIImage * snapshotImage = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); return snapshotImage; } 

    В соответствии с этой статьей вы можете видеть, что новый метод drawViewHierarchyInRect:afterScreenUpdates: во много раз быстрее, чем renderInContext: эталонный тест

    Я создал расширение Swift на основе решения @Dima:

     extension UIImage { class func imageWithView(view: UIView) -> UIImage { UIGraphicsBeginImageContextWithOptions(view.bounds.size, view.opaque, 0.0) view.drawViewHierarchyInRect(view.bounds, afterScreenUpdates: true) let img = UIGraphicsGetImageFromCurrentImageContext() UIGraphicsEndImageContext() return img } } 

    EDIT: улучшенная версия Swift 4

     extension UIImage { class func imageWithView(_ view: UIView) -> UIImage { UIGraphicsBeginImageContextWithOptions(view.bounds.size, view.isOpaque, 0) defer { UIGraphicsEndImageContext() } view.drawHierarchy(in: view.bounds, afterScreenUpdates: true) return UIGraphicsGetImageFromCurrentImageContext() ?? UIImage() } } 

    Применение:

     let view = UIView(frame: CGRect(x: 0, y: 0, width: 100, height: 100)) let image = UIImage.imageWithView(view) 

    Чтобы улучшить ответы @Tommy и @Dima, используйте следующую категорию, чтобы отобразить UIView в UIImage с прозрачным фоном и без потери качества. Работа с iOS7. (Или просто повторно использовать этот метод в реализации, заменив self вашим изображением)

    UIView + RenderViewToImage.h

     #import  @interface UIView (RenderToImage) - (UIImage *)imageByRenderingView; @end 

    UIView + RenderViewToImage.m

     #import "UIView+RenderViewToImage.h" @implementation UIView (RenderViewToImage) - (UIImage *)imageByRenderingView { UIGraphicsBeginImageContextWithOptions(self.bounds.size, NO, 0.0); [self drawViewHierarchyInRect:self.bounds afterScreenUpdates:YES]; UIImage * snapshotImage = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); return snapshotImage; } @end 

    Swift 3

    Решение Swift 3 (на основе ответа Димы ) с расширением UIView должно быть таким:

     extension UIView { public func getSnapshotImage() -> UIImage { UIGraphicsBeginImageContextWithOptions(self.bounds.size, self.isOpaque, 0) self.drawHierarchy(in: self.bounds, afterScreenUpdates: false) let snapshotImage: UIImage = UIGraphicsGetImageFromCurrentImageContext()! UIGraphicsEndImageContext() return snapshotImage } } 

    IOSстриж

    Использование современного UIGraphicsImageRenderer

     public extension UIView { @available(iOS 10.0, *) public func renderToImage(afterScreenUpdates: Bool = false) -> UIImage { let rendererFormat = UIGraphicsImageRendererFormat.default() rendererFormat.opaque = isOpaque let renderer = UIGraphicsImageRenderer(size: bounds.size, format: rendererFormat) let snapshotImage = renderer.image { _ in drawHierarchy(in: bounds, afterScreenUpdates: afterScreenUpdates) } return snapshotImage } } 

    Swift 2.0:

    Использование метода расширения:

     extension UIImage{ class func renderUIViewToImage(viewToBeRendered:UIView?) -> UIImage { UIGraphicsBeginImageContextWithOptions((viewToBeRendered?.bounds.size)!, false, 0.0) viewToBeRendered!.drawViewHierarchyInRect(viewToBeRendered!.bounds, afterScreenUpdates: true) viewToBeRendered!.layer.renderInContext(UIGraphicsGetCurrentContext()!) let finalImage = UIGraphicsGetImageFromCurrentImageContext() UIGraphicsEndImageContext() return finalImage } } 

    Применение:

     override func viewDidLoad() { super.viewDidLoad() //Sample View To Self.view let sampleView = UIView(frame: CGRectMake(100,100,200,200)) sampleView.backgroundColor = UIColor(patternImage: UIImage(named: "ic_120x120")!) self.view.addSubview(sampleView) //ImageView With Image let sampleImageView = UIImageView(frame: CGRectMake(100,400,200,200)) //sampleView is rendered to sampleImage var sampleImage = UIImage.renderUIViewToImage(sampleView) sampleImageView.image = sampleImage self.view.addSubview(sampleImageView) } 

    Расширение Drop-in Swift 3.0, поддерживающее новый API iOS 10.0 и предыдущий метод.

    Заметка:

    • Проверка версии iOS
    • Обратите внимание на использование defer для упрощения очистки контекста.
    • Будет также применяться непрозрачность и текущий масштаб представления.
    • Ничто не просто распакуется ! что может привести к сбою.

     extension UIView { public func renderToImage(afterScreenUpdates: Bool = false) -> UIImage? { if #available(iOS 10.0, *) { let rendererFormat = UIGraphicsImageRendererFormat.default() rendererFormat.scale = self.layer.contentsScale rendererFormat.opaque = self.isOpaque let renderer = UIGraphicsImageRenderer(size: self.bounds.size, format: rendererFormat) return renderer.image { _ in self.drawHierarchy(in: self.bounds, afterScreenUpdates: afterScreenUpdates) } } else { UIGraphicsBeginImageContextWithOptions(self.bounds.size, self.isOpaque, self.layer.contentsScale) defer { UIGraphicsEndImageContext() } self.drawHierarchy(in: self.bounds, afterScreenUpdates: afterScreenUpdates) return UIGraphicsGetImageFromCurrentImageContext() } } } 

    Внедрение Swift 3.0

     extension UIView { func getSnapshotImage() -> UIImage { UIGraphicsBeginImageContextWithOptions(bounds.size, isOpaque, 0) drawHierarchy(in: bounds, afterScreenUpdates: false) let snapshotImage = UIGraphicsGetImageFromCurrentImageContext()! UIGraphicsEndImageContext() return snapshotImage } } 

    Все ответы Swift 3 не работали для меня, поэтому я перевел наиболее приемлемый ответ:

     extension UIImage { class func imageWithView(view: UIView) -> UIImage { UIGraphicsBeginImageContextWithOptions(view.bounds.size, view.isOpaque, 0.0) view.layer.render(in: UIGraphicsGetCurrentContext()!) let img: UIImage? = UIGraphicsGetImageFromCurrentImageContext() UIGraphicsEndImageContext() return img! } } 

    Несколько раз метод drawRect создает проблему, поэтому я получил ответы более подходящими. Вы тоже можете посмотреть на него. Захват UIImage UIView застрял в методе DrawRect

     - (UIImage*)screenshotForView:(UIView *)view { UIGraphicsBeginImageContext(view.bounds.size); [view.layer renderInContext:UIGraphicsGetCurrentContext()]; UIImage *image = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); // hack, helps w/ our colors when blurring NSData *imageData = UIImageJPEGRepresentation(image, 1); // convert to jpeg image = [UIImage imageWithData:imageData]; return image; } 

    Вот расширение Swift 4 UIView, основанное на ответе от @Dima.

     extension UIView { func image () -> UIImage? { UIGraphicsBeginImageContextWithOptions(bounds.size, isOpaque, 0) drawHierarchy(in: bounds, afterScreenUpdates: false) let image = UIGraphicsGetImageFromCurrentImageContext() UIGraphicsEndImageContext() return image } } 

    В этом методе просто передается объект вида, и он возвращает объект UIImage.

     -(UIImage*)getUIImageFromView:(UIView*)yourView { UIGraphicsBeginImageContext(yourView.bounds.size); [yourView.layer renderInContext:UIGraphicsGetCurrentContext()]; UIImage *image = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); return image; } 

    Добавьте этот метод в категорию UIView

     - (UIImage*) capture { UIGraphicsBeginImageContext(self.bounds.size); CGContextRef context = UIGraphicsGetCurrentContext(); [self.layer renderInContext:context]; UIImage *img = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); return img; } 
    Interesting Posts

    Как использовать источник данных JNDI, предоставленный Tomcat весной?

    Как разбирать строку JSON в массиве с помощью Jackson

    UnsupportedOperationException при попытке удалить из списка, возвращаемого Array.asList

    Как добавить Linux в новый менеджер загрузки Windows 8?

    Как использовать инструменты Entity Framework Power Tools в Visual Studio 2015?

    Использование пользовательских шрифтов с использованием CSS?

    Найдите необработанные ветви Гита?

    Как предотвратить закрытие диалогового windows при нажатии кнопки

    Клиент Node.js WebRTC

    Почему большинство моих MP3-дисков отображаются как «неизвестный художник / альбом» в Zune Software?

    Как я могу тестировать метод controllerа, который имеет атрибут ?

    Клавиша Remap на ноутбуке Gateway

    mysql проверяет, находятся ли числа в списке, разделенном запятыми

    Android: java.lang.OutOfMemoryError: не удалось выделить выделение байтов 23970828 с 2097152 бесплатными байтами и 2 МБ до тех пор, пока OOM

    Как удалить hiberfil.sys

    Давайте будем гением компьютера.