MENU

【swift アプリ開発】AVFoundationで自前カメラ画面を作成してみよう!

  • URLをコピーしました!
ios-appdevelopment-0013-02

こんにちは!Popoです。

今回は、カメラ画面を作成してみたいと思います。

こんな方へのお勧めの記事です。

  • カメラアプリを作成したい
  • カスタマイズ可能なカメラ画面を作成したい
  • 「AVFoundation」を学習したい

昔、書籍を購入してobjective-cの勉強をしていたころ。

学習項目の中に必ず「カメラ画面作成のページがあったなぁ」と思い出しています。

定番の学習項目といったところですね。

目次

「AVFoundation」フレームワークを利用する理由

「AVFoundation」フレームワークを利用する理由

書籍等では「UIImagePickerController」を利用しているものが多いです。

私がなぜ「AVFoundation」フレームワークを利用しているか?

「AVFoundation」フレームワークのメリット、デミリットをあげてみますと!(ザックリですが)

メリットデメリット
カメラ画面に色々なカスタマイズ可能ロジックが「UIImagePickerController」より複雑

私が「AVFoundation」を選択する一番の理由は「カメラ画面に色々なカスタマイズが可能」という点です。

「UIImagePickerController」では、フレームワークのお決まり画面になってしまうため自由度がありません。

その反面、ロジックがかさむというデミリットもあります。(私の開発方針自体ロジックがかさみますが😅)

私は、メリットの方が効果が大きいと判断して「AVFoundation」を利用しています。

アプリの動作環境

アプリの動作環境

アプリの開発環境です。

項目バージョン
XcodeVersion 14.3.1 (14E300c)
SwiftSwift version 5.8.1
MacOSmacOS Ventura バージョン13.4(22F66)

アプリ開発の前提条件

アプリ開発の前提条件

アプリを開発する上で、コーディング以外に必要な設定や作業を上げておきます。

カメラロールアクセス

カメラロールへのアクセスについては、前記事の「カメラロールへのアクセス前提条件」項目を参照してください。

カメラロールへ画像データ追加

アプリからデバイスのカメラロールに画像データを追加するためには「info.plist」にNSPhotoLibraryAddUsageDescriptionキーを追加する必要があります。

NSPhotoLibraryAddUsageDescriptionキー

Valueには、アプリ初回起動時に表示されるダイアログのメッセージを入力しておきます。

カメラロールアクセスメッセージ

カメラへのアクセス

アプリからデバイスのカメラにアクセスをするためには「info.plist」にNSCameraUsageDescriptioキーを追加する必要があります。

NSCameraUsageDescriptioキー

こちらも同様に、Valueにはダイアログに表示されるメッセージを設定します。

エラーメッセージ

「AVFoundation」フレームワーク

「AVFoundation」フレームワーク

「AVFoundation」フレームワークでは、Appleプラットフォーム上でオーディオビジュアルメディアを検査、再生、キャプチャするための幅広いAPIが用意されています。

今回は下記の4つを利用していきます。

AVCaptureSession

キャプチャ動作を構成し、入力デバイスからキャプチャ出力までのデータ処理を調整します。

AVCaptureDevice

カメラ等、仮想キャプチャデバイスのオブジェクトです。

AVCapturePhotoOutput

キャプチャーの出力を管理します。

AVCaptureVideoPreviewLayer

カメラからビデオを表示するためのレイアになります。

アプリのソースコード全体

アプリのソースコード全体

ソースコードについて解説していきます。

OneViewController

メインのUIViewControllerの解説です。

主な機能

  • AVCaptureSession生成
  • AVCaptureDeviceの生成
  • AVCapturePhotoOutputの生成
  • AVCaptureVideoPreviewLayerの生成
  • カメラロールアクセスの判定とエラーメッセージ設定
  • シャッターボタンの生成
  • シャッターボタンタッチイベント
  • AVCapturePhotoCaptureDelegateデリゲートメソッド
  • カメラロールへ画像データ出力

import UIKit
import AVFoundation

class OneViewController: UIViewController {
    
    // デバイスからの入力と出力を管理するオブジェクトの作成
    fileprivate var captureSession = AVCaptureSession()
    // カメラデバイスそのものを管理するオブジェクトの作成
    // メインカメラの管理オブジェクトの作成
    fileprivate var mainCamera: AVCaptureDevice?
    // インカメの管理オブジェクトの作成
    fileprivate var innerCamera: AVCaptureDevice?
    // 現在使用しているカメラデバイスの管理オブジェクトの作成
    fileprivate var currentDevice: AVCaptureDevice?
    // キャプチャーの出力データを受け付けるオブジェクト
    fileprivate var photoOutput : AVCapturePhotoOutput?
    // プレビュー表示用のレイヤ
    fileprivate var cameraPreviewLayer : AVCaptureVideoPreviewLayer?

    //cameraボタン---------------------------------------
    fileprivate var shutterButton : UIButton!
    
    fileprivate var shutterImageView = UIImageView()
    //View Size取得
    fileprivate var camerabaseRect = UIScreen.main.bounds
    //シャッターボタン重複チェックフラグ
    fileprivate var shutterFlag : Bool = true
    //カメラ使用許可フラグ
    fileprivate var errorFlag : Bool = true

    override func viewDidLoad() {
        super.viewDidLoad()
        
        self.view.backgroundColor = UIColor.black
        if (self.cameraFirstAuthorization())
        {
            //カメラ使用許可
            self.errorFlag = true
            //カメラ生成
            self.setupCaptureSession()
            self.setupDevice()
            self.setupInputOutput()
            self.setupPreviewLayer()

        } else {
            //カメラ使用許可
            self.errorFlag = false

        }
        
    }
    
    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        
        self.shutterFlag = true
        //エラーチェック
        if (!self.errorFlag)
        {
            //エラーメッセージ表示
            self.cameraUseError()
        } else {
            //カメラ画面
            self.captureSession.startRunning()
        }
        //--ボタン生成-----------------------------
        self.initButton()
        //---------------------------------------
        
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }
    
    
}
//MARK: 画面UI
extension OneViewController
{
    //Layer,totalボタン生成
    fileprivate func initButton() {

        //シャッターボタン------------------------------------------------
        self.shutterButton = UIButton()
        self.shutterButton.backgroundColor = UIColor.clear
        self.shutterButton.addTarget(self, action: #selector(OneViewController.shutterButtonPush(_:)), for: UIControl.Event.touchUpInside)
        self.shutterButton.layer.cornerRadius = min(self.shutterButton.frame.width, self.shutterButton.frame.height) / 2
       
        let cameraButtonSize = CGRect(x:(SCREEN_WIDTH/2) - 40, y: SCREEN_HEIGHT - 115, width: 80, height: 80)
        self.shutterButton.frame = cameraButtonSize
        self.shutterButton.isEnabled = true

        self.view.addSubview(self.shutterButton)
        
        //シャッターimageView------------------------------------------------
        let headerImage :UIImage? = UIImage(named:"shutterButton")
        self.shutterImageView = UIImageView(image:headerImage)
        
        self.shutterImageView.frame = CGRect(x:(SCREEN_WIDTH/2) - 40, y: SCREEN_HEIGHT - 115, width: 80, height: 80)
        self.shutterImageView.backgroundColor = UIColor.black
        self.shutterImageView.contentMode = UIView.ContentMode.scaleAspectFit
        self.shutterImageView.isUserInteractionEnabled = false
        self.view.addSubview(self.shutterImageView)
        
    }
    //カメラ アクセス確認
    fileprivate func cameraFirstAuthorization() ->Bool
    {
        var checkFlag:String = "0"
        switch AVCaptureDevice.authorizationStatus(for: AVMediaType.video) {
        case .authorized:
            print("cameraFirstAuthorization authorized")
            break
        // キャプチャー開始など
        case .denied:
            print("cameraFirstAuthorization denied")
            checkFlag = "1"
            break
        // 拒否されてる。設定画面への遷移示唆など
        case .notDetermined:
            print("cameraFirstAuthorization notDetermined")
            AVCaptureDevice.requestAccess(for: .video, completionHandler: {accessGranted in
                if (!accessGranted)
                {
                    checkFlag = "1"
                }
                
            })
            break
        // 初回。確認ダイアログをここで出すとハンドリングが楽。
        case .restricted:
            print("cameraFirstAuthorization Restricted")
            // 利用が制限されている。ペアレント・コントロール?
            checkFlag = "1"
            break
        @unknown default:
            print("@unknown default")
            break
        }
        if checkFlag == "0"
        {
            return true
        } else {
            return false
        }
    }
    //カメラ アクセスエラーメッセージ
    fileprivate func cameraUseError()
    {
        let alertVC = UIAlertController(title: "カメラにアクセスする権限がありません。アプリケーションの権限設定を変更してください。", message: nil, preferredStyle: .alert)
        alertVC.addAction(UIAlertAction(title: "OK", style: .default, handler: { (action) in
            
        }))
        self.present(alertVC, animated: true, completion: nil)
    }
}
//MARK: ボタンイベント
extension OneViewController{

    //カメラシャッターボタン------------------------------------
    @objc func shutterButtonPush(_ sender: UIButton)
    {
        if self.shutterFlag
        {
            
            self.shutterFlag = false
            // フラッシュの設定
            let settings = AVCapturePhotoSettings()
            //flashサポートしてるかの確認
            let device = AVCaptureDevice.default(
                AVCaptureDevice.DeviceType.builtInWideAngleCamera,
                for: AVMediaType.video, // ビデオ入力
                position: AVCaptureDevice.Position.back)
            if !device!.hasFlash{
                settings.flashMode = .off
            } else {
                settings.flashMode = .auto
            }
 
            // 撮影された画像をdelegateメソッドで処理
            self.photoOutput?.capturePhoto(with: settings, delegate: self as AVCapturePhotoCaptureDelegate)

        }
    }
}

//MARK: AVCapturePhotoCaptureDelegateデリゲートメソッド
extension OneViewController: AVCapturePhotoCaptureDelegate{
    
    // 撮影した画像データが生成されたときに呼び出されるデリゲートメソッド
    func photoOutput(_ output: AVCapturePhotoOutput, didFinishProcessingPhoto photo: AVCapturePhoto, error: Error?) {
        if let imageData = photo.fileDataRepresentation() {
            // Data型をUIImageオブジェクトに変換
            let image = UIImage(data: imageData)
            
            //画像データを写真に登録
            self.imagePhotoSave(image)
        }
    }

}
//MARK: カメラ設定メソッド
extension OneViewController{
    // カメラの画質の設定
    fileprivate func setupCaptureSession() {
        // sessionPreset: キャプチャ・クオリティの設定
        //session.sessionPreset = AVCaptureSession.Preset.high
        // session.sessionPreset = AVCaptureSessionPresetPhoto
        // session.sessionPreset = AVCaptureSessionPresetHigh
        // session.sessionPreset = AVCaptureSessionPresetMedium
        // session.sessionPreset = AVCaptureSessionPresetLow
        self.captureSession.sessionPreset = AVCaptureSession.Preset.photo
        //captureSession.sessionPreset = AVCaptureSession.Preset.medium
    }
    
    // デバイスの設定
    fileprivate func setupDevice() {
        // カメラデバイスのプロパティ設定
        let deviceDiscoverySession = AVCaptureDevice.DiscoverySession(deviceTypes: [AVCaptureDevice.DeviceType.builtInWideAngleCamera], mediaType: AVMediaType.video, position: AVCaptureDevice.Position.unspecified)
        // プロパティの条件を満たしたカメラデバイスの取得
        let devices = deviceDiscoverySession.devices
        
        for device in devices {
            if device.position == AVCaptureDevice.Position.back {
                self.mainCamera = device
            } else if device.position == AVCaptureDevice.Position.front {
                self.innerCamera = device
            }
        }
        // 起動時のカメラを設定
        self.currentDevice = self.mainCamera
    }
    
    // 入出力データの設定
    fileprivate func setupInputOutput() {
        do {
            // 指定したデバイスを使用するために入力を初期化
            let captureDeviceInput = try AVCaptureDeviceInput(device: self.currentDevice!)
            // 指定した入力をセッションに追加
            self.captureSession.addInput(captureDeviceInput)
            // 出力データを受け取るオブジェクトの作成
            self.photoOutput = AVCapturePhotoOutput()
            // 出力ファイルのフォーマットを指定
            if #available(iOS 11.0, *)
            {
                self.photoOutput?.setPreparedPhotoSettingsArray([AVCapturePhotoSettings(format:[AVVideoCodecKey:AVVideoCodecType.jpeg])], completionHandler: nil)
            } else {
                self.photoOutput?.setPreparedPhotoSettingsArray([AVCapturePhotoSettings(format:[AVVideoCodecKey:AVVideoCodecJPEG])], completionHandler: nil)
            }
            self.captureSession.addOutput(self.photoOutput!)
        } catch {
            print(error)
        }
    }
    
    // カメラのプレビューを表示するレイヤの設定
    fileprivate func setupPreviewLayer() {
        // 指定したAVCaptureSessionでプレビューレイヤを初期化
        self.cameraPreviewLayer = AVCaptureVideoPreviewLayer(session: captureSession)
        // プレビューレイヤが、カメラのキャプチャーを縦横比を維持した状態で、表示するように設定
        //self.cameraPreviewLayer?.videoGravity = AVLayerVideoGravity.resizeAspectFill
        self.cameraPreviewLayer?.videoGravity = AVLayerVideoGravity.resizeAspect
        // プレビューレイヤの表示の向きを設定
        self.cameraPreviewLayer?.connection?.videoOrientation = AVCaptureVideoOrientation.portrait

        
        self.cameraPreviewLayer?.frame = CGRect(x: 0, y: 80, width: self.camerabaseRect.width, height: self.camerabaseRect.width + 100)
        
        self.view.layer.insertSublayer(self.cameraPreviewLayer!, at: 0)
    }

}
//MARK: カメラ設定メソッド
extension OneViewController{
    
    //写真ライブラリに保存
    fileprivate func imagePhotoSave(_ image:UIImage!)
    {
        //カメラ画面停止
        self.captureSession.stopRunning()
        
        guard let cameraImage:UIImage = image?.fixOrientation() else{
            return
        }

        //写真ライブラリに保存
        UIImageWriteToSavedPhotosAlbum(cameraImage, nil, nil, nil)
    }   
}

アプリの画面動作

アプリの画面動作を動画で見てみましょう!

各ロジック解説

各ロジック解説

それでは、各クラスの詳細箇所の解説をします。

Import

「AVFoundation」をインポートします。

import UIKit
import AVFoundation

viewDidLoad、viewWillAppear

  • viewDidLoad

画面の背景色は黒色にします。

「cameraFirstAuthorization」メソッドでカメラアクセスの判定を行い、許可状態であれば「AVCaptureSession」「AVCaptureDevice」「AVCapturePhotoOutput」「AVCaptureVideoPreviewLayer」を生成します。

    override func viewDidLoad() {
        super.viewDidLoad()
        
        self.view.backgroundColor = UIColor.black
        if (self.cameraFirstAuthorization())
        {
            //カメラ使用許可
            self.errorFlag = true
            //カメラ生成
            self.setupCaptureSession()
            self.setupDevice()
            self.setupInputOutput()
            self.setupPreviewLayer()

        } else {
            //カメラ使用許可
            self.errorFlag = false

        }
        
    }
  • viewWillAppear

「viewDidLoad」でのカメラアクセス判定結果から、エラーメッセージ表示かカメラ起動を行います。

     override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        
        self.shutterFlag = true
        //エラーチェック
        if (!self.errorFlag)
        {
            //エラーメッセージ表示
            self.cameraUseError()
        } else {
            //カメラ画面
            self.captureSession.startRunning()
        }
        //--ボタン生成-----------------------------
        self.initButton()
        //---------------------------------------
        
    }

カメラアクセスが許可されていない場合は、下記のエラーメッセージが表示されます。

カメラアクセスエラーメッセージ

ボタン生成

私は、基本「UIButton」の「setImage」は使用しません。「UIImageView]を使用します。

「UIImageView」の「contentMode」で綺麗に画像を表示することができるためです。

      //Layer,totalボタン生成
    fileprivate func initButton() {

        //シャッターボタン------------------------------------------------
        self.shutterButton = UIButton()
        self.shutterButton.backgroundColor = UIColor.clear
        self.shutterButton.addTarget(self, action: #selector(OneViewController.shutterButtonPush(_:)), for: UIControl.Event.touchUpInside)
        self.shutterButton.layer.cornerRadius = min(self.shutterButton.frame.width, self.shutterButton.frame.height) / 2
       
        let cameraButtonSize = CGRect(x:(SCREEN_WIDTH/2) - 40, y: SCREEN_HEIGHT - 115, width: 80, height: 80)
        self.shutterButton.frame = cameraButtonSize
        self.shutterButton.isEnabled = true

        self.view.addSubview(self.shutterButton)
        
        //シャッターimageView------------------------------------------------
        let headerImage :UIImage? = UIImage(named:"shutterButton")
        self.shutterImageView = UIImageView(image:headerImage)
        
        self.shutterImageView.frame = CGRect(x:(SCREEN_WIDTH/2) - 40, y: SCREEN_HEIGHT - 115, width: 80, height: 80)
        self.shutterImageView.backgroundColor = UIColor.black
        self.shutterImageView.contentMode = UIView.ContentMode.scaleAspectFit
        self.shutterImageView.isUserInteractionEnabled = false
        self.view.addSubview(self.shutterImageView)
        
    }

カメラロールアクセス許可

「AVCaptureDevice.authorizationStatus」を使用してカメラアクセスの許可判定を行っています。

    //カメラ アクセス確認
    fileprivate func cameraFirstAuthorization() ->Bool
    {
        var checkFlag:String = "0"
        switch AVCaptureDevice.authorizationStatus(for: AVMediaType.video) {
        case .authorized:
            print("cameraFirstAuthorization authorized")
            break
        // キャプチャー開始など
        case .denied:
            print("cameraFirstAuthorization denied")
            checkFlag = "1"
            break
        // 拒否されてる。設定画面への遷移示唆など
        case .notDetermined:
            print("cameraFirstAuthorization notDetermined")
            AVCaptureDevice.requestAccess(for: .video, completionHandler: {accessGranted in
                if (!accessGranted)
                {
                    checkFlag = "1"
                }
                
            })
            break
        // 初回。確認ダイアログをここで出すとハンドリングが楽。
        case .restricted:
            print("cameraFirstAuthorization Restricted")
            // 利用が制限されている。ペアレント・コントロール?
            checkFlag = "1"
            break
        @unknown default:
            print("@unknown default")
            break
        }
        if checkFlag == "0"
        {
            return true
        } else {
            return false
        }
    }

「AVCaptureDevice.authorizationStatus」のマニュアルになります。

「viewDidLoad」で呼ばれているメソッドです。

シャッターボタンタッチイベント

デバイスにフラッシュ機能があるかチェックを行い、delegateメソッドをCallしてキャプチャを取得します。

flash機能の無いデバイスに「.auto」の設定でdelegateメソッドをCallするとクラッシュしてしまいます。

     //カメラシャッターボタン------------------------------------
    @objc func shutterButtonPush(_ sender: UIButton)
    {
        if self.shutterFlag
        {
            
            self.shutterFlag = false
            // フラッシュの設定
            let settings = AVCapturePhotoSettings()
            //flashサポートしてるかの確認
            let device = AVCaptureDevice.default(
                AVCaptureDevice.DeviceType.builtInWideAngleCamera,
                for: AVMediaType.video, // ビデオ入力
                position: AVCaptureDevice.Position.back)
            if !device!.hasFlash{
                settings.flashMode = .off
            } else {
                settings.flashMode = .auto
            }
 
            // 撮影された画像をdelegateメソッドで処理
            self.photoOutput?.capturePhoto(with: settings, delegate: self as AVCapturePhotoCaptureDelegate)
   
        }
    }

AVCapturePhotoCaptureDelegateデリゲートメソッド

カメラで撮影した画像データを取得します。

     // 撮影した画像データが生成されたときに呼び出されるデリゲートメソッド
    func photoOutput(_ output: AVCapturePhotoOutput, didFinishProcessingPhoto photo: AVCapturePhoto, error: Error?) {
        if let imageData = photo.fileDataRepresentation() {
            // Data型をUIImageオブジェクトに変換
            let image = UIImage(data: imageData)
            
            //画像データを写真に登録
            self.imagePhotoSave(image)
        }
    }

カメラ生成

カメラの生成ロジックになります。

カメラの画質の設定

色々と試したため、他のプロパティはコメントにしています。

「sessionPreset」でカメラの品質レベル、ビートレートを設定します。

    fileprivate func setupCaptureSession() {
        // sessionPreset: キャプチャ・クオリティの設定
        //session.sessionPreset = AVCaptureSession.Preset.high
        // session.sessionPreset = AVCaptureSessionPresetPhoto
        // session.sessionPreset = AVCaptureSessionPresetHigh
        // session.sessionPreset = AVCaptureSessionPresetMedium
        // session.sessionPreset = AVCaptureSessionPresetLow
        self.captureSession.sessionPreset = AVCaptureSession.Preset.photo
        //captureSession.sessionPreset = AVCaptureSession.Preset.medium
    }

詳細は下記を参照ください。

プロパティ内容
high高品質の出力をキャプチャするのに適したプリセット。
medium中品質の出力をキャプチャするのに適したプリセット。
low低品質の出力をキャプチャするのに適したプリセット。
photo高解像度の写真品質の出力をキャプチャするのに適したプリセット。
inputPriorityキャプチャ セッションのオーディオおよびビデオ出力設定を指定しないプリセット。
qHD960x540クォーター HD 品質 (960 x 540 ピクセル) ビデオ出力のキャプチャに適したプリセット。
hd1280x720720p 品質 (1280 x 720 ピクセル) ビデオ出力のキャプチャに適したプリセット。
hd1920x10801080p 品質 (1920 x 1080 ピクセル) ビデオ出力のキャプチャに適したプリセット。
hd4K3840x21602160p 品質 (3840 x 2160 ピクセル) のビデオ出力のキャプチャに適したプリセット。
qvga320x240320 x 240 ピクセルのビデオ出力のキャプチャに適したプリセット。
vga640x480VGA 品質 (640 x 480 ピクセル) ビデオ出力のキャプチャに適したプリセット。
iFrame960x540AAC オーディオを使用して、960 x 540 品質の iFrame H.264 ビデオを約 30 Mbit/秒でキャプチャするのに適したプリセット。
iFrame1280x720AAC オーディオを使用して、約 40 Mbit/秒で 1280 x 720 品質の iFrame H.264 ビデオをキャプチャするのに適したプリセット。
cif352x288CIF 品質 (352 x 288 ピクセル) ビデオ出力のキャプチャに適したプリセット。

デバイスの設定

「AVCaptureDevice.Position.back」(デバイスの被写体に面する側の位置)のオブジェクトを取得します。

      fileprivate func setupDevice() {
        // カメラデバイスのプロパティ設定
        let deviceDiscoverySession = AVCaptureDevice.DiscoverySession(deviceTypes: [AVCaptureDevice.DeviceType.builtInWideAngleCamera], mediaType: AVMediaType.video, position: AVCaptureDevice.Position.unspecified)
        // プロパティの条件を満たしたカメラデバイスの取得
        let devices = deviceDiscoverySession.devices
        
        for device in devices {
            if device.position == AVCaptureDevice.Position.back {
                self.mainCamera = device
            } else if device.position == AVCaptureDevice.Position.front {
                self.innerCamera = device
            }
        }
        // 起動時のカメラを設定
        self.currentDevice = self.mainCamera
    }

Appleのドキュメントです。

 入出力データの設定

入出力の情報を「AVCaptureSession」に設定します。

     fileprivate func setupInputOutput() {
        do {
            // 指定したデバイスを使用するために入力を初期化
            let captureDeviceInput = try AVCaptureDeviceInput(device: self.currentDevice!)
            // 指定した入力をセッションに追加
            self.captureSession.addInput(captureDeviceInput)
            // 出力データを受け取るオブジェクトの作成
            self.photoOutput = AVCapturePhotoOutput()
            // 出力ファイルのフォーマットを指定
            if #available(iOS 11.0, *)
            {
                self.photoOutput?.setPreparedPhotoSettingsArray([AVCapturePhotoSettings(format:[AVVideoCodecKey:AVVideoCodecType.jpeg])], completionHandler: nil)
            } else {
                self.photoOutput?.setPreparedPhotoSettingsArray([AVCapturePhotoSettings(format:[AVVideoCodecKey:AVVideoCodecJPEG])], completionHandler: nil)
            }
            self.captureSession.addOutput(self.photoOutput!)
        } catch {
            print(error)
        }
    }

カメラのプレビューを表示するレイヤの設定

    fileprivate func setupPreviewLayer() {
        // 指定したAVCaptureSessionでプレビューレイヤを初期化
        self.cameraPreviewLayer = AVCaptureVideoPreviewLayer(session: captureSession)
        // 
        self.cameraPreviewLayer?.videoGravity = AVLayerVideoGravity.resizeAspect
        // プレビューレイヤの表示の向きを設定
        self.cameraPreviewLayer?.connection?.videoOrientation = AVCaptureVideoOrientation.portrait

        self.cameraPreviewLayer?.frame = CGRect(x: 0, y: 80, width: self.camerabaseRect.width, height: self.camerabaseRect.width + 100)
        
        self.view.layer.insertSublayer(self.cameraPreviewLayer!, at: 0)
    }

    //View Size取得

    fileprivate var camerabaseRect = UIScreen.main.bounds

上記の画面サイズの定義は入れています。

カメラロール出力

カメラを停止後、カメラロールに画像データを出力します。

    //写真ライブラリに保存
    fileprivate func imagePhotoSave(_ image:UIImage!)
    {
        //カメラ画面停止
        self.captureSession.stopRunning()
        
        guard let cameraImage:UIImage = image?.fixOrientation() else{
            return
        }

        //写真ライブラリに保存
        UIImageWriteToSavedPhotosAlbum(cameraImage, nil, nil, nil)
    }

まとめ

まとめ

「AVFoundation」フレームワークを利用してカメラ画面を作成してみました。

このフレームワークのメリットは、

カメラ画面に色々なカスタマイズが可能

パターンを掴めば、かさむロジックも大した事はないと思っています。

それよりも色々なカスタマイズができる事の方が有益性が高いです。

私はもう「UIImagePickerController」には戻れません。

それではまた!

よかったらシェアしてね!
  • URLをコピーしました!
目次