Как захватить UIView к UIImage без потери качества на дисплее сетчатки
мой код отлично работает для обычных устройств, но создает размытые изображения на устройствах retina.
кто-нибудь знает решение моей проблемы?
+ (UIImage *) imageWithView:(UIView *)view
{
UIGraphicsBeginImageContext(view.bounds.size);
[view.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage * img = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return img;
}
15 ответов:
переход от использования
UIGraphicsBeginImageContextдоUIGraphicsBeginImageContextWithOptions(см. на этой странице). Пройти 0.0 по шкале (третий аргумент) и вы получите в связи с масштабным коэффициентом, равным экрана.
UIGraphicsBeginImageContextиспользует фиксированный масштабный коэффициент 1,0, так что вы на самом деле получаете точно такое же изображение на iPhone 4, как и на других iPhone. Я готов поспорить, что либо iPhone 4 применяет фильтр, когда вы неявно масштабируете его, либо просто ваш мозг воспринимает его менее острым чем все вокруг.Итак, я думаю:
#import <QuartzCore/QuartzCore.h> + (UIImage *)imageWithView:(UIView *)view { UIGraphicsBeginImageContextWithOptions(view.bounds.size, view.opaque, 0.0); [view.layer renderInContext:UIGraphicsGetCurrentContext()]; UIImage * img = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); return img; }и в swift 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; }Swift 4:
func imageWithView(view: UIView) -> UIImage? { UIGraphicsBeginImageContextWithOptions(view.bounds.size, view.isOpaque, 0.0) view.drawHierarchy(in: view.bounds, afterScreenUpdates: true) let snapshotImage = UIGraphicsGetImageFromCurrentImageContext() UIGraphicsEndImageContext() return snapshotImage }по состоянию на в этой статье, вы можете видеть, что новый метод iOS7
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 <UIKit/UIKit.h> @interface UIView (RenderToImage) - (UIImage *)imageByRenderingView; @endUIView+RenderViewToImage.м
#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
используя современный 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 3
The 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 } }
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 расширение, которое поддерживает новый iOS 10.0 API & предыдущий метод.
Примечание:
- проверка версии 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; }
вот Свифт 4 расширение UIView на основе ответа от @Dima.
extension UIView { func image () -> UIImage? { UIGraphicsBeginImageContextWithOptions(bounds.size, isOpaque, 0) drawHierarchy(in: bounds, afterScreenUpdates: false) let image = UIGraphicsGetImageFromCurrentImageContext() UIGraphicsEndImageContext() return image } }
в этом методе просто передайте объект view, и он вернет объект 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; }

Comments