iOSでカメラを扱うにはUIImagePickerControllerがあります。撮影して、保存、アルバムで確認するアプリが作れます。
簡単に扱える半面できないこともあり、詳細を設定したい場合はAVCapturePhotoOutput あるいは AVCaptureVideoDataOutputを使います。
iOS11から NSPhotoLibraryAddUsageDescription を追加
Xcode 11.3.1
UIImagePickerController
UIImagePickerControllerを使ってみますが、これに限らずCameraを扱う場合ユーザー許可を得ないとcrashします。
Cocoa Keys
This app has crashed because it attempted to access privacy-sensitive data without a usage description. The app’s Info.plist must contain an NSCameraUsageDescription key with a string value explaining to the user how the app uses this data.
こういうエラーが表示されたら、説明の通りInfo.plist にNSCameraUsageDescriptionの設定を行いましょう。
加えて、フォトライブラリーも当然使うためNSPhotoLibraryAddUsageDescriptionも加えておきます。
NSPhotoLibraryAddUsageDescription が必要になりました
NSCameraUsageDescriptionというkeyを設定して、valueにはその理由を説明せよという事らしいですね。
Info.plistの編集:
Info.plistをプロジェクトで開いてKeyとvaleを追加します。
一番Topを選択すると「+」ボタンが表示されこれで「Key」の項目を作成でき、そのValueも追加することができます。
ただし、info.plistでは表示が変わります
- NSCameraUsageDescription
- Privacy – Camera Usage Description
- NSPhotoLibraryAddUsageDescription
- Privacy – Photo Library Additions Usage Description
もっとも、Finderからファイルを直接編集してしまう方が早いでしょう。
これをそのまま叩くとXcodeで前と同じになりますので、アプリを選択して「テキストエディット.app」とか自前で用意したエディタで編集すれば簡単です。
Info.plist
1 2 3 4 5 6 7 8 |
<dict> ... <key>NSCameraUsageDescription</key> <string>許可せんとcamera使えまへんで </string> <key>NSPhotoLibraryAddUsageDescription</key> <string>許可せんと保存できませんで </string> ... </dict> |
これを設定するとこんなDialogが表れます。
これにユーザーに許可をdialogで求めるのは最初だけで、その後は自動的に許可されています。ただし、設定のアプリから詳細設定でこの許可・不許可がいつでも設定できるようです。
なんかAndroidのRuntime Permissionのようになってきましたね。
ただし、不許可にした場合dialogが出てこない、機能が使えないだけでエラーになるわけでもない。
以前から使っていたNSPhotoLibraryUsageDescriptionは読み出しでは必要なのかとも思いましたが…iOS11では要らないような気がします。古いバージョンに対応する時は入れておきましょう。Ref: Cocoa Keys
- NSPhotoLibraryAddUsageDescription
- Specifies the reason for your app to get write-only access to the user’s photo library. See NSPhotoLibraryAddUsageDescription for details.
iOS 11 and later
- Specifies the reason for your app to get write-only access to the user’s photo library. See NSPhotoLibraryAddUsageDescription for details.
- NSPhotoLibraryUsageDescription
- Specifies the reason for your app to access the user’s photo library. See NSPhotoLibraryUsageDescription for details.
iOS 6.0 and later
- Specifies the reason for your app to access the user’s photo library. See NSPhotoLibraryUsageDescription for details.
camera app plan
Storyboard にアプリの構想もかねて部品を配置してみます
- カメラを起動させる
- ボタン:UIButton「Start」
- カメラ起動の action
- 撮影した画像を表示
- 画像表示:UIImageView
- 画像を保存
- ボタン:UIButton「Save」
- 画像を保存する action
- 保存した画像を確認する
- ボタン:UIButton「Album」
- アルバムに移動する action
- それぞれのステータスを表示
- ラベル:UILabel
ボタンを3つ作成して、それぞれに「Start」「Save」「Album」と名前を付け、背景色も付けます
UIImageView を配置し、ラベルをその下に入れます。まあ、このへんは好みですので適当で
UIImagePickerController
まずUIImagePickerController というクラスを使います
このクラスの親クラスは UINavigationController です
そのためデリゲートとして以下のDelegateをを設定
- UINavigationControllerDelegate
- UIImagePickerControllerDelegate
IBOutlet と部品との関係は
「UILabel」-> label
「UIImageView」-> cameraView
です、これに合わせて、storyboard の部品と紐付けします
また、それぞれの action は
startCamera
savePicture
showAlbum
でそれぞれのボタンに紐付けし記述します
ViewController.swift
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 |
import UIKit class ViewController: UIViewController, UIImagePickerControllerDelegate, UINavigationControllerDelegate{ @IBOutlet var cameraView : UIImageView! @IBOutlet var label : UILabel! override func viewDidLoad() { super.viewDidLoad() label.text = "Tap the [Start] to take a picture" } // カメラの撮影開始 @IBAction func startCamera(_ sender : Any) { let sourceType:UIImagePickerController.SourceType = UIImagePickerController.SourceType.camera // カメラが利用可能かチェック if UIImagePickerController.isSourceTypeAvailable( UIImagePickerController.SourceType.camera){ // インスタンスの作成 let cameraPicker = UIImagePickerController() cameraPicker.sourceType = sourceType cameraPicker.delegate = self self.present(cameraPicker, animated: true, completion: nil) } else{ label.text = "error" } } // 撮影が完了時した時に呼ばれる func imagePickerController(_ imagePicker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]){ if let pickedImage = info[.originalImage] as? UIImage { cameraView.contentMode = .scaleAspectFit cameraView.image = pickedImage } //閉じる処理 imagePicker.dismiss(animated: true, completion: nil) label.text = "Tap the [Save] to save a picture" } // 撮影がキャンセルされた時に呼ばれる func imagePickerControllerDidCancel(_ picker: UIImagePickerController) { picker.dismiss(animated: true, completion: nil) label.text = "Canceled" } // 写真を保存 @IBAction func savePicture(_ sender : Any) { let image:UIImage! = cameraView.image if image != nil { UIImageWriteToSavedPhotosAlbum( image, self, #selector(ViewController.image(_:didFinishSavingWithError:contextInfo:)), nil) } else{ label.text = "image Failed !" } } // 書き込み完了結果の受け取り @objc func image(_ image: UIImage, didFinishSavingWithError error: NSError!, contextInfo: UnsafeMutableRawPointer) { if error != nil { print(error.code) label.text = "Save Failed !" } else{ label.text = "Save Succeeded" } } // アルバムを表示 @IBAction func showAlbum(_ sender : Any) { let sourceType:UIImagePickerController.SourceType = UIImagePickerController.SourceType.photoLibrary if UIImagePickerController.isSourceTypeAvailable( UIImagePickerController.SourceType.photoLibrary){ // インスタンスの作成 let cameraPicker = UIImagePickerController() cameraPicker.sourceType = sourceType cameraPicker.delegate = self self.present(cameraPicker, animated: true, completion: nil) label.text = "Tap the [Start] to save a picture" } else{ label.text = "error" } } } |
カメラでの撮影は
1. カメラを利用する設定
2. カメラが利用可能かチェック
3. UIImagePickerController のインスタンスの作成
4. デリゲートを設定
5. present では
UIViewControllerが管理しているビューにを全画面を覆う画像の表示をします
self.present(cameraPicker, animated: true, completion: nil)
イメージピッカーはカメラ以外にも使います
- UIImagePickerControllerSourceType.camera
- カメラ
- UIImagePickerControllerSourceType.photoLibrary
- フォトライブラリ
そのため、UIImagePickerControllerSourceType
にどれを使うか指定します。
カメラを使う所と、アルバムを表示するところはほとんど同じです
このUIImagePickerCOntrollerを使ってCore MLを実装して機械学習アプリに作りかえられます。
関連:
- UIImagePickerController
- AVCapturePhotoOutput
- AVCaptureVideoDataOutput
References:
UIImagePickerController – UIKit | Apple Developer Documentation
imagePickerController