2016-09-02 6 views
6

Ich möchte, dass der Benutzer auf meine App gehen und einen Screenshot der App nach dem programmgesteuerten Drücken einer Taste in Swift machen. Ich weiß, dass UIGraphicsGetImageFromCurrentImageContext() einen Screenshot macht, aber ich möchte kein Bild des gesamten Bildschirms. Ich möchte, dass ein Rechteck angezeigt wird (ähnlich wie ein Zuschneidewerkzeug), und der Benutzer kann das Rechteck ziehen und seine Größe ändern, um einen Screenshot nur eines bestimmten Teils des Bildschirms aufzunehmen. Ich möchte das Rechteck über eine WKWebView gehen und ein Bild der Webansicht zuschneiden.Wie man einen Screenshot des Teils von UIView macht?

Antwort

16

Die Standard-Snapshot-Technik ist drawViewHierarchyInRect. Um einen Teil eines Bildes zu erhalten, können Sie CGImageCreateWithImageInRect verwenden.

So in Swift 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) 
    } 

} 

In Swift 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) 
    } 

} 

Und, es zu benutzen, können Sie tun:

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

Große Arbeit wie immer Rob. Vielen Dank. – damirstuhec

+0

Perfekte Lösung. Es gibt andere auf SO, aber sie erfassen den gesamten Bildschirm. Dies ist die Lösung für beide. – Septronic

3

Dies ist eine zuvor gestellte Frage an How to capture UIView to UIImage without loss of quality on retina display aber in schnellen (2.3) zu erweitern: Sie

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

So kann entweder ein Bild aus einer Ansicht mit UIView.image(theView) oder indem er die Ansicht, selbst let viewImage = self.view.image()

bekommen

Denken Sie jedoch daran, dass dies grob ist und wahrscheinlich weitere Untersuchungen zur Fadensicherheit usw. erforderlich sind.

Verwandte Themen