使用 Windows 内置相机 UI 捕获照片和视频

本文介绍如何通过使用内置于 Windows 的相机 UI 来使用 CameraCaptureUI 类捕获照片或视频。 此功能易于使用。 它可让你的应用只需几行代码即可获取用户捕获的照片或视频。

如果你希望提供你自己的相机 UI 或者你的方案需要对捕获操作进行更可靠的低级别控制,则你应使用 MediaCapture 类并实现自己的捕获体验。 有关详细信息,请参阅 使用 MediaCapture 捕获基本的照片、视频和音频

注意

如果你的应用只使用了“CameraCaptureUI”,则不应指定应用清单文件中的“网络摄像头”或“麦克风”功能。 如果指定了这些功能,应用将显示在设备的摄像头隐私设置中,但是即使用户拒绝摄像头访问应用,也不会阻止 CameraCaptureUI 捕获媒体。

这是因为 Windows 内置的摄像头应用是受信任的第一方应用,需要用户按下按钮来启动照片、音频和视频捕获。 如果将 CameraCaptureUI 用作你唯一的照片捕获机制时指定了网络摄像头或麦克风功能,则提交至 Microsoft Store 时可能无法通过 Windows 应用程序认证工具包认证。

如果使用 MediaCapture 以编程方式捕获音频、照片或视频,则必须指定应用清单文件中的网络摄像头或麦克风功能。

使用 CameraCaptureUI 捕获照片

若要使用相机捕获 UI,请将 Windows.Media.Capture 命名空间包含在你的项目中。 若要针对返回的图像文件执行文件操作,请包含 Windows.Storage

using Windows.Media.Capture;
using Windows.Storage;
#include <winrt/Windows.Media.Capture.h>
#include <winrt/Windows.Media.Playback.h>
#include <winrt/Windows.Storage.h>
using namespace winrt;
using namespace Windows::Media::Capture;
using namespace Windows::Storage;

若要捕获照片,请创建新的 CameraCaptureUI 对象。 通过使用对象的 PhotoSettings 属性,你可以为返回的照片指定属性,例如照片的图像格式。 默认情况下,相机捕获 UI 支持在返回照片之前裁剪照片。 可以使用 AllowCropping 属性禁用此功能。 此示例设置 CroppedSizeInPixels 以要求返回的图像像素为 200 x 200。

注意

移动设备系列中的设备不支持 CameraCaptureUI 中的图像剪裁。 在这些设备上运行应用时,将忽略 AllowCropping 属性的值。

调用 CaptureFileAsync 并指定 CameraCaptureUIMode.Photo 以指定应捕获的照片。 如果捕获成功,该方法将返回包含该图像的 StorageFile 实例。 如果用户取消捕获,则返回的对象为 NULL。

CameraCaptureUI captureUI = new CameraCaptureUI();
captureUI.PhotoSettings.Format = CameraCaptureUIPhotoFormat.Jpeg;
captureUI.PhotoSettings.CroppedSizeInPixels = new Size(200, 200); 

StorageFile photo = await captureUI.CaptureFileAsync(CameraCaptureUIMode.Photo);

if (photo == null)
{
    // User cancelled photo capture
    return;
}
CameraCaptureUI captureUI;
captureUI.PhotoSettings().Format(CameraCaptureUIPhotoFormat::Jpeg);
captureUI.PhotoSettings().CroppedSizeInPixels({ 200, 200 });

StorageFile photo = co_await captureUI.CaptureFileAsync(CameraCaptureUIMode::Photo);

if (!photo)
{
    // User cancelled photo capture
    co_return;
}

为包含捕获的照片的 StorageFile 提供一个动态生成的名称,并将其保存在应用的本地文件夹中。 若要更好地组织你捕获的照片,可以将该文件移动到其他文件夹。

StorageFolder destinationFolder = 
    await ApplicationData.Current.LocalFolder.CreateFolderAsync("ProfilePhotoFolder", 
        CreationCollisionOption.OpenIfExists);

await photo.CopyAsync(destinationFolder, "ProfilePhoto.jpg", NameCollisionOption.ReplaceExisting);
await photo.DeleteAsync();
StorageFolder destinationFolder =
    co_await ApplicationData::Current().LocalFolder().CreateFolderAsync(L"ProfilePhotoFolder",
        CreationCollisionOption::OpenIfExists);

co_await photo.CopyAsync(destinationFolder, L"ProfilePhoto.jpg", NameCollisionOption::ReplaceExisting);
co_await photo.DeleteAsync();

若要在应用中使用你的照片,你可能希望创建可以与多个不同的通用 Windows 应用功能结合使用的 SoftwareBitmap 对象。

首先,在项目中添加 Windows.Graphics.Imaging 命名空间。

using Windows.Storage.Streams;
using Windows.Graphics.Imaging;
#include <winrt/Windows.Graphics.Imaging.h>
#include <winrt/Windows.Storage.Streams.h>
using namespace Windows::Graphics::Imaging;
using namespace Windows::Storage::Streams;

调用 OpenAsync 以从图像文件获得一个流。 调用 BitmapDecoder.CreateAsync 以获取流的位图解码器。 然后,调用 GetSoftwareBitmap 以获取该图像的 SoftwareBitmap 表示形式。

IRandomAccessStream stream = await photo.OpenAsync(FileAccessMode.Read);
BitmapDecoder decoder = await BitmapDecoder.CreateAsync(stream);
SoftwareBitmap softwareBitmap = await decoder.GetSoftwareBitmapAsync();
IRandomAccessStream stream = co_await photo.OpenAsync(FileAccessMode::Read);
BitmapDecoder decoder = co_await BitmapDecoder::CreateAsync(stream);
SoftwareBitmap softwareBitmap = co_await decoder.GetSoftwareBitmapAsync();

若要在 UI 中显示该图像,请在 XAML 页面中声明 Image 控件。

<Image x:Name="imageControl" Width="200" Height="200"/>
<Image x:Name="imageControl" Width="200" Height="200"/>

若要在 XAML 页面中使用软件位图,请在项目中包含正在使用的 Windows.UI.Xaml.Media.Imaging 命名空间。

using Windows.UI.Xaml.Media.Imaging;
#include <winrt/Windows.UI.Xaml.Media.Imaging.h>
using namespace Windows::UI::Xaml::Media::Imaging;

图像控件要求图像源采用 BGRA8 格式,并预乘 alpha 或无 alpha。 调用静态方法 SoftwareBitmap.Convert 以使用所需格式创建新的软件位图。 接下来,创建一个新的 SoftwareBitmapSource 对象,并调用 SetBitmapAsync 以将软件位图分配给该源。 最后,设置 Image 控件的 Source 属性以显示 UI 中已捕获的照片。

SoftwareBitmap softwareBitmapBGR8 = SoftwareBitmap.Convert(softwareBitmap,
        BitmapPixelFormat.Bgra8, 
        BitmapAlphaMode.Premultiplied);

SoftwareBitmapSource bitmapSource = new SoftwareBitmapSource();
await bitmapSource.SetBitmapAsync(softwareBitmapBGR8);

imageControl.Source = bitmapSource;
SoftwareBitmap softwareBitmapBGR8 = SoftwareBitmap::Convert(softwareBitmap,
    BitmapPixelFormat::Bgra8,
    BitmapAlphaMode::Premultiplied);

SoftwareBitmapSource bitmapSource;
co_await bitmapSource.SetBitmapAsync(softwareBitmapBGR8);

imageControl().Source(bitmapSource);

使用 CameraCaptureUI 捕获视频

若要捕获视频,请创建新的 CameraCaptureUI 对象。 通过使用对象的 VideoSettings 属性,你可以为返回的视频指定属性,例如视频格式。

调用 CaptureFileAsync 并指定 Video 以捕获视频。 如果捕获成功,该方法将返回包含该视频的 StorageFile 实例。 如果你取消捕获,则返回的对象为 Null。

CameraCaptureUI captureUI = new CameraCaptureUI();
captureUI.VideoSettings.Format = CameraCaptureUIVideoFormat.Mp4;

StorageFile videoFile = await captureUI.CaptureFileAsync(CameraCaptureUIMode.Video);

if (videoFile == null)
{
    // User cancelled photo capture
    return;
}
CameraCaptureUI captureUI;
captureUI.VideoSettings().Format(CameraCaptureUIVideoFormat::Mp4);

StorageFile videoFile = co_await captureUI.CaptureFileAsync(CameraCaptureUIMode::Video);

if (!videoFile)
{
    // User cancelled photo capture
    co_return;
}

根据应用方案处理所捕获视频文件。 本文的其余部分向你介绍了如何从一个或多个已捕获的视频快速创建媒体组合并将其显示在你的 UI 中。

首先,添加 MediaPlayerElement 控件,其中的视频组合将在 XAML 页面上显示。

<MediaPlayerElement x:Name="mediaPlayerElement" Width="320" Height="240" AreTransportControlsEnabled="True"/>

从相机捕获 UI 返回视频文件时,可通过调用 CreateFromStorageFile 创建一个新的 MediaSource。 调用与 MediaPlayerElement 关联的默认 MediaPlayerPlay 方法以播放视频。

mediaPlayerElement.Source = MediaSource.CreateFromStorageFile(videoFile);
mediaPlayerElement.MediaPlayer.Play();
mediaPlayerElement().Source(MediaSource::CreateFromStorageFile(videoFile));
mediaPlayerElement().MediaPlayer().Play();