如何在不损失视网膜显示质量的情况下将UIView捕获到UIImage

我的代码对普通设备工作正常,但在视网膜设备上创build模糊的图像。

有没有人知道我的问题的解决scheme?

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

从使用UIGraphicsBeginImageContext切换到UIGraphicsBeginImageContextWithOptions (如本页所述 )。 传递0.0作为比例(第三个参数),你将得到一个缩放因子等于屏幕的上下文。

UIGraphicsBeginImageContext使用1.0的固定比例因子,所以实际上iPhone 4上的图像与其他iPhone上的图像完全相同。 我敢打赌,iPhone 4正在应用一个filter,当你隐式地扩展它,或者只是你的大脑接近它而不是周围的一切。

所以,我猜:

 #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; } 

而在迅捷4:

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

目前接受的答案现在已经过时,至less如果你是支持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; } 

根据这篇文章 ,你可以看到,新的iOS7方法drawViewHierarchyInRect:afterScreenUpdates:renderInContext:要快很多倍。 基准http://f.cl.ly/items/323c000h013V2f3R2p3b/Screen%20Shot%202013-09-16%20at%2001.12.37%20.png

我已经基于@Dima解决scheme创build了一个Swift扩展:

 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 } } 

用法

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

要通过@Tommy和@Dima改进答案,请使用以下类别将UIView呈现为具有透明背景的 UIImage 并且不会损失质量。 在iOS7上工作。 (或者只是在实现中重用该方法,用图像replaceself引用)

UIView的+ RenderViewToImage.h

 #import <UIKit/UIKit.h> @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解决scheme(基于Dima的答案 )和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) } 

Swift 3.0的实现

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

所有斯威夫特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! } } 

embedded式Swift 3.0扩展,支持新的iOS 10.0 API和以前的方法。

注意:

  • iOS版本检查
  • 请注意使用延迟来简化上下文清理。
  • 也将应用视图的不透明度和当前比例。
  • 没有东西只是解开使用! 这可能会导致崩溃。

 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() } } } 

有时候drawRect方法会造成问题,所以我得到了更合适的答案。 你也可以看看它捕获UIView的UIImage卡在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; } 

在这个方法中只传递一个视图对象,它将返回一个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