如何将UIView转换为图像
我想将UIView转换为图像并将其保存在我的应用程序中。 有人可以告诉我如何截图视图或将其转换为图像,什么是最好的方法来保存在一个应用程序(不相机胶卷)? 这里是视图的代码:
var overView = UIView(frame: CGRectMake(0, 0, self.view.frame.width/1.3, self.view.frame.height/1.3)) overView.center = CGPointMake(CGRectGetMidX(self.view.bounds), CGRectGetMidY(self.view.bounds)-self.view.frame.height/16); overView.backgroundColor = UIColor.whiteColor() self.view.addSubview(overView) self.view.bringSubviewToFront(overView)
你可以使用扩展
extension UIImage { convenience init(view: UIView) { UIGraphicsBeginImageContext(view.frame.size) view.layer.render(in:UIGraphicsGetCurrentContext()!) let image = UIGraphicsGetImageFromCurrentImageContext() UIGraphicsEndImageContext() self.init(cgImage: image!.cgImage!) } }
这里快速的3/4版本:
extension UIImage { convenience init(view: UIView) { UIGraphicsBeginImageContext(view.frame.size) view.layer.render(in:UIGraphicsGetCurrentContext()!) let image = UIGraphicsGetImageFromCurrentImageContext() UIGraphicsEndImageContext() self.init(cgImage: image!.cgImage!) } }
通过drawViewHierarchyInRect将你的UIView转换成图像:afterScreenUpdates:这比renderInContext快很多倍
重要提示:不要从viewDidLoad或viewWillAppear调用这个函数,确保在显示/加载完成后捕获视图
Obj C
UIGraphicsBeginImageContextWithOptions(myView.bounds.size, myView.opaque, 0.0f); [myView drawViewHierarchyInRect:myView.bounds afterScreenUpdates:NO]; UIImage *snapshotImageFromMyView = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); myImageView.image = snapshotImageFromMyView;
保存编辑后的图片相册
UIImageWriteToSavedPhotosAlbum(snapshotImageFromMyView, nil,nil, nil);
Swift 3
UIGraphicsBeginImageContextWithOptions(myView.bounds.size, myView.isOpaque, 0.0) myView.drawHierarchy(in: myView.bounds, afterScreenUpdates: false) let snapshotImageFromMyView = UIGraphicsGetImageFromCurrentImageContext() UIGraphicsEndImageContext() print(snapshotImageFromMyView) myImageView.image = snapshotImageFromMyView
超级简单泛化与扩展,iOS10,Swift3
extension UIImage{ convenience init(view: UIView) { UIGraphicsBeginImageContextWithOptions(view.bounds.size, view.isOpaque, 0.0) view.drawHierarchy(in: view.bounds, afterScreenUpdates: false) let image = UIGraphicsGetImageFromCurrentImageContext() UIGraphicsEndImageContext() self.init(cgImage: (image?.cgImage)!) } } Use : //myView is completly loaded/visible , calling this code after only after viewDidAppear is call imgVV.image = UIImage.init(view: myView) // Simple image object let img = UIImage.init(view: myView)
在UIView
上的扩展应该做的伎俩。
extension UIView { // Using a function since `var image` might conflict with an existing variable // (like on `UIImageView`) func asImage() -> UIImage { let renderer = UIGraphicsImageRenderer(bounds: bounds) return renderer.image { rendererContext in layer.render(in: rendererContext.cgContext) } } }
苹果劝阻使用UIGraphicsBeginImageContext
从iOS 10开始,并引入P3色域。 UIGraphicsBeginImageContext
只有sRGB和32位。 他们介绍了全新的UIGraphicsImageRenderer
API,它是完全由色彩pipe理的,基于块的,具有PDF和图像的子类,并自动pipe理上下文生存期。 查看WWDC16会话205获取更多细节(图像渲染在11:50分左右开始)
在iOS 10上:
extension UIImage { convenience init(view: UIView) { UIGraphicsBeginImageContext(view.frame.size) view.layer.render(in: UIGraphicsGetCurrentContext()!) let image = UIGraphicsGetImageFromCurrentImageContext() UIGraphicsEndImageContext() self.init(cgImage: (image?.cgImage)!) } }
UIGraphicsBeginImageContext(self.view.bounds.size); self.view.layer.renderInContext(UIGraphicsGetCurrentContext()) var screenShot = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext();
例如,如果我有一个大小的观点:50 50 100 100。 我可以使用下面的截图:
UIGraphicsBeginImageContextWithOptions(CGSizeMake(100, 100), false, 0); self.view.drawViewHierarchyInRect(CGRectMake(-50,-5-,view.bounds.size.width,view.bounds.size.height), afterScreenUpdates: true) var image:UIImage = UIGraphicsGetImageFromCurrentImageContext();
在我看来,与初始化的方法并不是那么好,因为它创build了两个图像。
我更喜欢这个:
extension UIView { var snapshot: UIImage? { UIGraphicsBeginImageContext(self.frame.size) guard let context = UIGraphicsGetCurrentContext() else { return nil } layer.render(in: context) let image = UIGraphicsGetImageFromCurrentImageContext() UIGraphicsEndImageContext() return image } }
截至iOS 10和Swift 3的最佳实践
同时还支持iOS 9及更早版本
extension UIView { func asImage() -> UIImage? { if #available(iOS 10.0, *) { let renderer = UIGraphicsImageRenderer(bounds: bounds) return renderer.image { rendererContext in layer.render(in: rendererContext.cgContext) } } else { UIGraphicsBeginImageContextWithOptions(self.bounds.size, self.isOpaque, 0.0) defer { UIGraphicsEndImageContext() } guard let currentContext = UIGraphicsGetCurrentContext() else { return nil } self.layer.render(in: currentContext) return UIGraphicsGetImageFromCurrentImageContext() } } }
我不确定这个问题意味着什么:
什么是最好的方式来保存在一个应用程序(不相机胶卷)?
var snapshot = overView.snapshotViewAfterScreenUpdates(false)
或者在Objective-C中
UIView* snapshot = [overView snapshotViewAfterScreenUpdates:NO];
这适用于我的Xcode 9 / Swift 3.2 / Swift 4和Xcode 8 / Swift 3
if #available(iOS 10.0, *) { // for Xcode 9/Swift 3.2/Swift 4 -Paul Hudson's code let renderer = UIGraphicsImageRenderer(size: view!.bounds.size) let capturedImage = renderer.image { (ctx) in view!.drawHierarchy(in: view!.bounds, afterScreenUpdates: true) } return capturedImage } else { // for Xcode 8/Swift 3 UIGraphicsBeginImageContextWithOptions((view!.bounds.size), view!.isOpaque, 0.0) view!.drawHierarchy(in: view!.bounds, afterScreenUpdates: false) let capturedImage = UIGraphicsGetImageFromCurrentImageContext() UIGraphicsEndImageContext() return capturedImage! }
以下是如何在一个函数中使用它:
fileprivate func captureUIImageFromUIView(_ view:UIView?) -> UIImage { guard (view != nil) else{ // if the view is nil (it's happened to me) return an alternative image let errorImage = UIImage(named: "Error Image") return errorImage } // if the view is all good then convert the image inside the view to a uiimage if #available(iOS 10.0, *) { let renderer = UIGraphicsImageRenderer(size: view!.bounds.size) let capturedImage = renderer.image { (ctx) in view!.drawHierarchy(in: view!.bounds, afterScreenUpdates: true) } return capturedImage } else { UIGraphicsBeginImageContextWithOptions((view!.bounds.size), view!.isOpaque, 0.0) view!.drawHierarchy(in: view!.bounds, afterScreenUpdates: false) let capturedImage = UIGraphicsGetImageFromCurrentImageContext() UIGraphicsEndImageContext() return capturedImage! } }
以下是如何处理从函数返回的图像:
@IBOutlet weak fileprivate var myCustomView: UIView! fileprivate var myPic: UIImage? @IBAction fileprivate func saveImageButtonTapped(_ sender: UIButton) { myPic = captureUIImageFromUIView(myCustomView) //safely unwrap myPic and do something with it }
我得到了保罗·哈德森的Xcode 9 / Swift 3.2 / Swift 4的答案在uiview中将图像转换为uiimage
我从某个地方得到了Xcode 8 / Swift 3 ,所以我忘记了在哪里:(
或iOS 10或更高版本,您可以使用新的UIGraphicsImageRenderer +推荐的drawHierarchy,在某些情况下,它可能比layer.renderInContext
extension UIView { func asImage() -> UIImage { let renderer = UIGraphicsImageRenderer(size: self.bounds.size) return renderer.image { _ in self.drawHierarchy(in: CGRect(x: 0, y: 0, width: bounds.size.width, height: bounds.size.height), afterScreenUpdates: false) } } }
您可以使用这样的扩展名轻松使用它
// Take a snapshot from a view (just one view) let viewSnapshot = myView.snapshot // Take a screenshot (with every views in screen) let screenSnapshot = UIApplication.shared.snapshot // Take a snapshot from UIImage initialization UIImage(view: self.view)
如果你想使用这些扩展方法/variables,实现这一点
-
UIImage扩展
extension UIImage { convenience init(view: UIView) { if let cgImage = view.snapshot?.cgImage { self.init(cgImage: cgImage) } else { self.init() } } }
-
UIView扩展
extension UIView { var snapshot: UIImage? { UIGraphicsBeginImageContextWithOptions(bounds.size, isOpaque, 0.0) if UIGraphicsGetCurrentContext() != nil { drawHierarchy(in: bounds, afterScreenUpdates: true) let screenshot = UIGraphicsGetImageFromCurrentImageContext() UIGraphicsEndImageContext() return screenshot } return nil } }
-
UIApplication扩展
extension UIApplication { var snapshot: UIImage? { return keyWindow?.rootViewController?.view.snapshot } }
在Swift 3中的实现:
添加以下代码,超出课程范围。
extension UIImage { convenience init(_ view: UIView) { UIGraphicsBeginImageContext(view.frame.size) view.layer.render(in: UIGraphicsGetCurrentContext()!) let image = UIGraphicsGetImageFromCurrentImageContext() UIGraphicsEndImageContext() self.init(cgImage: (image?.cgImage)!) } }
用法:
let image = UIImage( Your_View_Outlet )
我实现了@Naveed J.的方法,就像魅力一样。
这是他的扩展:
extension UIView { // Using a function since `var image` might conflict with an existing variable // (like on `UIImageView`) func asImage() -> UIImage { let renderer = UIGraphicsImageRenderer(bounds: bounds) return renderer.image { rendererContext in layer.render(in: rendererContext.cgContext) } } }
这是我如何实现它。
//create an image from yourView to display //determine the frame of the view/imageimage let screen = self.superview!.bounds let width = screen.width / 4 //make image 1/4 width of screen let height = width let frame = CGRect(x: 0, y: 0, width: width, height: height) let x = (screen.size.width - frame.size.width) * 0.5 let y = (screen.size.height - frame.size.height) * 0.5 let mainFrame = CGRect(x: x, y: y, width: frame.size.width, height: frame.size.height) let yourView = YourView() //instantiate yourView yourView.frame = mainFrame //give it the frame yourView.setNeedsDisplay() //tell it to display (I am not 100% sure this is needed) let characterViewImage = yourView.asImage()
谢谢@包团团员! 我想添加一个补充。
当你使用的代码:
yourView.layer.render(in:UIGraphicsGetCurrentContext()!)
你必须注意到:
- If you had used `autoLayout` or `Masonry` in `yourView` (that you want to convert) . - If you did not add `yourView` to another view which means that `yourView` was not used as a subview but just an object.
那么,你必须使用 :
[yourView setNeedsLayout]; [yourView layoutIfNeeded];
在yourView.layer.render(in:UIGraphicsGetCurrentContext()!)
之前更新yourView
。
否则,你可能会得到一个不包含元素的图像对象
please try below code. -(UIImage *)getMainImageFromContext { UIGraphicsBeginImageContextWithOptions(viewBG.bounds.size, viewBG.opaque, 0.0); [viewBG.layer renderInContext:UIGraphicsGetCurrentContext()]; UIImage * img = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); return img; }