2011年11月17日木曜日

iPhoneのカメラの起動・保存

カメラの起動と撮影した写真の保存についてメモ。
カメラを使ったアプリを作る場合は、実機でのデバッグ環境が必要となります。

(1)Xcodeでプロジェクトを作成

今回はカメラを起動して保存するだけなのでテンプレートは「Single View Applications」で作っていきます。
Templates
Singie View Applications
Device Family
対応させるデバイス(iPad Or iPhone Or 両方)
デバイスの下にある3つのチェックボックスはすべてチェックを外す
(一部iOS5.0が必須になってしまいます)
(2)画面の作成

画面にはカメラを起動するボタンと保存するボタン、撮影した写真を表示するエリアを設けます。
上記の画面のようにアプリ画面の上に「NavigationBar」、下に「ImageView」を貼付けます。
次に「Assistant Editor」を開き関連付けを行います。
NavigationItemNavigationBar
Connection:Outlet
Name:aNavBar
ImageView
Connection:Outlet
Name:aImageView
次に配置したNavigationBarの左にカメラ起動ボタン、右に保存ボタンを配置します。
今回はこれをプログラムで追加します。
「ViewController.m」を開き、「ViewDidLoad」メソッドに以下を記述します。
- (void)viewDidLoad
{
    [super viewDidLoad];
 // Do any additional setup after loading the view, typically from a nib.
    
    // 以下を追加
    // カメラボタン追加
    UIBarButtonItem *cameraButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemCamera target:self action:@selector(doCamera:)];
    aNavBar.leftBarButtonItem = cameraButton;
    [cameraButton release];
    
    // 保存ボタン追加
    UIBarButtonItem *saveButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemSave target:self action:@selector(doSave:)];
    aNavBar.rightBarButtonItem = saveButton;
    [saveButton release];
}

これはNavigationBarに対してOSがもつカメラボタンおよび保存ボタンを追加しています。
「ViewController.xib」にはなにも表示されませんが実行してみるとボタンが追加されているはずです。
ただしこの状態ではビルドエラーになってします。
なぜならカメラボタン、保存ボタンを押したときの処理メソッドがまだ存在しないためです。

とりあえずここでは以下のメソッドを追加します。
- (IBAction)doCamera:(id)sender {
    NSLog(@"カメラ");
}

- (IBAction)doSave:(id)sender {
    NSLog(@"保存");
}

追加して実行すると以下の画面が表示されます。
画面はこんなかんじ完成。

(3)カメラの起動

カメラを使用するにはSDKに用意されてある「UIImagePickerController」クラスを使います。「ViewController.h」を開き、ヘッダにカメラ使用の宣言を記述します。
(このあたりの詳細はそのうち。。。)
@interface ViewController : UIViewController
// 以下を追加
<
    UINavigationControllerDelegate,
    UIImagePickerControllerDelegate
>

宣言はこれだけ。
次にカメラの起動とその処理ついて「ViewController.m」を修正していきます。
- (void)navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated {
}
- (void)navigationController:(UINavigationController *)navigationController didShowViewController:(UIViewController *)viewController animated:(BOOL)animated {
}
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info {
    NSLog(@"撮影");
    
    if ([picker respondsToSelector:@selector(presentingViewController)]) {
        [[picker presentingViewController] dismissModalViewControllerAnimated:YES];
    } else {
        [[picker parentViewController] dismissModalViewControllerAnimated:YES];
    }
}
- (void)imagePickerControllerDidCancel:(UIImagePickerController *)picker {
    NSLog(@"キャンセル");
    
    if ([picker respondsToSelector:@selector(presentingViewController)]) {
        [[picker presentingViewController] dismissModalViewControllerAnimated:YES];
    } else {
        [[picker parentViewController] dismissModalViewControllerAnimated:YES];
    }
}

ちょっとごちゃごちゃとしてますがカメラ起動したときの処理ついて上記を記述します。
この内容はほぼ決まりごとと思って書いていきます。

次にカメラの起動
- (IBAction)doCamera:(id)sender {
    NSLog(@"カメラ");
    
    // 以下を追加
    UIImagePickerControllerSourceType sourceType = UIImagePickerControllerSourceTypeCamera;
    
    if ( ! [UIImagePickerController isSourceTypeAvailable:sourceType]) {
        // カメラ起動エラー
        UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"エラー" message:@"カメラを起動できません" delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil];
        [alert show];
        [alert release];
        return;
    }
    
    UIImagePickerController *ipc = [[UIImagePickerController alloc] init];
    [ipc setSourceType:sourceType];
    [ipc setDelegate:self];
    [self presentModalViewController:ipc animated:YES];
    [ipc release];
}

(2)で追加した「doCamera」メソッドに上記を追記します。
最初の「UIImagePickerControllerSourceType」では起動をカメラに指定しています。
カメラに以外にフォトライブラリやカメラロールの起動を指定することができます。

下の条件文ではカメラが起動できるデバイスかどうかを判断しています。
シミュレータでこのアプリを実行するとカメラを起動できませんのアラートが表示されます。

最後の部分は起動の設定になります。
起動方法をカメラに指定したり写真撮影後にトリミングをしたりムービーの切替など指定します。

これでカメラを起動して撮影することができます。
実機をつなげてデバッグしてみてください。

(4)撮影した写真を画面に表示

(3)でカメラを起動して撮影することはできましたが撮影しただけではどこにもその写真は残りません。
今回はまずアプリ上に写真を表示します。
撮影後、呼び出されるメソッドは「imagePickerController:didFinishPickerMediaWithInfo」です。
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info {
    NSLog(@"撮影");
    
    // ここ
    UIImage *aImage = [info objectForKey:UIImagePickerControllerOriginalImage];
    [aImageView setImage:aImage];
    
    if ([picker respondsToSelector:@selector(presentingViewController)]) {
        [[picker presentingViewController] dismissModalViewControllerAnimated:YES];
    } else {
        [[picker parentViewController] dismissModalViewControllerAnimated:YES];
    }
}

撮影した情報を取得するのは「[info objectForKey:UIImagePickerControllerOriginalImage]」の部分。
トリミングを有効にしている場合だと「[info objectForKey:UIImagePickerControllerEditedImage]」となります。
あとは取得した写真をImageViewにセットしているだけです。

これで実行すると撮影後、撮影した写真が画面に表示されます。

(5)写真を保存

保存処理は(2)で追加した「doSave」メソッドに追加していきます。
- (void)image:(UIImage *)image didFinishSavingWithError:(NSError *)error contextInfo:(void *)contextInfo {
    NSLog(@"保存終了");
    
    UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"保存終了" message:@"アルバムに写真を追加しました" delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil];
    [alert show];
    [alert release];
}

- (IBAction)doSave:(id)sender {
    NSLog(@"保存");
    
    UIImage *aImage = [aImageView image];
    
    if (aImage == nil) {
        // カメラ未撮影
        UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"エラー" message:@"写真を撮影してください" delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil];
        [alert show];
        [alert release];
        return;
    }
    
    UIImageWriteToSavedPhotosAlbum(aImage, self, @selector(image:didFinishSavingWithError:contextInfo:),nil);
}

doSaveメソッド内では(4)でセットしたImageViewから情報を取得します。
取得後、「UIImageWriteToSavedPhotosAlbum」を呼び出し写真を保存します。
保存が完了したらメッセージを表示しますが、それが「image:didFinishSavingWithError:contextInfo」メソッドになります。

これで今回のアプリは完成。実機にてデバッグするとカメラ起動→撮影→表示→保存の流れができあがると思います。
保存した写真はカメラロール内に保存されます。


6 件のコメント:

  1. こちらのブログを参考にアプリ学習をしているのですが、「leftBarButtonItem not found」というエラーがでてしまうのですが、解決策があれば伝授していただけますか?

    返信削除
  2. ありがとうございます。
    (2)の部分を作ってる段階でエラーがでているのでしょうか?

    返信削除
  3. そうです、(2)のleftBarButtonItem とrightBarButtonItemのふたつが見当たらないらしいです。ちなみに僕もxcode4.2なので環境は一緒です

    返信削除
  4. なんでしょうか。。。
    NavigationBarが正しく配置されていれば問題なく動作すると思うのですが。。。

    返信削除
  5. https://lh5.googleusercontent.com/-pWs-VqbXFk8/TuvmTbKIi4I/AAAAAAAAABc/pA_YLJSyLgA/s720/%25E3%2582%25B9%25E3%2582%25AF%25E3%2583%25AA%25E3%2583%25BC%25E3%2583%25B3%25E3%2582%25B7%25E3%2583%25A7%25E3%2583%2583%25E3%2583%2588%2B0023-12-17%2B9.35.07.png

    スクリーンショットしてみたんで、よければ検品してもらえませんか?

    返信削除
  6. スクリーンショットありがとうございます。
    私のほうでも確認できました。
    載せていた記事にあやまりがあったので修正しています。
    Assistant Editorで関連付けを行う際に、NavigatoinBarに対して関連付けをするようにしてましたが実際にはNavigationItemに対して関連付けを行う必要があるようです。
    NavigatoinItemはNavigationBarの子要素になってます。
    ちょっとわかりにくいかもしれませんが試してみてください

    返信削除