Windows PhoneでPhotoCameraクラスを使って静止画撮影をおこなう

By | 2013/04/22
Pocket

Windows Phone OS 7.1から対応されたPhotoCameraクラスを利用し、アプリケーションからカメラ機能を使用する準備と実際にプレビューをおこなうまでについては、「PhotoCameraクラスを使うための前準備」「カメラプレビューを行う」をご覧ください。

本記事内では、PhotoCameraクラスを使った静止画撮影してみましょう。

## 静止画撮影を行うトリガーを用意する

静止画撮影を行うトリガーとしてApplicationBarに下図のように撮影用のメニューアイテムを追加しました。

MainPage.xaml のApplicationBar.MenuItemsにApplicationBarMenuItemを追加しています。追加したメニューアイテムには、静止画撮影のトリガーとなるClickイベントのハンドラを設定しています。

    <!-- アプリケーションバー -->
    <phone:PhoneApplicationPage.ApplicationBar>
        <shell:ApplicationBar IsVisible="True" 
            IsMenuEnabled="True" Mode="Minimized">

            <shell:ApplicationBar.MenuItems>
                <shell:ApplicationBarMenuItem 
                    x:Name="menuItemTakePicture"
                    Text="Take Picture" 
                    Click="menuItemTakePicture_Click" />
            </shell:ApplicationBar.MenuItems>

        </shell:ApplicationBar>
    </phone:PhoneApplicationPage.ApplicationBar>

ここでトリガーとして用意したmenuItemTakePicture_Clickメソッドがコールされた時、静止画撮影を行うように実装してみましょう。

## 静止画撮影の解像度の設定

Windows Phone OSを搭載する端末にはハードウェア要件として、5Mピクセル以上のカメラ対応が含まれています。

私の持っているHTC Mozartは最大8Mピクセルまでしか撮影出来ませんが、IS12Tは13Mピクセルまで撮影する事が可能です。機種によって搭載されているカメラセンサーは異なり、当然撮影可能な解像度も違ってきます。

実行中のWindows Phone端末で撮影可能な解像度を得るためには、PhotoCamera.AvailableResolutionsプロパティからSizeの配列を取得します。

    // 静止画撮影可能な解像度を取得する
    var sizes = camera.AvailableResolutions;
    // 撮影可能な解像度のうち一番大きなものを設定
    camera.Resolution = sizes.Last();

Windows Phone エミュレータでの撮影可能な解像度を取得したところです。取得できた解像度は、640x360、640×480(VGA)、2592×1944(5M)、3264×2448(8M)の4つ。通常Windows Phoneの標準カメラアプリでは存在しない撮影サイズが含まれている事に注目してください。

デバッグ実行中のスクリーンショットを取りました。下図の通り解像度が取得出来ているのが確認出来ます。

## 静止画撮影を行う

本題の静止画撮影を開始する前に、フラッシュモードと撮影解像度の設定を行いましょう。可能性としては無視出来ると思いますが、将来端末間で実装に差が出た場合を考え、撮影前に明確に任意の値を設定するようにしておきましょう。

アプリケーションバーのメニューの「take picture」がタップされると、撮影シーケンス中に発行されるイベントハンドラの設定を行い、PhotoCamera.CaptureImageメソッドにて静止画撮影のシーケンスを開始します。

private void menuItemTakePicture_Click(object sender, EventArgs e) {

    // フラッシュモードの設定を行う
    // カメラが赤目補正モードに対応しているか判定する
    if (camera.IsFlashModeSupported(FlashMode.RedEyeReduction)) {
        camera.FlashMode = FlashMode.RedEyeReduction;
    }

    // 静止画撮影可能な解像度を取得する
    var sizes = camera.AvailableResolutions;
    // 撮影可能な解像度のうち一番大きなものを設定
    camera.Resolution = sizes.Last();

    // 撮影シーケンス時に発行されるイベントにハンドラを設定
    camera.CaptureStarted += new EventHandler(camera_CaptureStarted);
    camera.CaptureImageAvailable += new EventHandler<ContentReadyEventArgs>(camera_CaptureImageAvailable);
    camera.CaptureThumbnailAvailable += new EventHandler<ContentReadyEventArgs>(camera_CaptureThumbnailAvailable);
    camera.CaptureCompleted += new EventHandler<CameraOperationCompletedEventArgs>(camera_CaptureCompleted);
    
    // 静止画撮影の開始要求
    camera.CaptureImage();
}

静止画撮影の要求を投げると、まずCaptureStartedイベントが発行されます。連続撮影しないのであればこの時点でプレビューを止めてしまって良いかもしれません。

// 静止画撮影の開始
void camera_CaptureStarted(object sender, EventArgs e) {
    Debug.WriteLine("camera_CaptureStarted");
}

撮影した画像は最終的にJPEGデータにエンコードされます。PhotoCamera.Resolutionプロパティに指定した大きな解像度の画像のエンコードが完了すると、CaptureImageAvailableイベントが通知されます。

撮影とエンコードが正しく出来ているかを調べるため、エンコード済みの静止画画像のストリームが引数のContentReadyEventArgs.ImageStreamプロパティから取得できますので、これを分離ストレージへ保存します。

// カメラからの静止画取り込み終了し画像が使用可能になった
void camera_CaptureImageAvailable(object sender, ContentReadyEventArgs e) {
    Debug.WriteLine("camera_CaptureImageAvailable");

    try {
        // 分離ストレージへキャプチャーデータへ保存する
        using (var store = IsolatedStorageFile.GetUserStoreForApplication())
        using (var strm = store.CreateFile("capture_image.jpg")) {
            var bytes = new byte[256 * 1024];
            while (true) {
                int read = e.ImageStream.Read(bytes, 0, bytes.Length);
                if (read <= 0) break;
                strm.Write(bytes, 0, read);
            }
        }
    } catch (Exception ex) {
        // ここでエラー処理
    } finally {
        e.ImageStream.Close();
    }
}

サムネイル画像のJPEGエンコードが完了するとCaptureThumbnailAvailableイベントが通知されます。エンコードの完成した方が先に通知されます。

サムネイル画像もCaptureImageAvailableイベントの処理と同様に分離ストレージへ保存してしまいましょう。

// カメラからの静止画取り込み終了しサムネイル画像が使用可能になった
void camera_CaptureThumbnailAvailable(object sender, ContentReadyEventArgs e) {
    Debug.WriteLine("camera_CaptureThumbnailAvailable");

    try {
        // 分離ストレージへサムネイルデータへ保存する
        using (var store = IsolatedStorageFile.GetUserStoreForApplication())
        using (var strm = store.CreateFile("thumbnail.jpg")) {
            var bytes = new byte[256 * 1024];
            while (true) {
                int read = e.ImageStream.Read(bytes, 0, bytes.Length);
                if (read <= 0) break;
                strm.Write(bytes, 0, read);
            }
        }
    } catch (Exception ex) {
        // ここでエラー処理
    } finally {
        e.ImageStream.Close();
    }
}

最後にCaptureCompletedイベントが通知されて、静止画撮影シーケンスは完了です。引数のCameraOperationCompletedEventArgsのSucceededプロパティを参照することで、静止画撮影が成功したのか失敗したのかを判定する事が出来ます。

// 静止画撮影の完了
void camera_CaptureCompleted(object sender, CameraOperationCompletedEventArgs e) {
    Debug.WriteLine("camera_CaptureCompleted");

    if (e.Succeeded) {
        // 静止画撮影が成功した時の処理
    } else {
        // 静止画撮影が失敗した時の処理 
    }
}

以上、静止画撮影の開始までの設定と静止画撮影シーケンス中に発生するイベントについて説明させて頂きました。

撮影した画像がきちんと撮れているかを確認するために分離ストレージに保存されたデータを確認してみましょう。Isolated Storage Explorer Toolを使って、分離ストレージに保存したJPEGデータをPCへ転送してください。

Isolated Storage Explorer Toolの使い方については、こちらをご覧ください。

## 参考

* [PhotoCamera.CaptureImage メソッド](http://msdn.microsoft.com/en-us/library/microsoft.devices.photocamera.captureimage%28v=VS.92%29.aspx)