How Do I Take a Screen Shot of a UIView?
I think you may want renderInContext
, not drawInContext
. drawInContext is more a method you would override...
Note that it may not work in all views, specifically a year or so ago when I tried to use this with the live camera view it did not work.
How to take screenshot of a UIView in swift?
For drawing of one view, just use this:
// Begin context
UIGraphicsBeginImageContextWithOptions(view.bounds.size, false, UIScreen.mainScreen().scale)
// Draw view in that context
drawViewHierarchyInRect(view.bounds, afterScreenUpdates: true)
// And finally, get image
let image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
If you want to use it multiple times, probably extension would do the job:
//Swift4
extension UIView {
func takeScreenshot() -> UIImage {
// Begin context
UIGraphicsBeginImageContextWithOptions(self.bounds.size, false, UIScreen.main.scale)
// Draw view in that context
drawHierarchy(in: self.bounds, afterScreenUpdates: true)
// And finally, get image
let image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
if (image != nil)
{
return image!
}
return UIImage()
}
}
//Old Swift
extension UIView {
func takeScreenshot() -> UIImage {
// Begin context
UIGraphicsBeginImageContextWithOptions(self.bounds.size, false, UIScreen.mainScreen().scale)
// Draw view in that context
drawViewHierarchyInRect(self.bounds, afterScreenUpdates: true)
// And finally, get image
let image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return image
}
}
To explain what those parameters do:
UIGraphicsBeginImageContextWithOptions() creates a temporary rendering
context into which the original is drawn. The first argument, size, is
the target size of the scaled image. The second argument, isOpaque is
used to determine whether an alpha channel is rendered. Setting this
to false for images without transparency (i.e. an alpha channel) may
result in an image with a pink hue. The third argument scale is the
display scale factor. When set to 0.0, the scale factor of the main
screen is used, which for Retina displays is 2.0 or higher (3.0 on the
iPhone 6 Plus).
More about it here http://nshipster.com/image-resizing/
As for the draw call, Apple Docs explains it to detail here and here
How to take screenshot of portion of UIView?
The standard snapshot technique is drawHierarchy(in:afterScreenUpdates:)
, drawing that to an image context. In iOS 10 and later, you can use UIGraphicsImageRenderer
:
extension UIView {
/// Create image snapshot of view.
///
/// - Parameters:
/// - rect: The coordinates (in the view's own coordinate space) to be captured. If omitted, the entire `bounds` will be captured.
/// - afterScreenUpdates: A Boolean value that indicates whether the snapshot should be rendered after recent changes have been incorporated. Specify the value false if you want to render a snapshot in the view hierarchy’s current state, which might not include recent changes. Defaults to `true`.
///
/// - Returns: The `UIImage` snapshot.
func snapshot(of rect: CGRect? = nil, afterScreenUpdates: Bool = true) -> UIImage {
return UIGraphicsImageRenderer(bounds: rect ?? bounds).image { _ in
drawHierarchy(in: bounds, afterScreenUpdates: afterScreenUpdates)
}
}
}
And you’d use that like so:
let image = webView.snapshot(of: rect)
Prior to iOS 10, you would to get portion of an image, you can use CGImage
method cropping(to:)
. E.g.:
extension UIView {
/// Create snapshot
///
/// - Parameters:
/// - rect: The coordinates (in the view's own coordinate space) to be captured. If omitted, the entire `bounds` will be captured.
/// - afterScreenUpdates: A Boolean value that indicates whether the snapshot should be rendered after recent changes have been incorporated. Specify the value false if you want to render a snapshot in the view hierarchy’s current state, which might not include recent changes. Defaults to `true`.
///
/// - Returns: Returns `UIImage` of the specified portion of the view.
func snapshot(of rect: CGRect? = nil, afterScreenUpdates: Bool = true) -> UIImage? {
// snapshot entire view
UIGraphicsBeginImageContextWithOptions(bounds.size, isOpaque, 0)
drawHierarchy(in: bounds, afterScreenUpdates: afterScreenUpdates)
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
guard let cgImage = image.cgImage?.cropping(to: rect * image.scale) else { return nil }
return UIImage(cgImage: cgImage, scale: image.scale, orientation: .up)
}
}
Which uses this little convenient operator:
extension CGRect {
static func * (lhs: CGRect, rhs: CGFloat) -> CGRect {
return CGRect(x: lhs.minX * rhs, y: lhs.minY * rhs, width: lhs.width * rhs, height: lhs.height * rhs)
}
}
And to use it, you can do:
if let image = webView.snapshot(of: rect) {
// do something with `image` here
}
For Swift 2 rendition, see previous revision of this answer.
How can I take a snapshot of a UIView that isn't rendered?
drawViewHierarchyInRect
will work for you. You can use this directly on your WKWebView.
There is some useful detail on this Apple Technical Q&A. Also I touch on it here in answer to a slightly different question.
I use it in a category on UIView:
@implementation UIView (ImageSnapshot)
- (UIImage*)imageSnapshot {
UIGraphicsBeginImageContextWithOptions(self.bounds.size,
YES, self.contentScaleFactor);
[self drawViewHierarchyInRect:self.bounds afterScreenUpdates:YES];
UIImage* newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return newImage;
}
@end
I don't know what you mean by 'the obvious method' - but I have tested this on a WKWebView and it works.
How to take a screenshot of UIView on a background thread?
Actually ,it is possible! But first on UIThread you need get some infos Like this:
CALayer* layer = view.layer;
CGRect frame = view.frame;
, then change to backgroundthead use codes below to get image:
UIGraphicsBeginImageContextWithOptions(frame.size, NO, 0);
CGContextRef context = UIGraphicsGetCurrentContext();
[layer renderInContext:context];
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
Related Topics
How to Set Up a Simple Delegate to Communicate Between Two View Controllers
Nsurlsession/Nsurlconnection Http Load Failed on iOS 9
Ios Launching Settings -≫ Restrictions Url Scheme
Objective-C Arc: Strong VS Retain and Weak VS Assign
Generate Json String from Nsdictionary in Ios
How Disable Copy, Cut, Select, Select All in Uitextview
Uiview Infinite 360 Degree Rotation Animation
Iphone Uitextfield - Change Placeholder Text Color
What Is the Documents Directory (Nsdocumentdirectory)
How to Access a Specific Field from Cloud Firestore Firebase in Swift
How to Increment the Filename If File Already Exists
How to Deal With the Nsdateformatter Locale "Feechur"
Launch an App from Within Another (Iphone)
Adding Space/Padding to a Uilabel
Why Isn't Projectname-Prefix.Pch Created Automatically in Xcode 6