情報
要求されたトピックは次のとおりです。しかし、このトピックはこのライブラリには含まれていません。

Windows Phone 8 の基本カメラ アプリを作成する方法

2014/06/18

対象: Windows Phone 8 および Windows Phone Silverlight 8.1 | Windows Phone OS 7.1

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

Windows Phone 8 以降、アプリでは高度なキャプチャ シナリオ用に PhotoCaptureDevice クラスを使用するようになりました。PhotoCaptureDevice により、(電話にある場合) ISO、露出補正、手動フォーカス位置などの写真プロパティをアプリで制御できます。このトピックでは、PhotoCaptureDevice については説明していません。詳細については、「Windows Phone 8 の高度な写真キャプチャ」を参照してください。

メモメモ:

multiple devices 写真のキャプチャがアプリの主要機能ではない場合は、カメラ API を直接使用するのではなく、カメラ キャプチャ タスクを使用して写真をキャプチャすることを検討してください。カメラ キャプチャ タスクに割り当てられたメモリはアプリ メモリの合計使用量に含まれません。これにより、アプリによるメモリ使用を最小限に抑えることができます。これは、アプリが 低メモリ デバイス で実行されるときに特に重要です。詳細については、「低メモリの電話向けの Windows Phone 8 用のアプリ開発」と「Windows Phone 8 のカメラ キャプチャ タスクを使用する方法」を参照してください。

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

  1. カメラ UI の作成

  2. ファインダーとカメラベースのイベントの実装

  3. メディア ライブラリとローカル フォルダーへの保存

ヒントヒント:

このトピックは、基本的なカメラのサンプルに対応しています。

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

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

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 OS 7.1 エミュレーター (Emulator 7.5) では完了できません。電話または Windows Phone 8 エミュレーターを使用してこのアプリを開発します。

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

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

  1. Windows Phone SDK を開き、[Windows Phone アプリ] テンプレートを使用して新しいプロジェクトを作成します。

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

  3. MainPage.xaml で、次のコードに示すように phone:PhoneApplicationPage 要素を更新します。

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

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

  4. 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 8 のハードウェア カメラ シャッター ボタンにアクセスする方法」を参照してください。

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

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

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

    <Capability Name="ID_CAP_ISV_CAMERA"/>
    

    背面カメラを前提とする Windows Phone 8 アプリの場合、ID_REQ_BACKCAMERA ハードウェア要件を使用して、背面カメラのないハードウェアのユーザーがそのアプリをダウンロードできないようにします。機能の詳細については、「Windows Phone 8 のアプリ機能とハードウェア要件」を参照してください。

  8. メディア ライブラリにアクセスするには、アプリ マニフェスト ファイルでメディア ライブラリ機能を宣言する必要があります。この宣言が存在しないと、アプリはメディア ライブラリにファイルを保存できません。アプリで対象とする Windows Phone のバージョンに応じて、以下の機能を追加します。

    • ID_CAP_MEDIALIB: Windows Phone OS 7.1 アプリでは、この機能を使用するとメディア ライブラリにアクセスできます。

    • ID_CAP_MEDIALIB_PHOTO: Windows Phone 8 アプリでは、この機能を使用してメディア ライブラリに写真を保存できます。

    Windows Phone 8 アプリで、メディア ライブラリのビデオとオーディオにアクセスするには、追加機能を使用する必要があります。詳細については、「Windows Phone 8 のアプリ機能とハードウェア要件」を参照してください。

  9. (任意) アプリの機能が前面カメラを前提としている場合、アプリの対象となる Windows Phone のバージョンに応じて、アプリのマニフェスト ファイルに前面カメラの機能またはハードウェア要件を追加します。

    • ID_HW_FRONTCAMERA: Windows Phone OS 7.1 アプリはこの機能を使用できます。この機能を使用する場合、前面カメラのないユーザーに対しては、使用中の電話ではアプリの一部の機能が動作しないが、アプリをダウンロードすることは可能である旨が通知されます。

    • ID_REQ_FRONTCAMERA: Windows Phone 8 アプリはこのハードウェア要件を使用できます。この要件を使用する場合、前面カメラのないユーザーはこのアプリをダウンロードできません。

    機能の詳細については、「Windows Phone 8 のアプリ機能とハードウェア要件」を参照してください。

ファインダーを実装するには、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 phone.
                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 phone.
                        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 phone.
                    this.Dispatcher.BeginInvoke(delegate()
                    {
                        // Write message.
                        txtDebug.Text = "A Camera is not available on this phone.";
                    });
    
                    // 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 8 のカメラ アプリでグレースケールを処理する方法」を参照してください。

  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 phone.
                    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 の名前を設定するために使用します。

写真撮影時には、2 つの画像がキャプチャされます。1 つはフル解像度の画像であり、もう 1 つはフル解像度の写真を表示するためにギャラリー ビューで使用されるサムネイル画像です。ここでは、フル解像度の画像を電話のメディア ライブラリに格納する方法を示します。また、フル解像度の画像とサムネイル画像をローカル フォルダーに保存する方法も示します。

メディア ライブラリとローカル フォルダーに画像を保存するには

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

        // Informs when full resolution photo has been taken, saves to local media library and the local folder.
        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 photo.";
                });
    
                // Save photo to the media library camera roll.
                library.SavePictureToCameraRoll(fileName, e.ImageStream);
    
                // Write message to the UI thread.
                Deployment.Current.Dispatcher.BeginInvoke(delegate()
                {
                    txtDebug.Text = "Photo has been saved to camera roll.";
    
                });
    
                // Set the position of the stream back to start
                e.ImageStream.Seek(0, SeekOrigin.Begin);
    
                // Save photo as JPEG to the local folder.
                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 the local folder. 
                        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 = "Photo has been saved to the local folder.";
    
                });
            }
            finally
            {
                // Close image stream
                e.ImageStream.Close();
            }
    
        }
    
        // Informs when thumbnail photo has been taken, saves to the local folder
        // User will select this image in the Photos Hub to bring up the full-resolution. 
        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 the local folder.
                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 the local folder. 
                        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 the local folder.";
    
                });
            }
            finally
            {
            // Close image stream
            e.ImageStream.Close();
            }
        }
    
    

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

    メモメモ:

    写真をフォト ハブの [保存した写真] アルバムに保存するには、SavePicture() メソッドを使用します。この例で使用する SavePictureToCameraRoll() メソッドは、画像を Camera Roll アルバムに保存します。

  2. 電話で、[デバッグ] メニューの [デバッグ開始] をクリックしてアプリを実行します。[SH] ボタンを押してアプリをテストします。txtDebug TextBlock は、ローカル フォルダーへの保存操作の状態を示します。アプリを終了した後、アプリで撮影した写真を、写真ハブの [カメラ ロール] フォルダーで検索できます。

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

    AP_Con_CameraWireFrame

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

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

表示: