此页面有用吗?
您对此内容的反馈非常重要。 请告诉我们您的想法。
更多反馈?
1500 个剩余字符
导出 (0) 打印
全部展开
信息
您所需的主题如下所示。但此主题未包含在此库中。

如何为 Windows Phone 8 创建基本相机应用

2014/6/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.0 应用以使用 Windows Phone OS 7.1 中的功能时,相机功能 ID_CAP_ISV_CAMERA 不会自动添加到应用清单文件 WMAppManifest.xml 中。如果没有 ID_CAP_ISV_CAMERA,则使用相机 API 的应用将无法工作。在新的 Windows Phone OS 7.1 项目中,该功能包含在应用的清单文件中。

本主题未能完整介绍 Windows Phone OS 7.1 模拟器(模拟器 7.5)。使用手机或 Windows Phone 8 模拟器开发此应用。

在本节中,创建相机 UI,它包含一个用于显示所拍摄帧的取景器区域和一个用于拍摄图像的快门按钮。

创建相机 UI 的步骤

  1. 若使用 Windows Phone SDK,则使用 Windows Phone 应用 模板创建新项目。

  2. 创建项目后,从“项目”菜单中,选择“添加引用”。在 .NET 标签上,选择 Microsoft.XNA.Framework,然后单击“确定”

  3. MainPage.xaml 文件中,更新 phone:PhoneApplicationPage 元素,如以下代码中所示。

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

    这将配置横向的页面以及隐藏系统托盘。

  4. MainPage.xaml 中,将名为 LayoutRootGrid 替换为以下代码。

        <!--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>
    
    

    该代码创建一个 640 x 480 取景器区域,该区域具有一个包含快门按钮 SHStackPanel 控件。在以下部分中实现 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. 若要创建相机应用,必须在应用清单文件中声明相机功能。如果没有相机功能,该应用将无法工作。Open WMAppManifest.xml and confirm that the following capabilities element is present.

    <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) 方法创建名为 camPhotoCamera 对象并配置多个事件。该代码还将 VideoBrush 源设置为手机相机对象 cam

    如果除了主相机之外,手机还有一个前置相机,则应用将使用此前置相机。并非所有手机都有前置相机,因此 IsCameraTypeSupported(CameraType) 方法还用于在创建 PhotoCamera 对象之前检查该对象是否可用。还有可能手机没有任何类型的相机。这种情况下,会禁用 UI 并且显示一条消息。

    为了说明 Windows Phone 执行模型,在 OnNavigatedTo(NavigationEventArgs) 方法中初始化 PhotoCamera 对象并在 OnNavigatingFrom(NavigatingCancelEventArgs) 方法期间进行显式释放。在 OnNavigatedTo(NavigationEventArgs) 中添加 PhotoCamera 事件的事件处理程序并在 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 事件更新名为 txtDebugTextBlock。需要使用 BeginInvoke 方法更新状态,因为应用 UI 在另一个线程上运行。

  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 命名。

照相时拍摄两个图像。一个是高分辨率图像,另一个是用于在库视图中提供高分辨率照片的缩略图图像。本节演示如何将高分辨率图像放置到手机媒体库中。还演示如何将高分辨率图像和缩略图图像保存到本地文件夹。

将图像保存到媒体库和本地文件夹的步骤

  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();
            }
        }
    
    

    该代码实现 CaptureImageAvailableCaptureThumbnailAvailable 事件。第一个方法将高分辨率图像保存到媒体库和本地文件夹。第二个方法演示如何将缩略图图像保存到本地文件夹。

    说明注意:

    若要将照片保存到照片中心的“保存的图片”相册中,请使用 SavePicture() 方法。此示例中使用的 SavePictureToCameraRoll() 方法将图像保存到“本机拍照”相册中。

  2. 在手机上,通过选择“调试 | 启动调试”菜单命令来运行应用。通过按 SH 按钮测试应用。txtDebug TextBlock 将指示保存到本地文件夹的保存操作的状态。退出应用之后,您可以在照片中心的“本机拍照”文件夹中找到使用该应用拍摄的照片。

    以下示例演示此时如何显示 UI。

    AP_Con_CameraWireFrame

    在此示例中,软件快门按钮 SH 显示在 UI 的右上角。Mango 的照片出现在名为 viewfinderCanvasCanvas 控件中。

  3. 既然您已完成了这个基本相机应用,那么您可以使用它来完成以下主题:

显示:
© 2015 Microsoft