● Carbon視点でiPhone探求(2009/06/06)

  このニュースは、MOSAの会員にのみ配布されているデベロッパー向けの
  デジタルマガジンMOSADeNのに掲載された記事です。ほぼ一ヶ月遅れで
  ここに掲載されて行きます

 〜 UIImagePickerControllerで画像取り込み 〜


iPhone OS 3.0では画像をコピー&ペーストで別アプリケーションから持ってくることが可能になりました。しかしiPhone OS 2.2では、まだそうした操作はできません。主な画像の入手方法は、iPhoneの「写真ライブラリ」から得るか、アプリケーションから直接「写真撮影」するかのどちらかです。

ちなみに、そうした方法以外にも、ウェブサイト上に登録されている画像を持ってきたり、MacやWindowsマシンに保存されている画像ファイルをネットワーク経由で転送したりすることも可能です。機会があれば、こうした別の方法にもチャレンジしたいと思います。また、写真ライブラリにはiTunes経由で転送された画像も含まれますが、これらの画像は、iPhoneでの表示に最適化するために、オリジナルサイズから縮小されている場合があります。また自作アプリケーションからの写真撮影では、Core Locationを利用した位置情報が画像ファイルに添付されないという制限がありますので御注意ください。

「写真ライブラリ」からの画像の取り込みや「写真撮影」を利用するためには、UIKitに属するUIImagePickerControllerクラスを利用します。このクラスを使う場合に注意しなければいけない点は、iPod touchには「カメラ」が搭載されていないという事です。この事実を無視して、iPod touchでもカメラ撮影用の機能が使える状態になっていると(撮影ボタンなどがあると)App Storeへの登録申請において認可が下りない(リジェクトされる)ことになります。くれぐれも注意してください。以下は、ユーザが「画像取り込み」ボタンを押した時のターゲット&アクションの一例です。

- (IBAction)getImage:(id)sender
{
  NSString    *b1,*b2,*b3;
  NSString    *esc,*title;
  UIActionSheet *action;

  if( [UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera]==YES )
                      // カメラ機能が使えるかどうか?
  {
    esc=NSLocalizedString( @"ESC_BUTN",@"" );  // キャンセル
    title=NSLocalizedString( @"ACT_TYPE_01",@""); // タイトル
    b1=NSLocalizedString( @"ACT_TYPE_02",@"" ); // 写真アルバム
    b2=NSLocalizedString( @"ACT_TYPE_03",@"" ); // カメラロール
    b3=NSLocalizedString( @"ACT_TYPE_04",@"" ); // 写真撮影
    if( action=[[UIActionSheet alloc] initWithTitle:title delegate:self cancelButtonTitle:esc destructiveButtonTitle:nil otherButtonTitles:b1,b2,b3,nil] )
    {
      action.actionSheetStyle=UIBarStyleBlackTranslucent; // スタイル設定
      [action showInView:self.view]; // 方法選択のアクションシートを開く
      [action release];
    }
  }
  else
    [self actionSheet:nil clickedButtonAtIndex:0]; // 写真アルバムを開く
}

現在のデバイスでカメラが利用できるかどうかは、 UIImagePickerControllerのクラスメソッドであるisSourceTypeAvailable:で確認できます。もしカメラが使えるならば、先んじてアクションシート(UIActionSheet)を表示させ、「写真アルバム」「カメラロール」「写真撮影」の3つの方法のどれを利用するかユーザに選択させます。カメラが使用できなければ、アクションシートを表示させずに、強制的に「写真アルバム」から画像を読み込む処理を実行させます。この場合は、アクションシート上の最初のボタン(番号はゼロ)を押した処理と同等となります。

アクションシートに表示するボタンのタイトルですが、直接ソースコード内に日本語で書き込んでも問題はありません。しかし、後々の英語ローカライズを考慮して「ja.lproj」(日本語リソース)フォルダ内に、Localizable.stringsファイルを用意し、アプリケーション内で使用する文字列をキーで参照できるよう定義しておきます。こうした文字列は NSLocalizedString()ルーチンにキーを渡して読み込むことが可能です。iPhoneの言語設定を変更すると読み込まれるLocalizable.stringsファイルが切り替わり、その言語設定に対応した文字列が表示される仕組みです(無ければデフォルトが使われる)。

ESC_BUTN="キャンセル";
ACT_TYPE_01="画像の取り込みを行えます。";
ACT_TYPE_02="写真アルバム";
ACT_TYPE_03="カメラロール";
ACT_TYPE_04="写真撮影";

さて、アクションシートが表示され、ユーザにより表示されているボタンのどれかが押されると、UIActionSheetのデリゲートが呼ばれ、そこで適切な処理へと分岐させる処理を実行させます。こうしたデリゲートのいくつかは、各クラスでプロトコルとして定義されています。今回の処理で関係するのは以下の3つのプロトコルです。

@protocol UIActionSheetDelegate <NSObject>
@protocol UIImagePickerControllerDelegate <NSObject>
@protocol UINavigationControllerDelegate <NSObject>

よってそれらを利用する場合には、そのクラス定義(ヘッダファイル)において、各プロトコルに準拠していることを明記しておく必要があります。この「プロトコルへの準拠」の記載がなされていないと、Make時にXcodeがアラート(警告)を表示します。以下の様に、今回のRootViewControllerクラスは3つのプロトコルに準拠していることを明記しておきます。

@interface RootViewController : UITableViewController
                < UINavigationControllerDelegate,
                 UIActionSheetDelegate,
                 UIImagePickerControllerDelegate >

アクションシートでボタンが押されると、そのデリゲートメソッドであるactionSheet: clickedButtonAtIndex:が呼ばれます。ボタン番号はbuttonIndexから得られますので、その値を確認し、キャンセルボタン以外であればUIImagePickerController(画像ピッカー)を作成して、その後の処理は全部それ(iPhone OS側)に任せてしまいます。

- (void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex
{
  UIImagePickerController  *picker;
  NSUInteger        type;

  if( buttonIndex!=3 ) // キャンセルボタンではない
  {
    if( buttonIndex==0 ) // 写真アルバムから画像を読み込む
      type=UIImagePickerControllerSourceTypePhotoLibrary;
    else if( buttonIndex==1 ) // カメラロールから像を読み込む
      type=UIImagePickerControllerSourceTypeSavedPhotosAlbum;
    else if( buttonIndex==2 ) // 写真撮影を行う
      type=UIImagePickerControllerSourceTypeCamera;

    if( picker=[[UIImagePickerController alloc] init] )
    {
      picker.allowsImageEditing=YES; // 画像編集(トリミング)を許す
      picker.sourceType=type; // 画像ピッカーのタイプを設定
      picker.delegate=self;  // デリゲートはこのオブジェクト
      [self presentModalViewController:picker animated:YES];
                    // 画像ピッカーをオープンする
      [picker release];
    }
  }
}

タイプ設定のための定数の名称ですが、日本語環境でのUIImagePickerController(画像ピッカー)のタイトル表示と何故だか一致していないので注意してください(仕様変更して欲しい)。UIImagePickerControllerSourceTypePhotoLibraryでは「写真アルバム」というタイトルが表示され、UIImagePickerControllerSourceTypeSavedPhotosAlbumの方では「カメラロール」というタイトルが表示されます。

画像ピッカーで画像を得るための処理が正しく終了すると、以下のデリゲートメソッドが呼ばれます。引数で渡されるimage(UIImage *)が対象となる画像です。そのデータをファイルへ保存し、そのパス名をモデルオブジェクトへ登録する処理をここに記載すればOKとなります。これらの処理については、また別の機会に解説したいと思います。

- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingImage:(UIImage *)image editingInfo:(NSDictionary *)editingInfo
{
  // ここにモデルオブジェクトへの登録と画像ファイルの保存処理を記述する

  [self dismissModalViewControllerAnimated:YES]; // 画像ピッカーを閉じる
}

画像ピッカーでキャンセルボタンが押された場合には、以下のデリゲートメソッドが呼ばれます。この時には何もせずに画像ピッカー(UIImagePickerController )を閉じます。

- (void)imagePickerControllerDidCancel:(UIImagePickerController *)picker;
{
  [self dismissModalViewControllerAnimated:YES]; // 画像ピッカーを閉じる
}

取り込んだ画像をファイルへ保存し、そのパス名をモデルオブジェクトへ登録する準備が整いました。次回からは、UIViewController(多分UITableViewController)上に配置したUITableViewにそうした画像を一覧表示させる処理へと話を進めたいと思います。

copyright 2009 Ottimo, Inc. All rights reserved
無断転載・引用禁止