如何在不损失视网膜显示质量的情况下将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 } }
使用现代的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; }