LoginSignup
28
23

More than 5 years have passed since last update.

Swift2 カメラで静止画を撮影 (AVFoundation)

Last updated at Posted at 2016-01-17

Swift2で、AVCaptureStillImageOutputを使ったカメラでの画像撮影です。
Swiftはじめてまだ1週間くらいです。へんなとこあったら教えてください。

良かったらブログの方もご覧ください。

ソースコード

CameraViewController.swfit
import UIKit
import AVFoundation

class CameraViewController: UIViewController, UIGestureRecognizerDelegate {

    // AVキャプチャセッション
    var avSession: AVCaptureSession!

    // AVキャプチャデバイス
    var avDevice: AVCaptureDevice!

    // AVキャプチャデバイスインプット
    var avInput: AVCaptureInput!

    // AVキャプチャアウトプット
    var avOutput: AVCaptureStillImageOutput!

    override func viewDidLoad() {
        super.viewDidLoad()

        // 画面タップで撮影
        let tapGesture: UITapGestureRecognizer = UITapGestureRecognizer(target: self, action: "takePhoto:")
        tapGesture.delegate = self;
        self.view.addGestureRecognizer(tapGesture)

    }

    override func viewWillAppear(animated: Bool) {
        super.viewWillAppear(animated)
        self.initCamera()
    }

    func initCamera() {

        // AVキャプチャセッション
        // (AVFoundationにおけるキャプチャ入出力を管理するクラス)
        avSession = AVCaptureSession()

        if (avSession.canSetSessionPreset(AVCaptureSessionPresetPhoto)) {
            avSession.beginConfiguration()

            // キャプチャクオリティ設定
            // AVCaptureSessionPresetPhoto    写真専用、デバイスの最大解像度
            // AVCaptureSessionPresetHigh     最高録画品質 (静止画でも一番高画質なのはコレ)
            // AVCaptureSessionPresetMedium   WiFi向け
            // AVCaptureSessionPresetLow      3G向け
            // AVCaptureSessionPreset640x480  640x480 VGA固定
            // AVCaptureSessionPreset1280x720 1280x720 HD固定
            avSession.sessionPreset = AVCaptureSessionPresetPhoto

            avSession.commitConfiguration()
        }

        // AVキャプチャデバイス
        // (前背面カメラやマイク等のデバイス)
        let devices = AVCaptureDevice.devices()
        for capDevice in devices {
            if (capDevice.position == AVCaptureDevicePosition.Back) {
                // 背面カメラを取得
                avDevice = capDevice as? AVCaptureDevice
            }
        }

        if (avDevice != nil) {

            // AVキャプチャデバイスインプット
            // (AVキャプチャデバイスからの入力)
            do {
                // バックカメラからVideoInputを取得
                avInput = try AVCaptureDeviceInput.init(device: avDevice!)
            } catch let error as NSError {
                print(error)
            }

            // AVキャプチャデバイスインプットをセッションに追加
            if (avSession.canAddInput(avInput)) {

                avSession.addInput(avInput)

                // AVキャプチャアウトプット (出力方法)
                // AVCaptureStillImageOutput: 静止画
                // AVCaptureMovieFileOutput: 動画ファイル
                // AVCaptureAudioFileOutput: 音声ファイル
                // AVCaptureVideoDataOutput: 動画フレームデータ
                // AVCaptureAudioDataOutput: 音声データ

                avOutput = AVCaptureStillImageOutput()

                // 出力設定
                avOutput.outputSettings = [AVVideoCodecKey: AVVideoCodecJPEG]

                // AVキャプチャアウトプットをセッションに追加
                if (avSession.canAddOutput(avOutput)) {
                    avSession.addOutput(avOutput)
                }

                // 画像を表示するレイヤーを生成.
                let capVideoLayer: AVCaptureVideoPreviewLayer = AVCaptureVideoPreviewLayer.init(session:avSession)
                capVideoLayer.frame = self.view.bounds
                capVideoLayer.videoGravity = AVLayerVideoGravityResizeAspectFill

                // AVLayerVideoGravityResizeAspectFill
                //      アスペクト比維持 + 必要に応じてトリミング (縦いっぱいに表示し横をトリミング)

                // AVLayerVideoGravityResizeAspect
                //      アスペクト比維持 (縦横とも収まる様に表示)

                // AVLayerVideoGravityResize
                //      利用可能な画面領域いっぱいにリサイズ


                // Viewに追加.
                self.view.layer.addSublayer(capVideoLayer)

                // セッション開始.
                avSession.startRunning()

                renderView()

            }

        } else {

            // UIAlertControllerを作成する.
            let sampleAlert: UIAlertController = UIAlertController(title: "", message: "背面カメラがある実機で動かしてね。", preferredStyle: .Alert)

            // アクションを作成、追加
            let yesAction = UIAlertAction(title: "OK", style: .Default) {
                UIAlertAction in
                self.close()
            }
            sampleAlert.addAction(yesAction)

            // UIAlertを表示する
            self.presentViewController(sampleAlert, animated: true, completion: nil)
        }
    }

    // 画面を閉じる
    func close() {
        self.navigationController?.popViewControllerAnimated(true)
    }

    // 画面になにか重ねて表示する
    func renderView() {

        // 角丸なLabelを作成
        let labelHello: UILabel = UILabel(frame: CGRectMake(0, 0, self.view.frame.size.width - 40, 40))
        labelHello.layer.masksToBounds = true
        labelHello.layer.cornerRadius = 5.0

        labelHello.lineBreakMode = NSLineBreakMode.ByCharWrapping
        labelHello.numberOfLines = 1

        // 文字と文字色、背景色をセット
        labelHello.text = "画面タップで撮影&アルバム保存"
        labelHello.textColor = UIColor.whiteColor()
        labelHello.backgroundColor = UIColor.init(colorLiteralRed: 0.8, green: 0.2, blue: 0.3, alpha: 1.0)

        // 文字を中央寄せ、ウィンドウ中央に配置
        labelHello.textAlignment = NSTextAlignment.Center
        labelHello.layer.position = CGPoint(x: self.view.bounds.width/2, y: self.view.bounds.height - 80)

        // ViewにLabelを追加.
        self.view.addSubview(labelHello)
    }


    // 撮影をする
    func takePhoto(sender: UITapGestureRecognizer){

        // ビデオ出力に接続する
        let videoConnection = avOutput.connectionWithMediaType(AVMediaTypeVideo)

        // 接続から画像を取得する
        self.avOutput.captureStillImageAsynchronouslyFromConnection(videoConnection, completionHandler: { (imageDataBuffer, error) -> Void in

            // Jpegに変換する (NSDataにはExifなどのメタデータも含まれている)
            let imageData: NSData = AVCaptureStillImageOutput.jpegStillImageNSDataRepresentation(imageDataBuffer)

            // UIIMageを作成する
            let image: UIImage = UIImage(data: imageData)!

            // アルバムに追加する
            UIImageWriteToSavedPhotosAlbum(image, self, nil, nil)

            self.close()
        })  
    }   

    override func viewDidDisappear(animated: Bool) {
        super.viewDidDisappear(animated)

        // カメラの停止とメモリ解放
        self.avSession.stopRunning()

        for output in self.avSession.outputs {
            self.avSession.removeOutput(output as? AVCaptureOutput)
        }

        for input in self.avSession.inputs {
            self.avSession.removeInput(input as? AVCaptureInput)
        }

        self.avOutput = nil
        self.avInput = nil
        self.avDevice = nil
        self.avSession = nil
    }

}

28
23
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
28
23