iPadとPlaygroundsで学ぶ:内蔵カメラで写真を撮る【UIImagePickerController編】

内蔵カメラでの写真撮影に挑戦します。

カメラの機能を使う場合、以下の2つの方法があるようです。

  • UIImagePickerControllerでシステムカメラを利用する(お手軽,細かい制御はできない)
  • AVFoundationでカメラの機能を直接使う(色々自分で実装する必要がある,細かい制御ができる)

今回はUIImagePickerControllerを使ってみます。 developer.apple.com

UIImagePickerControllerでカメラを起動

UIImagePickerControllerを使うと以下の手順でカメラを起動することができます。

  1. UIImagePickerControllerのインスタンスを生成する
  2. 生成したインスタンスのsourceTypeにUIImagePickerController.SourceType.cameraを設定する
  3. プロトコルを登録する
  4. presentで生成したインスタンスへ画面遷移する

非常に簡単ですね。3.については次で説明します。

appleのサイトにはsourceTypeとmediaTypeが対応しているものかどうか確認するように書いてありますが今回は割愛します。

撮影結果を受け取る

UIImagePickerControllerの役割は画像データを準備してくれるところまでです。画像データを受け取るためにはプロトコルを使います。

プロトコルは他の言語で言うところのインターフェースクラスみたいなものです。 プロトコルを継承したクラスで必要な関数を実装し、そのクラスのインスタンスをコントローラーに登録することでイベントが発生した時に通知してもらうことが出来ます。

UIImagePickerControllerの通知は次のプロトコルを継承して受け取ります。

// プロトコル
UIImagePickerControllerDelegate

// 画像データが準備できたことを通知してもらう関数
UIImagePickerControllerDelegate. imagePickerController
// キャンセルされたことを通知してもらう関数
UIImagePickerControllerDelegate. imagePickerControllerDidCancel

上記の関数は通知に対して何か処理したいものだけ実装すれば良いです。今回はimagePickerControllerのみ実装します。

画像データはimagePickerController関数の第2引数(info)に格納されて渡されます。 infoは連想配列でいくつかの情報を保持しており、撮影した画像データはキーUIImagePickerController.InfoKey.originalImageを指定して取り出せます。

func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
    // 取り出してからUIImageにキャストする
    let image = info[UIImagePickerController.InfoKey.originalImage] as? UIImage 
}

またUIImagePickerControllerにプロトコルを登録する場合は画面遷移に関する下記プロトコルも継承する必要があります。こちらについても処理を追加したい関数のみ実装すれば良いです。

UINavigationControllerDelegate

アプリの仕様

ビューにボタンを配置しボタンが押されたときにシステムカメラを起動します。 画像を撮影しキャンセルされなかった場合には画面をアルバムに保存します。

コード

以下コードです。

import UIKit

class ViewController: UIViewController, UIImagePickerControllerDelegate, UINavigationControllerDelegate {
    var imagePicker: UIImagePickerController?
    var mainView: UIView?
    var button: UIButton?
    override func viewDidLoad() {
        createElements()
        setAnchorConstraint()
    }
    func createElements() {
        self.imagePicker = UIImagePickerController()
        self.mainView = UIView()
        self.button = UIButton()
        guard
            let imagePicker = self.imagePicker,
            let mainView = self.mainView,
            let button = self.button else {
            return
        }
        button.backgroundColor = UIColor.magenta
        button.addTarget(self, action:#selector(self.buttonEvent(_:)), for: UIButton.Event.touchUpInside)
        mainView.addSubview(button)
        self.view = mainView
    }
    func setAnchorConstraint() {
        guard
            let mainView = self.view,
            let button = self.button else {
            return
        }
        button.translatesAutoresizingMaskIntoConstraints = false
        button.centerXAnchor.constraint(equalTo:mainView.centerXAnchor).isActive = true
        button.bottomAnchor.constraint(equalTo:mainView.bottomAnchor, constant: -100).isActive = true
        button.widthAnchor.constraint(equalToConstant:60).isActive = true
        button.heightAnchor.constraint(equalToConstant:30).isActive = true
    }
    func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
        // 撮影結果から画像データを取り出す
        if let image = info[UIImagePickerController.InfoKey.originalImage] as? UIImage {
            // アルバムへ保存
            UIImageWriteToSavedPhotosAlbum(image, nil, nil, nil)
        }
        // 遷移元へ戻る
        picker.dismiss(animated:true, completion:nil)
    }
    @objc func buttonEvent(_ sender: UIButton) {
        guard let imagePicker = self.imagePicker else {
            return
        }
       // UIImagePickerControllerの設定
        imagePicker.sourceType = UIImagePickerController.SourceType.camera
        // protocolを設定
        imagePicker.delegate = self
        // 画面遷移
        present(imagePicker, animated:true, completion:nil)
    }
}

import PlaygroundSupport
PlaygroundPage.current.liveView = ViewController()

アルバムに保存する関数は実行結果を受け取るイベントを指定できるようですが今回は省略します。

実機で実行する場合

iPad + Playgroundsでは特に問題なく実行できましたが、実機でこのプログラムを動かす場合にはユーザー許可が必要です。 ユーザー許可の設定方法については実機で動かすときにまとめたいと思います。