web-dev-qa-db-ja.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)
}

ナビゲーションバーなどの他のすべての要素をスクリーンショットに取り込むには、何をする必要がありますか?

61
Pietro La Spada

ただ答えをそこに投げるのではなく、現在のコードが何をするのか、それを変更して全画面をキャプチャする方法を説明しましょう。

UIGraphicsBeginImageContext(view.frame.size)

このコード行は、viewと同じサイズの新しい画像コンテキストを作成します。ここで取り上げる主なことは、新しいイメージコンテキストがviewと同じサイズであることです。アプリケーションの低解像度(非網膜)バージョンをキャプチャする場合を除き、代わりにUIGraphicsBeginImageContextWithOptionsを使用する必要があります。次に、0.0を渡して、デバイスのメイン画面と同じスケール係数を取得できます。

view.layer.renderInContext(UIGraphicsGetCurrentContext())

このコード行は、ビューのレイヤーを現在のグラフィックスコンテキスト(作成したばかりのコンテキスト)にレンダリングします。ここで取り上げる主なことは、view(およびそのサブビュー)のみが画像コンテキストに描画されることです。

let image = UIGraphicsGetImageFromCurrentImageContext()

このコード行は、グラフィックコンテキストに描画されたものからUIImageオブジェクトを作成します。

UIGraphicsEndImageContext()

このコード行は、イメージコンテキストを終了します。クリーンアップです(コンテキストを作成し、同様に削除する必要があります。


結果は、viewと同じサイズの画像に、viewとそのサブビューが描画されます。

すべてを画像に描画する場合は、画面のサイズの画像を作成し、画面上にあるすべての画像を描画する必要があります。実際には、アプリケーションの「キーウィンドウ」内のすべてについて話しているだけです。 UIWindowUIViewのサブクラスであるため、画像コンテキストにも描画できます。

70

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用に更新

指定したコードは機能しますが、スクリーンショットでNavigationBarStatusBarをキャプチャすることはできません。 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は最終画像には表示されません。
53
Imanou Petit

詳細

  • Xcode 9.3、Swift 4.1
  • Xcode 10.2(10E125)、Swift 5

IOSでテスト済み:9、10、11、12

解決

import UIKit

extension UIApplication { func makeSnapshot() -> UIImage? { return keyWindow?.layer.makeSnapshot() } }

extension CALayer {
    func makeSnapshot() -> UIImage? {
        let scale = UIScreen.main.scale
        UIGraphicsBeginImageContextWithOptions(frame.size, false, scale)
        defer { UIGraphicsEndImageContext() }
        guard let context = UIGraphicsGetCurrentContext() else { return nil }
        render(in: context)
        let screenshot = UIGraphicsGetImageFromCurrentImageContext()
        return screenshot
    }
}

extension UIView {
    func makeSnapshot() -> UIImage? {
        if #available(iOS 10.0, *) {
            let renderer = UIGraphicsImageRenderer(size: frame.size)
            return renderer.image { _ in drawHierarchy(in: bounds, afterScreenUpdates: true) }
        } else {
            return layer.makeSnapshot()
        }
    }
}

extension UIImage {
    convenience init?(snapshotOf view: UIView) {
        guard let image = view.makeSnapshot(), let cgImage = image.cgImage else { return nil }
        self.init(cgImage: cgImage, scale: image.scale, orientation: image.imageOrientation)
    }
}

使用法

imageView.image = UIApplication.shared.makeSnapshot()

// or
imageView.image = view.makeSnapshot()

// or
imageView.image = view.layer.makeSnapshot()

// or
imageView.image = UIImage(snapshotOf: view)

古いソリューション

Xcode 8.2.1、Swift 3

IOS 10xのバージョン1

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

IOS 9x、10xのバージョン2

iOS 9xのバージョン1コードを使用しようとすると、エラーが発生します: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!
23

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
}
22
Daniel Storm

簡単にするために、独自のファイルに拡張子を追加します

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を拡張してその画像をキャプチャすることもできます。

10
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

IWindowのSwift 3拡張

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
  // 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

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タイプになります

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