ミライスタート TECH系ブログ

株式会社ミライスタートのエンジニア達が気になったTECH系の記事等をアップしています!

iOS swift カメラ 1.UIImagePickerController

 こんにちわ。株式会社ミライスタート、エンジニアの横田です。今回、swift、Xcodeの基本はある程度分かった位のレベルを対象にカメラ機能のチュートリアルを作成しています。自分もそれくらいのレベルで何とかカメラ機能を実装出来たばかりでして、知識の整理のためにという意図のアウトプットでもあります。拙いところもあるかもしれませんが、これからカメラアプリを作る後続者達の一助になってくれればいいんですけどね。

写真を撮るための選択肢
 iOSでカメラから静止画を撮影する場合、大きく3つの方法があるようです。難易度が低い順にあげていくと以下となります。

■UIImagePickerController
iOS標準のカメラ機能を呼び出すことが出来ます。カメラ機能の呼び出し、撮影した写真の受け取りの部分だけを実装すれば簡単にカメラを使ったアプリを作ることが出来ます。ただし、オリジナルの撮影画面を作りこんだり、細かい設定が出来ないのが難点です。

AVFoundation
■ AVCaptureStillImageOutput
■ AVCaptureVideoDataOutput
 AVFoundationというのは、UIImagePickerなどより直接的にカメラやマイクなどのメディアを扱う機能を集めたフレームワークらしいです。このフレームワークを使ってカメラを使う場合のやり方には、AVCaptureStillImageOutput、またはAVCaptureVideoDataOutputを使うという選択肢があります。すごく荒い解釈ですが、その名の表す通りそれぞれ、カメラから撮影した画像を静止画として出力する機能、動画として出力する機能となるようです。ですので写真撮影アプリを作るならAVCaptureStillImageOutputを使うのが定石かと最初は思ったのですが、写真を撮る前にプレビュー画面にリアルタイム処理を行いたい場合は(エフェクトをかけたり、顔認識をしたり)、AVCaptureVideoDataOutputの方が適しているようです。この機能を使って写真を保存する場合は、動画として出力されたデータの1コマを保存、という処理を行います。

UIImagePickerController
 今回は一番簡単なUIImagePickerControllerを紹介します。

 こんなコードを書き、

import UIKit
class ViewController: UIViewController, UIImagePickerControllerDelegate, UINavigationControllerDelegate {

    //撮影結果を表示するView
    @IBOutlet weak var cameraView: UIImageView!
    
    let cameraPicker = UIImagePickerController()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }

    //カメラボタンが押された時のアクション
    @IBAction func cameraStartButton(sender: AnyObject) {
        // カメラが利用可能かチェック
        if UIImagePickerController.isSourceTypeAvailable(UIImagePickerControllerSourceType.Camera){        
            // ソースタイプにカメラを指定して、
            cameraPicker.sourceType = UIImagePickerControllerSourceType.Camera
            cameraPicker.delegate = self

            //モーダル画面で撮影画面を表示
            self.presentViewController(cameraPicker, animated: true, completion: nil)
        }
    }

    //カメラ撮影完了時に呼び出すデリゲートメソッド
    func imagePickerController(imagePicker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : AnyObject]) {    
        if let pickedImage = info[UIImagePickerControllerOriginalImage] as? UIImage {
            cameraView.contentMode = .ScaleAspectFit
            cameraView.image = pickedImage
        }
        //モーダル画面を閉じる
        imagePicker.dismissViewControllerAnimated(true, completion: nil)
    }
}

そしてストーリーボードにUIImageViewとUIButtonを貼り付けた画面を作ってアウトレットをつなげて動かすと、
f:id:miraistart:20160615224657p:plain
 という具合にApple謹製カメラアプリとほぼ同じインターフェースの画面が呼び出されます。撮影した写真は作成した画面のUIImageViewに表示されています。けっこう簡単です。

 さらにこの撮影画面ですが、若干ですがカスタマイズも可能です。

            //デフォルトのカメラインターフェースをOFFにする
            cameraPicker.showsCameraControls = false
            
            //ボタンを作成
            let captureStartButton = UIButton()
            captureStartButton.layer.masksToBounds = true
            captureStartButton.backgroundColor = UIColor.redColor()
            captureStartButton.setTitle("撮影", forState: UIControlState.Normal)
            captureStartButton.frame = CGRect(x: (screenSize.width - captureStartViewWidth) / 2, y: screenSize.height - captureStartViewHeight - 10, width: captureStartViewWidth, height: captureStartViewHeight)
            captureStartButton.addTarget(self, action: #selector(ViewController.onClickMyButton(_:)), forControlEvents: .TouchUpInside)

            //作成したボタンをカメラ画面に重ねる
            cameraPicker.cameraOverlayView = captureStartButton

    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

    func onClickMyButton(sender: UIButton){
        //カメラ撮影を実行
        self.cameraPicker.takePicture()
    }

以上のようにカメラ撮影を呼ぶボタンを作成し、cameraOverlayViewに設定してやると、
f:id:miraistart:20160616225012j:plain
オリジナルの撮影ボタンが表示されました。このようにcameraOverlayViewに設定するViewを作りこんでいくことで、撮影画面の見た目を変えていくことは出来ます。