方法: Windows Phone 用の基本的なカメラ アプリケーションを作成する

2012/02/09

Windows Phone OS 7.1 を使用して、プログラムによってデバイス カメラにアクセスできます。このトピックは、カメラ API を使用して写真の撮影を行うカメラ アプリケーションの作成方法を説明するシリーズの最初のトピックです。このトピックでは、カメラのファインダーを表示し、プログラムでシャッターを切り、撮影した画像をメディア ライブラリおよび分離ストレージに保存する方法について説明します。

このトピックでは、次の手順について説明します。

  1. カメラ UI の作成

  2. Viewfinder とカメラベースのイベント

  3. メディア ライブラリと分離ストレージへの保存

ヒントヒント:

このトピックは、基本的なカメラのサンプルに対応しています。完全なプロジェクトをダウンロードするには、「Windows Phone のコード サンプル」を参照してください。

この基本的なカメラ アプリケーションが完成した後は、以下のトピックで、フラッシュとフォーカスの実装、撮影解像度の変更、携帯電話のハードウェア シャッター ボタンの使用などの機能について説明します。まず最初に、こトピックで基本的なカメラ アプリケーションを完成させる必要があります。以下のトピックでは、このアプリケーションを基にして、このトピックで実装した機能に新しい機能を追加します。

これらのトピックをすべて完了した後の最終的なソリューションは、次の図に示すような表示になります。

AP_Con_CameraAnatomy

このトピックでは、[SH] ボタンだけをアプリケーションに追加します。フラッシュ、オートフォーカス、解像度の各ボタンは、シリーズの他のトピックで追加します。

注注:

Windows Phone OS 7.1 の機能を使用するために、Windows Phone OS 7.0 アプリケーションをアップグレードした場合、カメラ機能 ID_CAP_ISV_CAMERA はアプリケーション マニフェスト ファイル WMAppManifest.xml に自動的に追加されません。ID_CAP_ISV_CAMERA がないと、カメラ API を使用したアプリケーションは機能しません。新しい Windows Phone OS 7.1 プロジェクトで、この機能はアプリケーション マニフェスト ファイルに含まれます。

このリリースの Windows Phone SDK では、このトピックの手順を実際に行うことができるのは Windows Phone デバイスだけであり、Windows Phone Emulator では行うことができません。

このトピックは、C# 開発を基にしていますが、Visual Basic のコードも提供しています。

ここでは、撮影されるフレームを表示するファインダー領域と画像を撮影するシャッター ボタンで構成される、カメラの UI を作成します。

カメラの UI を作成するには

  1. Visual Studio 2010 Express for Windows Phone で、[ファイル] メニューの [新しいプロジェクト] をクリックして新しいプロジェクトを作成します。

  2. [新しいプロジェクト] ウィンドウが表示されます。Visual C# のテンプレートを展開してから、Silverlight for Windows Phone のテンプレートを選択します。

  3. Windows Phone アプリケーション テンプレートを選択します。[名前] ボックスに選択した名前を入力します。

  4. [OK] をクリックします。[新しい Windows Phone アプリケーション] ウィンドウが表示されます。

  5. [ターゲットの Windows Phone のバージョン] メニューで、Windows Phone 7.1 が選択されていることを確認します。

  6. [OK] をクリックします。新しいプロジェクトが作成され、Visual Studio のデザイナー ウィンドウに MainPage.xaml が表示されます。

  7. [プロジェクト] メニューの [参照の追加] をクリックします。[.NET] タブで [Microsoft.XNA.Framework] を選択し、[OK] をクリックします。

  8. MainPage.xaml で、次のコードに示されているように phone:PhoneApplicationPage 要素を更新します。

        SupportedOrientations="Landscape" Orientation="LandscapeLeft"
        shell:SystemTray.IsVisible="False"
    
    

    これによって、ページが横向きに構成され、システム トレイが非表示になります。

  9. MainPage.xaml で、次のコードを使用して LayoutRoot という名前の Grid を置き換えます。

        <!--LayoutRoot is the root grid where all page content is placed-->
        <Grid x:Name="LayoutRoot" Background="Transparent">
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="640" />
                <ColumnDefinition Width="160" />
            </Grid.ColumnDefinitions>
            
            <Canvas x:Name="viewfinderCanvas" Width="640" Height="480" 
                       HorizontalAlignment="Left" >
                
                <!--Camera viewfinder -->
                <Canvas.Background>
                    <VideoBrush x:Name="viewfinderBrush" />
                </Canvas.Background>
             </Canvas>
            
            <!--Button StackPanel to the right of viewfinder>-->
            <StackPanel Grid.Column="1" >
                <Button x:Name="ShutterButton" Content="SH" Click="ShutterButton_Click" FontSize="26" FontWeight="ExtraBold" Height="75" />
            </StackPanel>
    
            <!--Used for debugging >-->
            <TextBlock Height="40" HorizontalAlignment="Left" Margin="8,428,0,0" Name="txtDebug" VerticalAlignment="Top" Width="626" FontSize="24" FontWeight="ExtraBold" />
        </Grid>
    
    

    このコードでは、シャッター ボタン SH を含む StackPanel コントロールで、640 x 480 のファインダー領域を作成します。以降のセクションでは、ShutterButton_Click イベントを実装します。

    注注:

    この演習のソフトウェア シャッター ボタンは、PhotoCamera API へのプログラムでのアクセスの実例を示すためにのみ使用します。エンド ユーザーに対するエクスペリエンスを最適にするには、カメラのハードウェア シャッター ボタンを使用することをお勧めします。ハードウェア シャッター ボタンの実装方法の詳細については、「方法: Windows Phone でハードウェア カメラのシャッター ボタンにアクセスする」を参照してください。

  10. メイン ページの分離コード ファイル MainPage.xaml.cs を開き、ページの先頭に次のディレクティブを追加します。

    // Directives
    using Microsoft.Devices;
    using System.IO;
    using System.IO.IsolatedStorage;
    using Microsoft.Xna.Framework.Media;
    
    
  11. MainPage.xaml.csMainPage クラスで、MainPage クラス コンストラクターの上に次の変数宣言を追加します。

        // Variables
        private int savedCounter = 0;
        PhotoCamera cam;
        MediaLibrary library = new MediaLibrary();
    
    
  12. カメラ アプリケーションを作成するには、アプリケーション マニフェスト ファイルでカメラ機能を宣言する必要があります。これがないと、アプリケーションは機能しません。WMAppManifest.xml を開き、次の機能要素が存在していることを確認します。

    <Capability Name="ID_CAP_ISV_CAMERA"/>
    
  13. (省略可能) 前向きのカメラが必要なアプリケーションの場合は、アプリケーション マニフェスト ファイルでさらに前向きカメラ機能を Capabilities 要素に追加します。

    <Capability Name="ID_HW_FRONTCAMERA"/>
    

    この機能は新しいプロジェクトには自動的に追加されないので、手動で追加する必要があります。前向きカメラを使用していないユーザーには、デバイスがアプリケーションの要件を満たしていないことが通知されますが、それでもアプリケーションをダウンロードできます。このアプリケーションはどちらかのカメラを使用するように設計されているので、この機能はこのアプリケーションに必須ではありません。詳細については、「Windows Phone のカメラと写真の概要」の「機能」セクションを参照してください。

ファインダーを実装するには、viewfinderBrush ソースを Windows Phone カメラに設定します。また、カメラの初期化、撮影完了、画像の使用可能性など、カメラ ベースの複数のイベントを実装します。

ファインダーおよびカメラ ベースのイベントを実装するには

  1. MainPage.xaml.cs で、次のコードを MainPage クラスに追加します。

    注注:

    この手順の以下の部分を完了するまで、Visual Studio によって、現在のコンテキストに存在しないメソッドに関するエラーが出力される可能性があります。これらのメソッドは、以下の手順で追加されます。

            //Code for initialization, capture completed, image availability events; also setting the source for the viewfinder.
            protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)
            {
    
                // Check to see if the camera is available on the device.
                if ((PhotoCamera.IsCameraTypeSupported(CameraType.Primary) == true) ||
                     (PhotoCamera.IsCameraTypeSupported(CameraType.FrontFacing) == true))
                {
                    // Initialize the camera, when available.
                    if (PhotoCamera.IsCameraTypeSupported(CameraType.FrontFacing))
                    {
                        // Use front-facing camera if available.
                        cam = new Microsoft.Devices.PhotoCamera(CameraType.FrontFacing);
                    }
                    else
                    {
                        // Otherwise, use standard camera on back of device.
                        cam = new Microsoft.Devices.PhotoCamera(CameraType.Primary);
                    }
    
                    // Event is fired when the PhotoCamera object has been initialized.
                    cam.Initialized += new EventHandler<Microsoft.Devices.CameraOperationCompletedEventArgs>(cam_Initialized);
    
                    // Event is fired when the capture sequence is complete.
                    cam.CaptureCompleted += new EventHandler<CameraOperationCompletedEventArgs>(cam_CaptureCompleted);
    
                    // Event is fired when the capture sequence is complete and an image is available.
                    cam.CaptureImageAvailable += new EventHandler<Microsoft.Devices.ContentReadyEventArgs>(cam_CaptureImageAvailable);
    
                    // Event is fired when the capture sequence is complete and a thumbnail image is available.
                    cam.CaptureThumbnailAvailable += new EventHandler<ContentReadyEventArgs>(cam_CaptureThumbnailAvailable);
    
                    //Set the VideoBrush source to the camera.
                    viewfinderBrush.SetSource(cam);
                }
                else
                {
                    // The camera is not supported on the device.
                    this.Dispatcher.BeginInvoke(delegate()
                    {
                        // Write message.
                        txtDebug.Text = "A Camera is not available on this device.";
                    });
    
                    // Disable UI.
                    ShutterButton.IsEnabled = false;
                }
            }
            protected override void OnNavigatingFrom(System.Windows.Navigation.NavigatingCancelEventArgs e)
            {
                if (cam != null)
                {
                    // Dispose camera to minimize power consumption and to expedite shutdown.
                    cam.Dispose();
    
                    // Release memory, ensure garbage collection.
                    cam.Initialized -= cam_Initialized;
                    cam.CaptureCompleted -= cam_CaptureCompleted;
                    cam.CaptureImageAvailable -= cam_CaptureImageAvailable;
                    cam.CaptureThumbnailAvailable -= cam_CaptureThumbnailAvailable;
                }
            }
    
    

    このコードでは、OnNavigatedTo(NavigationEventArgs) メソッドを使用して cam という名前の PhotoCamera オブジェクトを作成し、複数のイベントを構成します。また、このコードは、VideoBrush ソースをデバイスのカメラ オブジェクト cam に設定します。

    プライマリ カメラに加えてデバイスが前向きカメラを備えている場合、アプリケーションは前向きカメラを使用します。前向きカメラを備えていないデバイスもあるので、先に IsCameraTypeSupported(CameraType) メソッドを使用して前向きカメラを使用できるかどうかを確認してから、PhotoCamera オブジェクトを作成します。また、デバイスがどのような種類のカメラも備えていない場合もあります。その場合、UI は無効になり、メッセージが表示されます。

    Windows Phone 実行モデルに対応するため、PhotoCamera オブジェクトは OnNavigatedTo(NavigationEventArgs) メソッドで初期化された後、OnNavigatingFrom(NavigatingCancelEventArgs) メソッドの間に明示的に破棄されます。PhotoCamera イベントのイベント ハンドラーが OnNavigatedTo(NavigationEventArgs) で追加され、OnNavigatingFrom(NavigatingCancelEventArgs) において削除されて、メモリが解放されます。

    注注:

    カメラ プレビュー バッファーの個別フレームを分析および処理する方法については、「方法: Windows Phone 用カメラ アプリケーションでグレースケールを処理する」を参照してください。

  2. MainPage.xaml.cs で、次のコードを MainPage クラスに追加します。

        // Update the UI if initialization succeeds.
        void cam_Initialized(object sender, Microsoft.Devices.CameraOperationCompletedEventArgs e)
        {
            if (e.Succeeded)
            {
                this.Dispatcher.BeginInvoke(delegate()
                {
                    // Write message.
                    txtDebug.Text = "Camera initialized.";
                });
            }
        }
    
    

    このコードは、カメラの Initialized イベントを使用し、txtDebug という名前の TextBlock を更新します。アプリケーション UI は別のスレッドで実行されているので、状態を更新するには BeginInvoke メソッドが必要です。

  3. MainPage.xaml.cs で、次のコードを MainPage クラスに追加します。

            // Ensure that the viewfinder is upright in LandscapeRight.
            protected override void OnOrientationChanged(OrientationChangedEventArgs e)
            {
                if (cam != null)
                {
                    // LandscapeRight rotation when camera is on back of device.
                    int landscapeRightRotation = 180;
    
                    // Change LandscapeRight rotation for front-facing camera.
                    if (cam.CameraType == CameraType.FrontFacing) landscapeRightRotation = -180;
    
                    // Rotate video brush from camera.
                    if (e.Orientation == PageOrientation.LandscapeRight)
                    {
                        // Rotate for LandscapeRight orientation.
                        viewfinderBrush.RelativeTransform =
                            new CompositeTransform() { CenterX = 0.5, CenterY = 0.5, Rotation = landscapeRightRotation };
                    }
                    else
                    {
                        // Rotate for standard landscape orientation.
                        viewfinderBrush.RelativeTransform =
                            new CompositeTransform() { CenterX = 0.5, CenterY = 0.5, Rotation = 0 };
                    }
                }
    
                base.OnOrientationChanged(e);
            }
    
    

    このコードでは、カメラが上下逆 (LandscapeRight 方向) のときにファインダー viewfinderBrush が正しく上を向くようにします。カメラが前向きの場合は、カメラが裏側にある場合とは逆の向きに対応するブラシを回転する必要があります。

    注注:

    どちらの向きにビデオ ブラシを 180 度回転しても同じ結果になりますが、このコードではカメラの種類に基づいて UI の向きを決める例を示します。

  4. MainPage.xaml.cs で、次のコードを MainPage クラスに追加します。

            private void ShutterButton_Click(object sender, RoutedEventArgs e)
            {
                if (cam != null)
                {
                    try
                    {
                        // Start image capture.
                        cam.CaptureImage();
                    }
                    catch (Exception ex)
                    {
                        this.Dispatcher.BeginInvoke(delegate()
                        {
                            // Cannot capture an image until the previous capture has completed.
                            txtDebug.Text = ex.Message;
                        });
                    }
                }
            }
    
        void cam_CaptureCompleted(object sender, CameraOperationCompletedEventArgs e)
        {
            // Increments the savedCounter variable used for generating JPEG file names.
            savedCounter++;
        }
    
    

    このコードでは、シャッター ボタンと撮影完了のイベントを実装します。シャッター ボタンは、XAML コードで作成した、静止画像を撮影するためのソフトウェア ボタンです。このプロジェクトでは、CaptureCompleted イベントを使用して savedCounter 変数をインクリメントします。この変数は、次のセクションで JPEG の名前を設定するために使用します。

Windows Phone OS 7.1 を対象とするカメラ アプリケーションの場合、写真を撮影すると 2 つの画像がキャプチャされます。1 つはフル解像度の画像であり、もう 1 つはフル解像度の写真を表示するためにギャラリ ビューで使用されるサムネイル画像です。ここでは、フル解像度の画像をデバイスのメディア ライブラリに格納する方法を示します。また、フル解像度の画像とサムネイル画像を分離ストレージに保存する方法も示します。

画像をメディア ライブラリと分離ストレージに保存するには

  1. MainPage.xaml.cs で、次のコードを MainPage クラスに追加します。

        // Informs when full resolution picture has been taken, saves to local media library and isolated storage.
        void cam_CaptureImageAvailable(object sender, Microsoft.Devices.ContentReadyEventArgs e)
        {
            string fileName = savedCounter + ".jpg";
    
            try
            {   // Write message to the UI thread.
                Deployment.Current.Dispatcher.BeginInvoke(delegate()
                {
                    txtDebug.Text = "Captured image available, saving picture.";
                });
    
                // Save picture to the library camera roll.
                library.SavePictureToCameraRoll(fileName, e.ImageStream);
    
                // Write message to the UI thread.
                Deployment.Current.Dispatcher.BeginInvoke(delegate()
                {
                    txtDebug.Text = "Picture has been saved to camera roll.";
    
                });
    
                // Set the position of the stream back to start
                e.ImageStream.Seek(0, SeekOrigin.Begin);
    
                // Save picture as JPEG to isolated storage.
                using (IsolatedStorageFile isStore = IsolatedStorageFile.GetUserStoreForApplication())
                {
                    using (IsolatedStorageFileStream targetStream = isStore.OpenFile(fileName, FileMode.Create, FileAccess.Write))
                    {
                        // Initialize the buffer for 4KB disk pages.
                        byte[] readBuffer = new byte[4096];
                        int bytesRead = -1;
    
                        // Copy the image to isolated storage. 
                        while ((bytesRead = e.ImageStream.Read(readBuffer, 0, readBuffer.Length)) > 0)
                        {
                            targetStream.Write(readBuffer, 0, bytesRead);
                        }
                    }
                }
    
                // Write message to the UI thread.
                Deployment.Current.Dispatcher.BeginInvoke(delegate()
                {
                    txtDebug.Text = "Picture has been saved to isolated storage.";
    
                });
            }
            finally
            {
                // Close image stream
                e.ImageStream.Close();
            }
    
        }
    
        // Informs when thumbnail picture has been taken, saves to isolated storage
        // User will select this image in the pictures application to bring up the full-resolution picture. 
        public void cam_CaptureThumbnailAvailable(object sender, ContentReadyEventArgs e)
        {
            string fileName = savedCounter + "_th.jpg";
    
            try
            {
                // Write message to UI thread.
                Deployment.Current.Dispatcher.BeginInvoke(delegate()
                {
                    txtDebug.Text = "Captured image available, saving thumbnail.";
                });
    
                // Save thumbnail as JPEG to isolated storage.
                using (IsolatedStorageFile isStore = IsolatedStorageFile.GetUserStoreForApplication())
                {
                    using (IsolatedStorageFileStream targetStream = isStore.OpenFile(fileName, FileMode.Create, FileAccess.Write))
                    {
                        // Initialize the buffer for 4KB disk pages.
                        byte[] readBuffer = new byte[4096];
                        int bytesRead = -1;
    
                        // Copy the thumbnail to isolated storage. 
                        while ((bytesRead = e.ImageStream.Read(readBuffer, 0, readBuffer.Length)) > 0)
                        {
                            targetStream.Write(readBuffer, 0, bytesRead);
                        }
                    }
                }
    
                // Write message to UI thread.
                Deployment.Current.Dispatcher.BeginInvoke(delegate()
                {
                    txtDebug.Text = "Thumbnail has been saved to isolated storage.";
    
                });
            }
            finally
            {
            // Close image stream
            e.ImageStream.Close();
            }
        }
    
    

    このコードでは、CaptureImageAvailable イベントと CaptureThumbnailAvailable イベントを実装します。1 番目のメソッドは、フル解像度の画像をデバイスのメディア ライブラリと分離ストレージに保存します。2 番目のメソッドでは、サムネイル画像を分離ストレージ ファイルに保存する方法を示します。

    注注:

    写真を Pictures Hub の Saved Pictures アルバムに保存するには、SavePicture メソッドを使用します。この例で使用する SavePictureToCameraRoll メソッドは、画像を Camera Roll アルバムに保存します。

  2. デバイスで、[デバッグ] メニューの [デバッグ開始] をクリックしてアプリケーションを実行します。[SH] ボタンを押してアプリケーションをテストします。txtDebug TextBlock は、分離ストレージへの保存操作の状態を示します。アプリケーションを終了した後、アプリケーションで撮影した写真を、Pictures Hub の camera roll フォルダーで検索できます。

    この時点での UI の表示を次の例に示します。

    AP_Con_CameraWireFrame

    この例では、ソフトウェア シャッター ボタン [SH] は、UI の右上隅に表示されます。マンゴーの写真が、viewfinderCanvas という名前の Canvas コントロールに表示されます。

  3. 基本的なカメラ アプリケーションが完成したので、それを使用して以下のトピックの作業を行うことができます。

表示: