カメラによる写真撮影とフォトライブラリの写真利用について

フォトライブラリに蓄えられた写真に関しては、アプリケーションから自由に利用できるようです.

またアプリからカメラを起動し、写真撮影を行った画像の利用もおこなえるようです.

iPhone OS プログラミングガイドにも、簡単な概要が書かれているようですが、少々わかりづらかったので
まとめておくことにします.


概要

アプリ中で、カメラから写真撮影した画像をつかったり、フォトライブラリに蓄えられた画像を利用するためには、
UIImagePickerController を利用する.

概要としては、iPhone OS プログラミングガイドで「カメラによる写真の撮影」として紙面が割かれているので
参照すると良い.

ポイントは、次のようになる.

  • UIViewController から派生した、独自の ViewController を利用する
  • UIImagePickerController には、UIImagePickerControllerDelegate/UINavigationControllerDelegate を割り当てる必要がある.
  • カメラはついていないデバイス(iPod touch)が存在するので、利用できるかチェックが必要.
  • 撮影(選択)された、Image はデリゲートから渡される.
  • 撮影(選択)時/キャンセル時には、Picker の削除が必要.
  • UIImagePickerController から、処理したい View への Image の渡し方.

サンプルで作成してみるアプリの外観は、こんな感じ


(機能)

  • Camera ボタンを押すと、カメラを起動して画像取得、Photo Library ボタンを押すとフォトライブラリから画像の取得の表示を行う.
  • 取得した画像を、View に貼り付けておいた UIImageView に設定して画面表示する.

UIViewController に関して

iPhone OS プログラミングガイドでは、要点しかソースが載っていないし、直接的なサンプルも用意されていないので、
全体像がよく見えてこない.

よって、冗長かとはおもうが、私がテストに利用したソースをそのまま貼り付けておくことにした.
# はてな dialy でファイルの添付ができりゃいいのに...

(CameraViewController.h)

@interface CameraViewController
    : UIViewController <UIImagePickerControllerDelegate, UINavigationControllerDelegate>
{
    IBOutlet UIImageView* m_image_view;
}

/// PhotoLibrary からのイメージ読み込みボタン押下
- (IBAction) getImageByPhotoLibrary:(id)i_sender;

/// Camera からのイメージ読み込みボタン押下
- (IBAction) getImageByCamera:(id)i_sender;

@end

(CameraViewController.mm)

#include "CameraViewController.h"

// private
@interface CameraViewController()

/// CameraPicker の開始を行う
- (BOOL) startCameraPickerFromViewController:(UIViewController*)i_controller
                               usingDelegate:(id<UIImagePickerControllerDelegate, UINavigationControllerDelegate>)i_delegate
                                  sourceType:(UIImagePickerControllerSourceType)i_type;

- (void) useImage:(UIImage*)i_image;

@end

@implementation CameraViewController

/// ソースタイプを指定してイメージの取得を行う
- (void) getImageBySourceType:(UIImagePickerControllerSourceType)i_type
{
}

/// PhotoLibrary からのイメージ読み込みボタン押下
- (IBAction) getImageByPhotoLibrary:(id)i_sender
{
    [self startCameraPickerFromViewController:self usingDelegate:self sourceType:UIImagePickerControllerSourceTypePhotoLibrary];
}

/// Camera からのイメージ読み込みボタン押下
- (IBAction) getImageByCamera:(id)i_sender
{
    [self startCameraPickerFromViewController:self usingDelegate:self sourceType:UIImagePickerControllerSourceTypeCamera];
}


/// 解放処理
- (void)dealloc
{
	[super dealloc];
}

/// CameraPicker の開始を行う
- (BOOL) startCameraPickerFromViewController:(UIViewController*)i_controller
                               usingDelegate:(id<UIImagePickerControllerDelegate, UINavigationControllerDelegate>)i_delegate
                                  sourceType:(UIImagePickerControllerSourceType)i_type
{

    if( ![UIImagePickerController isSourceTypeAvailable:i_type]
        || (i_delegate == nil) 
        || (i_controller == nil ) ){
        return NO;
    }

    UIImagePickerController* a_picker = [[UIImagePickerController alloc] init];
    a_picker.sourceType = i_type;
    a_picker.delegate = i_delegate;
    a_picker.allowsImageEditing = YES;

    // ピッカーは非同期に表示される
    [i_controller presentModalViewController:a_picker animated:YES];

    return YES;
}

/// 画像が選択されたときに呼ばれるデリゲート関数
- (void) imagePickerController:(UIImagePickerController*)i_picker
         didFinishPickingImage:(UIImage*)i_image
                   editingInfo:(NSDictionary*)i_editing_info
{
    [self useImage:i_image];
    [[i_picker parentViewController] dismissModalViewControllerAnimated:YES];
    [i_picker release];
}

/// 画像の選択がキャンセルされたときに呼ばれるデリゲート関数
- (void) imagePickerControllerDidCancel:(UIImagePickerController*)i_picker
{
    [[i_picker parentViewController] dismissModalViewControllerAnimated:YES];
    [i_picker release];
}

- (void) navigationController:(UINavigationController*)i_navigation_controller
        didShowViewController:(UIViewController*)i_view_controller
                     animated:(BOOL)i_animated
{
}

- (void)useImage:(UIImage*)i_image
{
    m_image_view.image = i_image;
}

@end
||

この、 CameraViewController をどうやって利用するかってのに、少し悩んだ.
(後述)

View に貼り付けたボタンに対応して、 UIImagePickerController を作成するので、 getImageBy* は IBAction 指定にして、ボタンと接続を行っておく.
また、View に貼り付けた、UIImageView に対して、 UIImage をセットするので、IBOutlet 指定にして、 IImaageView と接続を行っておく.

** CameraViewController の要点?

>|objcpp|
@interface CameraViewController
    : UIViewController <UIImagePickerControllerDelegate, UINavigationControllerDelegate>

UIImagePickerController には、UIImagePickerControllerDelegate, UINavigationControllerDelegate を
設定する必要がある.

通常は、Controller が Delegate プロトコルを実装するらしいが、他のクラスが実装を行っても良い(らしい)

    if( ![UIImagePickerController isSourceTypeAvailable:i_type]
        || (i_delegate == nil) 
        || (i_controller == nil ) ){
        return NO;
    }

上記部分で、カメラ(フォトライブラリ)が利用できるか判断を行っている.


    // ピッカーは非同期に表示される
    [i_controller presentModalViewController:a_picker animated:YES];

上記部分で、モーダルView としてピッカーを登録している.
モードレスView としても利用できるらしいが、利用方法がよく分からなかった.


InterfaceBuilder での設定

(忘れがちなので、一応書き残しておく)

  • View の xib ファイルを作成するときに、 Fields Owner には、CameraViewController を設定しておくこと.
  • 今回は UIView 派生クラスは利用しないので、View 自体は、UIView に設定しておけばよい.

ImagePickerSampleAppDelegate

アプリケーション起動時には、作成した CameraViewController を UIViewController の代わりに利用する.

このあたりは、解説済みだから要点だけ載せておく.

- (void)applicationDidFinishLaunching:(UIApplication *)application
{
    CameraViewController* a_view_controller = [[CameraViewController alloc] initWithNibName:@"ImageView" bundle:[NSBundle mainBundle]];
    self.viewController = a_view_controller;
    [a_view_controller release];

    UIView* a_controllers_view = [m_view_controller view];
    [m_window addSubview:a_controllers_view];

    [m_window makeKeyAndVisible];
}

まとめとか、わからなかったこと

  • 理解できれば、 「iPhone OS プログラミングガイド」に書いてある通りで、補足説明すらいらないのかも...
  • 状況に応じて ViewController を使い回したい(複数個の ViewController を利用したい)場合ってどうすればいいんだろう?
  • 今回は、 ViewController だけで処理がすんだけれども、実際の処理が他のクラスにまたがる場合、データはどのように管理するのが良いのだろう?


...結局、まだまだ、iPhone OS の文化になじめていないってことですね




次回予告

基礎編としては、たぶんこんなもんでしょう.

もう少し変なことをやってみたいので、もう少し写真利用についての調査をやってみようかとおもいます.