2016-09-02 14 views
6

Chcę, aby użytkownik uruchomił moją aplikację i zrobił zrzut ekranu aplikacji po naciśnięciu przycisku programowo w Swift. Wiem, że UIGraphicsGetImageFromCurrentImageContext() robi zrzut ekranu, ale nie chcę obrazu całego ekranu. Chcę, aby pojawił się prostokąt (przypominający narzędzie do przycinania), a użytkownik może przeciągnąć i zmienić rozmiar prostokąta, aby zrobić zrzut ekranu tylko z określonej części ekranu. Chcę, aby prostokąt przeszedł ponad WKWebView i przyciąć obraz z widoku sieci.Jak zrobić zrzut ekranu z części UIView?

Odpowiedz

16

Standardową techniką snapshot jest drawViewHierarchyInRect. Aby uzyskać część obrazu, możesz użyć CGImageCreateWithImageInRect.

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

} 

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

} 

I go używać, można zrobić:

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

Wielką pracę jak zawsze Rob. Dzięki. – damirstuhec

+0

Idealne rozwiązanie. Są inne na SO, ale przechwytują cały ekran. To jest rozwiązanie dla obu. – Septronic

3

Jest to wcześniej zadawane pytanie na How to capture UIView to UIImage without loss of quality on retina display ale rozwijać się w szybki (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) 
    } 
} 

Więc możesz uzyskać obraz z widokiem z UIView.image(theView) lub pytając sam widok let viewImage = self.view.image()

Należy pamiętać, że jest to trudne i prawdopodobnie wymaga dalszego sprawdzenia w zakresie bezpieczeństwa wątków itp.

Powiązane problemy