2016-09-02 60 views
6

我希望用户在我的应用程序中继续,并在Swift中以编程方式按下按钮后截取应用程序。我知道UIGraphicsGetImageFromCurrentImageContext()需要截图,但我不想要整个屏幕的图片。我想要一个矩形弹出(有点像裁剪工具),用户可以拖动和调整矩形的大小来截取屏幕的某个部分。我想让这个矩形遍历WKWebView并裁剪一张网页视图。如何截取部分UIView的截图?

回答

16

标准快照技术是drawViewHierarchyInRect。要获取图像的一部分,可以使用CGImageCreateWithImageInRect

因此,斯威夫特2:

extension UIView { 

    /// Create snapshot 
    /// 
    /// - parameter rect: The `CGRect` of the portion of the view to return. If `nil` (or omitted), 
    ///     return snapshot of the whole view. 
    /// 
    /// - returns: Returns `UIImage` of the specified portion of the view. 

    func snapshot(of rect: CGRect? = nil) -> UIImage? { 
     // snapshot entire view 

     UIGraphicsBeginImageContextWithOptions(bounds.size, opaque, 0) 
     drawViewHierarchyInRect(bounds, afterScreenUpdates: true) 
     let wholeImage = UIGraphicsGetImageFromCurrentImageContext() 
     UIGraphicsEndImageContext() 

     // if no `rect` provided, return image of whole view 

     guard let rect = rect, let image = wholeImage else { return wholeImage } 

     // otherwise, grab specified `rect` of image 

     let scale = image.scale 
     let scaledRect = CGRect(x: rect.origin.x * scale, y: rect.origin.y * scale, width: rect.size.width * scale, height: rect.size.height * scale) 
     guard let cgImage = CGImageCreateWithImageInRect(image.CGImage!, scaledRect) else { return nil } 
     return UIImage(CGImage: cgImage, scale: scale, orientation: .Up) 
    } 

} 

在斯威夫特3:

extension UIView { 

    /// Create snapshot 
    /// 
    /// - parameter rect: The `CGRect` of the portion of the view to return. If `nil` (or omitted), 
    ///     return snapshot of the whole view. 
    /// 
    /// - returns: Returns `UIImage` of the specified portion of the view. 

    func snapshot(of rect: CGRect? = nil) -> UIImage? { 
     // snapshot entire view 

     UIGraphicsBeginImageContextWithOptions(bounds.size, isOpaque, 0) 
     drawHierarchy(in: bounds, afterScreenUpdates: true) 
     let wholeImage = UIGraphicsGetImageFromCurrentImageContext() 
     UIGraphicsEndImageContext() 

     // if no `rect` provided, return image of whole view 

     guard let image = wholeImage, let rect = rect else { return wholeImage } 

     // otherwise, grab specified `rect` of image 

     let scale = image.scale 
     let scaledRect = CGRect(x: rect.origin.x * scale, y: rect.origin.y * scale, width: rect.size.width * scale, height: rect.size.height * scale) 
     guard let cgImage = image.cgImage?.cropping(to: scaledRect) else { return nil } 
     return UIImage(cgImage: cgImage, scale: scale, orientation: .up) 
    } 

} 

,并使用它,你可以这样做:

if let image = webView.snapshot(of: rect) { 
    // do something with `image` here 
} 
+1

伟大的工作一如既往罗布。谢谢。 – damirstuhec

+0

完美的解决方案。还有其他的,但他们捕捉整个屏幕。这是两个解决方案。 – Septronic

3

这是How to capture UIView to UIImage without loss of quality on retina display(2.3)先前提出的问题,但在迅速扩大:

extension UIView { 

    class func image(view: UIView) -> UIImage? { 
     UIGraphicsBeginImageContextWithOptions(view.bounds.size, view.opaque, 0.0) 
     guard let ctx = UIGraphicsGetCurrentContext() else { 
      return nil 
     } 
     view.layer.renderInContext(ctx) 
     let img = UIGraphicsGetImageFromCurrentImageContext() 
     UIGraphicsEndImageContext() 
     return img 
    } 

    func image() -> UIImage? { 
     return UIView.image(self) 
    } 
} 

所以您可以得到一个视图中的图像与UIView.image(theView)或要求的观点本身let viewImage = self.view.image()

不要忘记,这是粗糙的,可能需要进一步寻找线程安全等......