Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Swift: Cropping a Screenshot without TabBar and NavigationBar

I have a screenshot of the entire screen, screenshot, generated using the following:

let layer = UIApplication.sharedApplication().keyWindow!.layer
let scale = UIScreen.mainScreen().scale
UIGraphicsBeginImageContextWithOptions(layer.frame.size, false, scale);

layer.renderInContext(UIGraphicsGetCurrentContext())
let screenshot = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()

I'd like to crop it so that the tab bar is not included, and I tried using the following code:

let crop = CGRectMake(0, 0, //"start" at the upper-left corner
self.view.bounds.width, //include half the width of the whole screen
self.view.bounds.height + self.navigationController!.navigationBar.frame.height) //include the height of the navigationBar and the height of view

let cgImage = CGImageCreateWithImageInRect(screenshot.CGImage, crop)
let image: UIImage = UIImage(CGImage: cgImage)!

This code results in image showing just a small portion of the screen, a rectangle starting at the upper-left corner of the screen (0, 0), and extending right for less than half the width of the screen, then downward for less than half the height of the screen. I'd like, though, for it to include the entire screen, except for the region occupied by the tab bar. Is there a such a way to crop it?

like image 577
Randoms Avatar asked Aug 15 '15 03:08

Randoms


3 Answers

According to this

The new image is created by
1) adjusting rect to integral bounds by calling CGRectIntegral;
2) intersecting the result with a rectangle with origin (0, 0) and size equal to the size of image;
3) referencing the pixels within the resulting rectangle, treating the first pixel of the image data as the origin of the image.
If the resulting rectangle is the null rectangle, this function returns NULL.

If W and H are the width and height of image, respectively, then the point (0,0) corresponds to the first pixel of the image data; the point (W-1, 0) is the last pixel of the first row of the image data; (0, H-1) is the first pixel of the last row of the image data; and (W-1, H-1) is the last pixel of the last row of the image data.

You will need to have a crop function like this. You may need adjust the calculation of the bottomBarHeight

func takeScreenshot(sender: AnyObject) {
    let layer = UIApplication.sharedApplication().keyWindow!.layer
    let scale = UIScreen.mainScreen().scale
    UIGraphicsBeginImageContextWithOptions(layer.frame.size, false, scale);

    layer.renderInContext(UIGraphicsGetCurrentContext())
    let screenshot = UIGraphicsGetImageFromCurrentImageContext()
    UIGraphicsEndImageContext()
    let croppedImage = self.cropImage(screenshot)
}

func cropImage(screenshot: UIImage) -> UIImage {
    let scale = screenshot.scale
    let imgSize = screenshot.size
    let screenHeight = UIScreen.mainScreen().applicationFrame.height
    let bound = self.view.bounds.height
    let navHeight = self.navigationController!.navigationBar.frame.height
    let bottomBarHeight = screenHeight - navHeight - bound
    let crop = CGRectMake(0, 0, //"start" at the upper-left corner
        (imgSize.width - 1) * scale, //include half the width of the whole screen
        (imgSize.height - bottomBarHeight - 1) * scale) //include the height of the navigationBar and the height of view

    let cgImage = CGImageCreateWithImageInRect(screenshot.CGImage, crop)
    let image: UIImage = UIImage(CGImage: cgImage)!
    return image
}
like image 125
sahara108 Avatar answered Nov 20 '22 01:11

sahara108


swift:

let contextImage: UIImage = <<screenshot>>!
let cropRect: CGRect = CGRectMake(x, y, width, height)
let imageRef: CGImageRef = CGImageCreateWithImageInRect(contextImage.CGImage, cropRect)
let image: UIImage = UIImage(CGImage: imageRef, scale: originalImage.scale, orientation: originalImage.imageOrientation)!

obj-c:

UIImage *image = <<screenshot>>;

CGRect croprect = CGRectMake(0, 0,
self.view.bounds.width,
self.view.bounds.height + self.navigationController!.navigationBar.frame.height));

// Draw new image in current graphics context
CGImageRef imageRef = CGImageCreateWithImageInRect([image CGImage], croprect);

// Create new cropped UIImage
UIImage *croppedImage = [UIImage imageWithCGImage:imageRef];
like image 28
Brian Daneshgar Avatar answered Nov 20 '22 01:11

Brian Daneshgar


You have two options here: First, you can take the screenshot using UIApplication.sharedApplication().keyWindow then we will have this:

    UIGraphicsBeginImageContext(UIApplication.sharedApplication().keyWindow!.bounds.size)
    UIApplication.sharedApplication().keyWindow!.layer.renderInContext(UIGraphicsGetCurrentContext())
    let screenshot = UIGraphicsGetImageFromCurrentImageContext()
    UIGraphicsEndImageContext()

So, you will have to crop the image like this:

    let yPosition = self.navigationController!.navigationBar.frame.height + UIApplication.sharedApplication().statusBarFrame.size.height
    let crop = CGRectMake(0, yPosition,
            self.view.bounds.width, 
            self.view.bounds.height)
    let cgImage = CGImageCreateWithImageInRect(screenshot.CGImage, crop)
    let image: UIImage = UIImage(CGImage: cgImage)!

The second option is to take the screenshot directly of your view, like this:

    UIGraphicsBeginImageContext(self.view!.bounds.size)
    self.view!.layer.renderInContext(UIGraphicsGetCurrentContext())
    let screenshot = UIGraphicsGetImageFromCurrentImageContext()
    UIGraphicsEndImageContext()

In this case, you don't need to crop the navigationBar.

This is a sample code at github https://github.com/gazolla/crop

like image 2
Sebastian Avatar answered Nov 20 '22 00:11

Sebastian