Swift: Cropping a Screenshot without TabBar and NavigationBar

前端 未结 5 823
臣服心动
臣服心动 2021-01-05 14:43

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

let layer = UIApplication.sharedApplication().keyWindow!.l         


        
相关标签:
5条回答
  • 2021-01-05 15:05

    My answer in Swift 4.2, the steps are in the comments above the code in the function getScreenshot()

    @IBAction fileprivate func takeScreenshotButtonTapped(_ sender: UIButton) {
    
        guard let croppedScreenshotImage = getScreenshot() else { return }
    
        // do something with the croppedScreenshotImage
    }
    
    func getScreenshot() -> UIImage? {
    
        // 1. get screenshot of the entire screen
        UIGraphicsBeginImageContext(UIApplication.shared.keyWindow!.bounds.size)
        UIApplication.shared.keyWindow!.layer.render(in: UIGraphicsGetCurrentContext()!)
        let screenshot = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
    
        // 2. height of statusBar
        let statusBarHeight = UIApplication.shared.statusBarFrame.size.height
    
        // 3. height of navigationBar
        var navBarHeight: CGFloat = 0
        if let navigationBarHeight = navigationController?.navigationBar.frame.height {
            navBarHeight = navigationBarHeight
        }
    
        // 4. total height of statusBar + navigationBar
        let topBarHeight = statusBarHeight + navBarHeight
    
        // 5. get the height of the tabBar
        var tabBarHeight: CGFloat = 0
        if let tabBarController = tabBarController {
            tabBarHeight = tabBarController.tabBar.frame.size.height
        }
    
        // 6. to exclude the navigationBar, statusBar, and tabBar from your screenshot start the rect's y-axis at everything below the topBarHeight. For the height subtract the topBarHeight and tabBarHeight from the view's height 
        let rectWithoutNavStatusAndTabBar = CGRect(x: 0, y: topBarHeight, width: self.view.bounds.width, height: self.view.bounds.height - topBarHeight - tabBarHeight)
    
        guard let safeScreenshot = screenshot else { return nil }
    
        // 7. crop the screenshot to the rectWithoutNavStatusAndTabBar
        guard let cgImage = safeScreenshot.cgImage?.cropping(to: rectWithoutNavStatusAndTabBar) else { return nil }
    
        // 8. create an image from the cgImage
        let yourCroppedScreenshotImage = UIImage(cgImage: cgImage)
    
        return yourCroppedScreenshotImage
    }
    

    This is also the Swift 4.2 version of the accepted answer:

    func takeScreenshot(sender: AnyObject) {
        let layer = UIApplication.shared.keyWindow!.layer
        let scale = UIScreen.main.scale
        UIGraphicsBeginImageContextWithOptions(layer.frame.size, false, scale);
    
        layer.render(in: UIGraphicsGetCurrentContext()!)
        let screenshot = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        let croppedImage = self.cropImage(screenshot: screenshot!)
    }
    
    func cropImage(screenshot: UIImage) -> UIImage {
        let scale = screenshot.scale
        let imgSize = screenshot.size
        let screenHeight = UIScreen.main.bounds.height
        let bound = self.view.bounds.height
        let navHeight = self.navigationController!.navigationBar.frame.height
        let bottomBarHeight = screenHeight - navHeight - bound
        let crop = CGRect(x: 0, y: 0, width: (imgSize.width - 1) * scale, height: (imgSize.height - bottomBarHeight - 1) * scale)
        let cgImage = screenshot.cgImage?.cropping(to: crop)
        let image: UIImage = UIImage(cgImage: cgImage!)
        return image
    }
    
    0 讨论(0)
  • 2021-01-05 15:14

    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];
    
    0 讨论(0)
  • 2021-01-05 15:17

    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
    }
    
    0 讨论(0)
  • 2021-01-05 15:17

    I think your crop CGRect is wrong.

    let crop = CGRectMake(0,
                          0,
                          self.view.frame.size.width,
                          self.view.frame.size.height + self.navigationController!.navigationBar.frame.height - self.tabBar.frame.size.height
                         )
    

    X: 0 and Y: 0 - start at 0, 0 respectively.

    Width: Capture the view's entire width

    Height: The entire view's height plus the height of the UINavigationBar minus the height of the UITabBar.

    0 讨论(0)
  • 2021-01-05 15:20

    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

    0 讨论(0)
提交回复
热议问题