it-roy-ru.com

Как сделать полноэкранный снимок экрана в Swift?

Я нашел этот код :

func screenShotMethod() {
    //Create the UIImage
    UIGraphicsBeginImageContext(view.frame.size)
    view.layer.renderInContext(UIGraphicsGetCurrentContext())
    let image = UIGraphicsGetImageFromCurrentImageContext()
    UIGraphicsEndImageContext()
    //Save it to the camera roll
    UIImageWriteToSavedPhotosAlbum(image, nil, nil, nil)
}

Что мне нужно сделать, чтобы получить все другие элементы, такие как панель навигации, на скриншотах?

56
Pietro La Spada

Вместо того, чтобы просто дать ответ, позвольте мне объяснить, что делает ваш текущий код и как его изменить, чтобы получить полный экран.

UIGraphicsBeginImageContext(view.frame.size)

Эта строка кода создает новый контекст изображения того же размера, что и view. Главное, что здесь нужно убрать, это то, что новый контекст изображения того же размера, что и view. Если вы не хотите записывать версию приложения с низким разрешением (не для сетчатки), вам, вероятно, следует использовать вместо нее UIGraphicsBeginImageContextWithOptions. Затем вы можете передать 0.0, чтобы получить тот же масштабный коэффициент, что и на главном экране устройства. 

view.layer.renderInContext(UIGraphicsGetCurrentContext())

Эта строка кода отобразит слой представления в текущий графический контекст (который является контекстом, который вы только что создали). Главное, что нужно здесь убрать, это то, что только view (и его подпредставления) вписываются в контекст изображения.

let image = UIGraphicsGetImageFromCurrentImageContext()

Эта строка кода создает объект UIImage из того, что было нарисовано в графическом контексте. 

UIGraphicsEndImageContext()

Эта строка кода завершает контекст изображения. Он очищен (вы создали контекст и также должны удалить его). 


В результате получается изображение того же размера, что и view, с view и его вложенными представлениями.

Если вы хотите нарисовать все на изображении, то вы должны создать изображение размером с экран и нарисовать в нем все, что на экране. На практике вы, скорее всего, просто говорите обо всем в «ключевом окне» вашего приложения. Поскольку UIWindow является подклассом UIView, его также можно нарисовать в контексте изображения.

66
David Rönnqvist

Swift 4

    /// Takes the screenshot of the screen and returns the corresponding image
    ///
    /// - Parameter shouldSave: Boolean flag asking if the image needs to be saved to user's photo library. Default set to 'true'
    /// - Returns: (Optional)image captured as a screenshot
    open func takeScreenshot(_ shouldSave: Bool = true) -> UIImage? {
        var screenshotImage :UIImage?
        let layer = UIApplication.shared.keyWindow!.layer
        let scale = UIScreen.main.scale
        UIGraphicsBeginImageContextWithOptions(layer.frame.size, false, scale);
        guard let context = UIGraphicsGetCurrentContext() else {return nil}
        layer.render(in:context)
        screenshotImage = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        if let image = screenshotImage, shouldSave {
            UIImageWriteToSavedPhotosAlbum(image, nil, nil, nil)
        }
        return screenshotImage
    }

Обновлено для Swift 2

Предоставленный вами код работает, но не позволяет вам захватывать NavigationBar и StatusBar на скриншоте. Если вы хотите сделать снимок экрана своего устройства, который будет содержать NavigationBar, вы должны использовать следующий код:

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

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

    UIImageWriteToSavedPhotosAlbum(screenshot, nil, nil, nil)
}

С этим кодом:

  • Когда вы в первый раз запускаете приложение и вызываете этот метод, устройство iOS запросит у вас разрешение на сохранение вашего изображения в рулоне камеры.
  • Результатом этого кода будет изображение .JPG.
  • StatusBar не появится в конечном изображении.
49
Imanou Petit

Swift 3 пример:

func captureScreen() -> UIImage? {
    guard let context = UIGraphicsGetCurrentContext() else { return .none }
    UIGraphicsBeginImageContextWithOptions(view.bounds.size, false, UIScreen.main.scale)
    view.layer.render(in: context)
    let image = UIGraphicsGetImageFromCurrentImageContext()
    UIGraphicsEndImageContext()
    return image
}
21
Daniel Storm

Подробности

Xcode 9.3, Swift 4.1

Протестировано на iOS: 9, 10, 11

Решение

import UIKit

extension UIApplication {

    var screenShot: UIImage?  {
        return keyWindow?.layer.screenShot
    }
}

extension CALayer {

    var screenShot: UIImage?  {
        let scale = UIScreen.main.scale
        UIGraphicsBeginImageContextWithOptions(frame.size, false, scale)
        if let context = UIGraphicsGetCurrentContext() {
            render(in: context)
            let screenshot = UIGraphicsGetImageFromCurrentImageContext()
            UIGraphicsEndImageContext()
            return screenshot
        }
        return nil
    }
}

Использование

 imageView.image = UIApplication.shared.screenShot

Подробности

Xcode 8.2.1, Swift 3

Версия 1 для iOS 10x

import UIKit

extension UIApplication {

    var screenShot: UIImage?  {

        if let layer = keyWindow?.layer {
            let scale = UIScreen.main.scale

            UIGraphicsBeginImageContextWithOptions(layer.frame.size, false, scale);
            if let context = UIGraphicsGetCurrentContext() {
                layer.render(in: context)
                let screenshot = UIGraphicsGetImageFromCurrentImageContext()
                UIGraphicsEndImageContext()
                return screenshot
            }
        }
        return nil
    }
}

Версия 2 для iOS 9x, 10x

Если вы попытаетесь использовать код версии 1 в iOS 9x у вас будет ошибка: CGImageCreateWithImageProvider: неверный поставщик изображений: NULL.

import UIKit

extension UIApplication {

    var screenShot: UIImage?  {

        if let rootViewController = keyWindow?.rootViewController {
            let scale = UIScreen.main.scale
            let bounds = rootViewController.view.bounds
            UIGraphicsBeginImageContextWithOptions(bounds.size, false, scale);
            if let _ = UIGraphicsGetCurrentContext() {
                rootViewController.view.drawHierarchy(in: bounds, afterScreenUpdates: true)
                let screenshot = UIGraphicsGetImageFromCurrentImageContext()
                UIGraphicsEndImageContext()
                return screenshot
            }
        }
        return nil
    }
}

Использование

let screenShot = UIApplication.shared.screenShot!
19
Vasily Bodnarchuk

Для удобства я бы добавил расширение в его собственный файл

import UIKit

  public extension UIWindow {

    func capture() -> UIImage {

      UIGraphicsBeginImageContextWithOptions(self.frame.size, self.opaque, UIScreen.mainScreen().scale)
      self.layer.renderInContext(UIGraphicsGetCurrentContext()!)
      let image = UIGraphicsGetImageFromCurrentImageContext()
      UIGraphicsEndImageContext()

      return image
  }
}

вызвать расширение следующим образом ...

let window: UIWindow! = UIApplication.sharedApplication().keyWindow

let windowImage = window.capture()

Точно так же можно расширить UIView, чтобы захватить изображение этого .... 

9
Damo

Рекомендуемый способ создания контекста в iOS 10 - использовать UIGraphicsImageRenderer.

extension UIView {
    func capture() -> UIImage? {
        var image: UIImage?

        if #available(iOS 10.0, *) {
            let format = UIGraphicsImageRendererFormat()
            format.opaque = isOpaque
            let renderer = UIGraphicsImageRenderer(size: frame.size, format: format)
            image = renderer.image { context in
                drawHierarchy(in: frame, afterScreenUpdates: true)
            }
        } else {
            UIGraphicsBeginImageContextWithOptions(frame.size, isOpaque, UIScreen.main.scale)
            drawHierarchy(in: frame, afterScreenUpdates: true)
            image = UIGraphicsGetImageFromCurrentImageContext()
            UIGraphicsEndImageContext()
        }

        return image
    }
}
4
neave

Я использую этот метод:

func captureScreen() -> UIImage {
    var window: UIWindow? = UIApplication.sharedApplication().keyWindow
    window = UIApplication.sharedApplication().windows[0] as? UIWindow
    UIGraphicsBeginImageContextWithOptions(window!.frame.size, window!.opaque, 0.0)
    window!.layer.renderInContext(UIGraphicsGetCurrentContext())
    let image = UIGraphicsGetImageFromCurrentImageContext()
    UIGraphicsEndImageContext()
    return image;
}

Он захватывает все, кроме строки состояния, и не запрашивает разрешения на сохранение изображений в фотоаппарате.

Надеюсь, поможет!

3
diegomen

Расширение Swift 3 для UIWindow

public extension UIWindow {

  func capture() -> UIImage? {

    UIGraphicsBeginImageContextWithOptions(self.frame.size, self.isOpaque, UIScreen.main.scale)
    self.layer.render(in: UIGraphicsGetCurrentContext()!)
    let image = UIGraphicsGetImageFromCurrentImageContext()
    UIGraphicsEndImageContext()

    return image

  }
}]
1
Gregg

Это похоже, надеюсь, это поможет кому-то в будущем.

self.view.image() //returns UIImage

Вот решение Swift 3

https://Gist.github.com/nitrag/b3117a4b6b8e89fdbc12b98029cf98f8

1
Ryan G
  // Full Screen Shot function. Hope this will work well in Swift.
  func screenShot() -> UIImage {                                                    
    UIGraphicsBeginImageContext(CGSizeMake(frame.size.width, frame.size.height))
    var context:CGContextRef  = UIGraphicsGetCurrentContext()
    self.view?.drawViewHierarchyInRect(frame, afterScreenUpdates: true)
    var screenShot = UIGraphicsGetImageFromCurrentImageContext()
    UIGraphicsEndImageContext();  
    return screenShot
  }
1
Rex

Моя версия также захватить клавиатуру. Swift 4.2

extension UIApplication {

    var screenshot: UIImage? {
        UIGraphicsBeginImageContextWithOptions(UIScreen.main.bounds.size, false, 0)
        guard let context = UIGraphicsGetCurrentContext() else { return nil }
        for window in windows {
            window.layer.render(in: context)
        }
        let image = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        return image
    }

}
0
Alexander Khitev

view.snapshotView (afterScreenUpdates: true)

0
Adam Smaka

Вот как я это делаю в Swift 4

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

теперь скриншот будет иметь тип UIImage

0
Pung Worathiti Manosroi

Swift 4 или выше.

Для расширения и вызова UIView, что вы захватили.

Декларация

extension UIView {

    func viewCapture() -> UIImage? {

        UIGraphicsBeginImageContext(self.frame.size)

        guard let cgContext = UIGraphicsGetCurrentContext() else {
        print("Fail to get CGContext")
        return nil

    }
    self.layer.render(in: cgContext)

    guard let image = UIGraphicsGetImageFromCurrentImageContext() else {
        print("Fail to get Image from current image context")
        return nil
    }
    UIGraphicsEndImageContext()

    return image

    }
}

Использование

var m_image = UIImage()

if let tempCaptureImg = self.m_Capture_View.viewCapture() {
    viewController.m_image = tempCaptureImg
}

// m_Capture_View - это тип UIView

0
Saharat Sittipanya