写真とビデオのキャプチャのための手動カメラ制御

この記事では、光学式手ブレ補正やスムーズ ズームなど、写真とビデオのキャプチャに関する拡張シナリオを可能にするために、手動デバイス制御を使う方法について説明します。

この記事で説明するコントロールはすべて、同じパターンを使ってアプリに追加されます。 まず、アプリが実行されている現在のデバイスで、コントロールがサポートされているかどうかを確認します。 コントロールがサポートされている場合は、コントロールに対して必要なモードを設定します。 一般的に、現在のデバイスで特定のコントロールがサポートされていない場合は、ユーザーがその機能を有効にできるような UI 要素を無効または非表示にする必要があります。

この記事のコードは、カメラの手動コントロール SDK のサンプルを基にしています。 このサンプルをダウンロードし、該当するコンテキストで使用されているコードを確認することも、サンプルを独自のアプリの開始点として使用することもできます。

注意

この記事の内容は、写真やビデオの基本的なキャプチャ機能を実装するための手順を紹介した「MediaCapture を使った基本的な写真、ビデオ、およびオーディオのキャプチャ」で取り上げた概念やコードに基づいています。 そちらの記事で基本的なメディア キャプチャのパターンを把握してから、高度なキャプチャ シナリオに進むことをお勧めします。 この記事で紹介しているコードは、MediaCapture のインスタンスが既に作成され、適切に初期化されていることを前提としています。

この記事で説明するデバイス制御 API はすべて、Windows.Media.Devices 名前空間のメンバーです。

using Windows.Media.Devices;

露出

ExposureControl によって、写真やビデオのキャプチャ時に使用されるシャッター速度を設定できます。

この例では、スライダー コントロールを使って現在の露出値を調整し、チェック ボックスを使って自動露出調整のオンとオフを切り替えます。

<Slider Name="ExposureSlider" ValueChanged="ExposureSlider_ValueChanged"/>
<TextBlock Name="ExposureTextBlock" Text="{Binding ElementName=ExposureSlider,Path=Value}"/>
<CheckBox Name="ExposureAutoCheckBox" Content="Auto" Checked="ExposureCheckBox_CheckedChanged" Unchecked="ExposureCheckBox_CheckedChanged"/>

現在のキャプチャ デバイスで ExposureControl がサポートされているかどうかを確認するには、Supported プロパティを確認します。 コントロールがサポートされている場合は、この機能の UI を表示し、有効にすることができます。 自動露出調整が現在アクティブであるかどうかを示すために、チェック ボックスのオンの状態を Auto プロパティの値に設定します。

露出値は、デバイスでサポートされている範囲内である必要があり、サポートされているステップ サイズのインクリメントである必要があります。 現在のデバイスでサポートされている値を取得するには、MinMax、および Step プロパティを確認します。これらのプロパティは、対応するスライダー コントロールのプロパティを設定するために使用されます。

値が設定されたときにイベントがトリガーされないように、ValueChanged イベント ハンドラーの登録を解除した後、スライダー コントロールの値を ExposureControl の現在値に設定します。

var exposureControl = _mediaCapture.VideoDeviceController.ExposureControl;

if (exposureControl.Supported)
{
    ExposureAutoCheckBox.Visibility = Visibility.Visible;
    ExposureSlider.Visibility = Visibility.Visible;

    ExposureAutoCheckBox.IsChecked = exposureControl.Auto;

    ExposureSlider.Minimum = exposureControl.Min.Ticks;
    ExposureSlider.Maximum = exposureControl.Max.Ticks;
    ExposureSlider.StepFrequency = exposureControl.Step.Ticks;

    ExposureSlider.ValueChanged -= ExposureSlider_ValueChanged;
    var value = exposureControl.Value;
    ExposureSlider.Value = value.Ticks;
    ExposureSlider.ValueChanged += ExposureSlider_ValueChanged;
}
else
{
    ExposureAutoCheckBox.Visibility = Visibility.Collapsed;
    ExposureSlider.Visibility = Visibility.Collapsed;
}

ValueChanged イベント ハンドラーで、コントロールの現在の値を取得し、SetValueAsync を呼び出して露出値を設定します。

private async void ExposureSlider_ValueChanged(object sender, Windows.UI.Xaml.Controls.Primitives.RangeBaseValueChangedEventArgs e)
{
    var value = TimeSpan.FromTicks((long)(sender as Slider).Value);
    await _mediaCapture.VideoDeviceController.ExposureControl.SetValueAsync(value);
}

自動露出チェック ボックスの CheckedChanged イベント ハンドラーで、SetAutoAsync を呼び出してブール値を渡すことにより、自動露出調整のオンとオフを切り替えます。

private async void ExposureCheckBox_CheckedChanged(object sender, RoutedEventArgs e)
{
    if(! _isPreviewing)
    {
        // Auto exposure only supported while preview stream is running.
        return;
    }

    var autoExposure = ((sender as CheckBox).IsChecked == true);
    await _mediaCapture.VideoDeviceController.ExposureControl.SetAutoAsync(autoExposure);
}

重要

自動露出モードは、プレビュー ストリームが実行中であるときにのみサポートされます。 自動露出をオンにする前に、プレビュー ストリームが実行されていることを確認します。

露出補正

ExposureCompensationControl によって、写真やビデオのキャプチャ時に使用される露出補正を設定できます。

この例では、スライダー コントロールを使って、現在の露出補正値を調整します。

<Slider Name="EvSlider" ValueChanged="EvSlider_ValueChanged"/>
<TextBlock Text="{Binding ElementName=EvSlider,Path=Value}" Name="EvTextBlock"/>

現在のキャプチャ デバイスで ExposureCompensationControl がサポートされているかどうかを確認するには、Supported プロパティを確認します。 コントロールがサポートされている場合は、この機能の UI を表示し、有効にすることができます。

露出補正値は、デバイスでサポートされている範囲内である必要があり、サポートされているステップ サイズのインクリメントである必要があります。 現在のデバイスでサポートされている値を取得するには、MinMax、および Step プロパティを確認します。これらのプロパティは、対応するスライダー コントロールのプロパティを設定するために使用されます。

値が設定されたときにイベントがトリガーされないように、ValueChanged イベント ハンドラーの登録を解除した後、スライダー コントロールの値を ExposureCompensationControl の現在値に設定します。

var exposureCompensationControl = _mediaCapture.VideoDeviceController.ExposureCompensationControl;

if (exposureCompensationControl.Supported)
{
    EvSlider.Visibility = Visibility.Visible;
    EvSlider.Minimum = exposureCompensationControl.Min;
    EvSlider.Maximum = exposureCompensationControl.Max;
    EvSlider.StepFrequency = exposureCompensationControl.Step;

    EvSlider.ValueChanged -= EvSlider_ValueChanged;
    EvSlider.Value = exposureCompensationControl.Value;
    EvSlider.ValueChanged += EvSlider_ValueChanged;
}
else
{
    EvSlider.Visibility = Visibility.Collapsed;
}

ValueChanged イベント ハンドラーで、コントロールの現在の値を取得し、SetValueAsync を呼び出して露出値を設定します。

private async void EvSlider_ValueChanged(object sender, Windows.UI.Xaml.Controls.Primitives.RangeBaseValueChangedEventArgs e)
{
    var value = (sender as Slider).Value;
    await _mediaCapture.VideoDeviceController.ExposureCompensationControl.SetValueAsync((float)value);
}

Flash

FlashControl によって、フラッシュを有効または無効にしたり、フラッシュを使うかどうかをシステムが動的に判断する、自動フラッシュを有効にしたりすることができます。 このコントロールによって、サポートされているデバイスで自動赤目軽減を有効にすることもできます。 これらの設定はすべて写真のキャプチャに適用されます。 TorchControl は、ビデオ キャプチャ時のトーチのオンとオフを切り替える別のコントロールです。

この例では、一連のラジオ ボタンを使って、ユーザーがオン、オフ、自動のフラッシュ設定を切り替えることができるようにします。 赤目軽減とビデオ トーチのオンとオフを切り替えるためのチェック ボックスも用意されています。

<RadioButton Name="FlashOnRadioButton" Content="On" Checked="FlashOnRadioButton_Checked"/>
<RadioButton Name="FlashAutoRadioButton" Content="Auto" Checked="FlashAutoRadioButton_Checked"/>
<RadioButton Name="FlashOffRadioButton" Content="Off" Checked="FlashOffRadioButton_Checked"/>
<CheckBox Name="RedEyeFlashCheckBox" Content="Red Eye" Visibility="Collapsed" Checked="RedEyeFlashCheckBox_CheckedChanged" Unchecked="RedEyeFlashCheckBox_CheckedChanged"/>
<CheckBox Name="TorchCheckBox" Content="Video Light" Visibility="Collapsed" Checked="TorchCheckBox_CheckedChanged" Unchecked="TorchCheckBox_CheckedChanged"/>

現在のキャプチャ デバイスで FlashControl がサポートされているかどうかを確認するには、Supported プロパティを確認します。 コントロールがサポートされている場合は、この機能の UI を表示し、有効にすることができます。 FlashControl がサポートされている場合でも、自動赤目軽減はサポートされている場合とサポートされていない場合があるため、UI を有効にする前に RedEyeReductionSupported プロパティを確認します。 TorchControl はフラッシュ コントロールとは別であるため、使用する前にその Supported プロパティも確認する必要があります。

フラッシュの各ラジオ ボタンの Checked イベント ハンドラーで、適切な対応するフラッシュの設定を有効または無効にします。 フラッシュが常に使用されるように設定するには、Enabled プロパティを true に、Auto プロパティを false に設定する必要があります。

var flashControl = _mediaCapture.VideoDeviceController.FlashControl;

if (flashControl.Supported)
{
    FlashAutoRadioButton.Visibility = Visibility.Visible;
    FlashOnRadioButton.Visibility = Visibility.Visible;
    FlashOffRadioButton.Visibility = Visibility.Visible;

    FlashAutoRadioButton.IsChecked = true;

    if (flashControl.RedEyeReductionSupported)
    {
        RedEyeFlashCheckBox.Visibility = Visibility.Visible;
    }

    // Video light is not strictly part of flash, but users might expect to find it there
    if (_mediaCapture.VideoDeviceController.TorchControl.Supported)
    {
        TorchCheckBox.Visibility = Visibility.Visible;
    }
}
else
{
    FlashAutoRadioButton.Visibility = Visibility.Collapsed;
    FlashOnRadioButton.Visibility = Visibility.Collapsed;
    FlashOffRadioButton.Visibility = Visibility.Collapsed;
}
private void FlashOnRadioButton_Checked(object sender, RoutedEventArgs e)
{
    _mediaCapture.VideoDeviceController.FlashControl.Enabled = true;
    _mediaCapture.VideoDeviceController.FlashControl.Auto = false;
}

private void FlashAutoRadioButton_Checked(object sender, RoutedEventArgs e)
{
    _mediaCapture.VideoDeviceController.FlashControl.Enabled = true;
    _mediaCapture.VideoDeviceController.FlashControl.Auto = true;
}

private void FlashOffRadioButton_Checked(object sender, RoutedEventArgs e)
{
    _mediaCapture.VideoDeviceController.FlashControl.Enabled = false;
}

赤目軽減チェック ボックスのハンドラーで、RedEyeReduction プロパティを適切な値に設定します。

private void RedEyeFlashCheckBox_CheckedChanged(object sender, RoutedEventArgs e)
{
    _mediaCapture.VideoDeviceController.FlashControl.RedEyeReduction = (RedEyeFlashCheckBox.IsChecked == true);
}

最後に、ビデオ トーチ チェック ボックスのハンドラーで、Enabled プロパティを適切な値に設定します。

private void TorchCheckBox_CheckedChanged(object sender, RoutedEventArgs e)
{
    _mediaCapture.VideoDeviceController.TorchControl.Enabled = (TorchCheckBox.IsChecked == true);

    if(! (_isPreviewing && _isRecording))
    {
        System.Diagnostics.Debug.WriteLine("Torch may not emit light if preview and video capture are not running.");
    }
}

注意

一部のデバイスでは、TorchControl.Enabled が true に設定されている場合でも、デバイスがプレビュー ストリームを実行中で、アクティブにビデオをキャプチャ中ではない限り、トーチは発光しません。 推奨される処理の順序は、ビデオのプレビューを有効にし、Enabled を true に設定してトーチを有効にした後、ビデオ キャプチャを開始するという順序です。 一部のデバイスでは、プレビューを開始した後もトーチが点灯しません。 その他のデバイスでは、トーチはビデオのキャプチャを開始するまで点灯しません。

対象

FocusControl オブジェクトでは、カメラのフォーカスを調整するためによく使用される 3 種類の方法である、連続オート フォーカス、タップしてフォーカス、手動フォーカスがサポートされています。 カメラ アプリでこれらの 3 つの方法がすべてをサポートされている可能性がありますが、分かりやすくするために、この記事ではそれぞれの手法を個別に説明します。 このセクションでは、フォーカス アシスト ライトを有効にする方法も説明します。

連続オート フォーカス

連続オート フォーカスを有効にすると、カメラに対して、動的にフォーカスを調整して、写真やビデオの被写体にフォーカスを合わせ続けるように指示されます。 この例では、ラジオ ボタンを使用して連続オート フォーカスのオンとオフを切り替えます。

<RadioButton Content="CAF" Name="CafFocusRadioButton" Checked="CafFocusRadioButton_Checked"/>

現在のキャプチャ デバイスで FocusControl がサポートされているかどうかを確認するには、Supported プロパティを確認します。 次に、連続オート フォーカスがサポートされている場合は、SupportedFocusModes の一覧を確認して値 FocusMode.Continuous が含まれていることを確認します。この値が含まれている場合は、連続オート フォーカスのラジオ ボタンを表示します。

var focusControl = _mediaCapture.VideoDeviceController.FocusControl;

if (focusControl.Supported)
{
    CafFocusRadioButton.Visibility = focusControl.SupportedFocusModes.Contains(FocusMode.Continuous) 
        ? Visibility.Visible : Visibility.Collapsed;
}
else
{
    CafFocusRadioButton.Visibility = Visibility.Collapsed;
}

連続オート フォーカス ラジオ ボタンの Checked イベント ハンドラーで、VideoDeviceController.FocusControl プロパティを使ってコントロールのインスタンスを取得します。 アプリが以前に LockAsync を呼び出して他のフォーカス モードのいずれかを有効にしていた場合は、UnlockAsync を呼び出してコントロールのロックを解除します。

新しい FocusSettings オブジェクトを作成し、Mode プロパティを Continuous に設定します。 AutoFocusRange プロパティをアプリのシナリオに適した値またはユーザーが UI で選択した値に設定します。 FocusSettings オブジェクトを Configure メソッドに渡し、FocusAsync を呼び出して連続オート フォーカスを開始します。

private async void CafFocusRadioButton_Checked(object sender, RoutedEventArgs e)
{
    if(! _isPreviewing)
    {
        // Autofocus only supported while preview stream is running.
        return;
    }

    var focusControl = _mediaCapture.VideoDeviceController.FocusControl;
    await focusControl.UnlockAsync();
    var settings = new FocusSettings { Mode = FocusMode.Continuous, AutoFocusRange = AutoFocusRange.FullRange };
    focusControl.Configure(settings);
    await focusControl.FocusAsync();
}

重要

オート フォーカス モードは、プレビュー ストリームが実行中であるときにのみサポートされます。 連続オート フォーカスをオンにする前に、プレビュー ストリームが実行されていることを確認します。

タップしてフォーカス

タップしてフォーカスの手法では、FocusControlRegionsOfInterestControl を使って、キャプチャ デバイスでフォーカスを合わせるキャプチャ フレームのサブ領域を指定します。 フォーカスの領域は、プレビュー ストリームが表示されている画面をユーザーがタップすることによって決定されます。

この例では、ラジオ ボタンを使って、タップしてフォーカス モードを有効または無効にします。

<RadioButton Content="Tap" Name="TapFocusRadioButton" Checked="TapFocusRadioButton_Checked"/>

現在のキャプチャ デバイスで FocusControl がサポートされているかどうかを確認するには、Supported プロパティを確認します。 この手法を使うには、RegionsOfInterestControl がサポートされており、少なくとも 1 つの領域をサポートしている必要があります。 AutoFocusSupported および MaxRegions プロパティを確認して、タップしてフォーカスのラジオ ボタンを表示するか、非表示にするかを決定します。

var focusControl = _mediaCapture.VideoDeviceController.FocusControl;

if (focusControl.Supported)
{
    TapFocusRadioButton.Visibility = (_mediaCapture.VideoDeviceController.RegionsOfInterestControl.AutoFocusSupported &&
                                      _mediaCapture.VideoDeviceController.RegionsOfInterestControl.MaxRegions > 0) 
                                      ? Visibility.Visible : Visibility.Collapsed;
}
else
{
    TapFocusRadioButton.Visibility = Visibility.Collapsed;
}

タップしてフォーカスのラジオ ボタンの Checked イベント ハンドラーで、VideoDeviceController.FocusControl プロパティを使ってコントロールのインスタンスを取得します。 アプリが以前に UnlockAsync を呼び出して連続オート フォーカスを有効にしていた場合は、LockAsync を呼び出してコントロールをロックし、ユーザーが画面をタップしてフォーカスを変更するまで待機します。

private async void TapFocusRadioButton_Checked(object sender, RoutedEventArgs e)
{
    // Lock focus in case Continuous Autofocus was active when switching to Tap-to-focus
    var focusControl = _mediaCapture.VideoDeviceController.FocusControl;
    await focusControl.LockAsync();
    // Wait for user tap
}

この例は、ユーザーが画面をタップすると領域にフォーカスを合わせ、ユーザーがもう一度タップすると、トグルのように、その領域からフォーカスを削除します。 現在のトグルの状態を追跡するには、ブール変数を使います。

bool _isFocused = false;

次の手順では、ユーザーが画面をタップしたときのイベントをリッスンします。そのためには、現在キャプチャ プレビュー ストリームを表示している CaptureElementTapped イベントを処理します。 カメラが現在プレビューを表示していない場合や、タップしてフォーカス モードが無効である場合は、何もせずにハンドラーから制御を戻します。

追跡変数 _isFocused が false になっており、カメラが現在フォーカスを処理していない場合 (FocusControlFocusState プロパティで判断)、タップしてフォーカスの処理を開始します。 ハンドラーに渡されるイベント引数から、ユーザーのタップの位置を取得します。 また、この例では、この機会を利用して、フォーカスが設定される領域のサイズを取得します。 この場合、サイズは、キャプチャ要素の最小サイズの 1/4 です。 タップの位置と領域のサイズを、次のセクションで定義される TapToFocus ヘルパー メソッドに渡します。

_isFocused トグルが true に設定されている場合、ユーザーがタップすると、前の領域からフォーカスがクリアされます。 これは、次に示す TapUnfocus ヘルパー メソッドで行われます。

private async void PreviewControl_Tapped(object sender, TappedRoutedEventArgs e)
{
    if (!_isPreviewing || (TapFocusRadioButton.IsChecked != true)) return;

    if (!_isFocused && _mediaCapture.VideoDeviceController.FocusControl.FocusState != MediaCaptureFocusState.Searching)
    {
        var smallEdge = Math.Min(Window.Current.Bounds.Width, Window.Current.Bounds.Height);

        // Choose to make the focus rectangle 1/4th the length of the shortest edge of the window
        var size = new Size(smallEdge / 4, smallEdge / 4);
        var position = e.GetPosition(sender as UIElement);

        // Note that at this point, a rect at "position" with size "size" could extend beyond the preview area. The following method will reposition the rect if that is the case
        await TapToFocus(position, size);
    }
    else
    {
        await TapUnfocus();
    }
}

TapToFocus ヘルパー メソッドで、最初に _isFocused トグルを true に設定します。これにより、次に画面をタップしたときに、タップした領域からフォーカスが解除されます。

このヘルパー メソッドの次のタスクでは、フォーカス コントロールに割り当てられるプレビュー ストリーム内の四角形を決定します。 これには 2 つのステップが必要です。 最初のステップは、CaptureElement コントロール内でプレビュー ストリームが占有する四角形を特定することです。 これは、プレビュー ストリームのサイズとデバイスの向きに依存します。 ヘルパー メソッド GetPreviewStreamRectInControl (このセクションの最後に示されている) は、このタスクを実行し、プレビュー ストリームが含まれている四角形を返します。

TapToFocus の次のタスクは、CaptureElement.Tapped イベント ハンドラーで特定された、タップの位置と目的のフォーカスの四角形のサイズを、キャプチャ ストリーム内の座標に変換することです。 ConvertUiTapToPreviewRect ヘルパー メソッド (このセクションで後で説明されている) は、フォーカスが要求されている四角形をキャプチャ ストリームの座標で返します。

ターゲットの四角形が取得されたら、Bounds プロパティを前の手順で取得されたターゲットの四角形に設定して、新しい RegionOfInterest オブジェクトを作成します。

キャプチャ デバイスの FocusControl を取得します。 新しい FocusSettings オブジェクトを作成し、FocusControl でサポートされていることを確認した後、ModeAutoFocusRange を目的の値に設定します。 最後に、FocusControlConfigure を呼び出して、設定をアクティブにし、指定された領域へのフォーカスを開始するようにデバイスに通知します。

次に、キャプチャ デバイスの RegionsOfInterestControl を取得し、SetRegionsAsync を呼び出してアクティブな領域を設定します。 サポートされているデバイスでは複数の対象領域を設定できますが、この例では単一の領域のみを設定します。

最後に、FocusControlFocusAsync を呼び出して、フォーカス設定を開始します。

重要

タップによるフォーカスを実装する場合、操作の順序が重要になります。 これらの API は、次の順序で呼び出す必要があります。

  1. FocusControl.Configure
  2. RegionsOfInterestControl.SetRegionsAsync
  3. FocusControl.FocusAsync
public async Task TapToFocus(Point position, Size size)
{
    _isFocused = true;

    var previewRect = GetPreviewStreamRectInControl();
    var focusPreview = ConvertUiTapToPreviewRect(position, size, previewRect);

    // Note that this Region Of Interest could be configured to also calculate exposure 
    // and white balance within the region
    var regionOfInterest = new RegionOfInterest
    {
        AutoFocusEnabled = true,
        BoundsNormalized = true,
        Bounds = focusPreview,
        Type = RegionOfInterestType.Unknown,
        Weight = 100,
    };


    var focusControl = _mediaCapture.VideoDeviceController.FocusControl;
    var focusRange = focusControl.SupportedFocusRanges.Contains(AutoFocusRange.FullRange) ? AutoFocusRange.FullRange : focusControl.SupportedFocusRanges.FirstOrDefault();
    var focusMode = focusControl.SupportedFocusModes.Contains(FocusMode.Single) ? FocusMode.Single : focusControl.SupportedFocusModes.FirstOrDefault();
    var settings = new FocusSettings { Mode = focusMode, AutoFocusRange = focusRange };
    focusControl.Configure(settings);

    var roiControl = _mediaCapture.VideoDeviceController.RegionsOfInterestControl;
    await roiControl.SetRegionsAsync(new[] { regionOfInterest }, true);

    await focusControl.FocusAsync();
}

TapUnfocus ヘルパー メソッドで、RegionsOfInterestControl を取得し、ClearRegionsAsync を呼び出して、TapToFocus ヘルパー メソッドでコントロールに登録された領域をクリアします。 次に、FocusControl を取得し、FocusAsync を呼び出して、対象領域を指定せずにデバイスで再びフォーカスを設定できるようにします。

private async Task TapUnfocus()
{
    _isFocused = false;

    var roiControl = _mediaCapture.VideoDeviceController.RegionsOfInterestControl;
    await roiControl.ClearRegionsAsync();

    var focusControl = _mediaCapture.VideoDeviceController.FocusControl;
    await focusControl.FocusAsync();
}

GetPreviewStreamRectInControl ヘルパー メソッドは、プレビュー ストリームの解像度とデバイスの向きを使い、コントロールがストリームの縦横比を維持するために提供する可能性があるレターボックス化されたパディングをトリミングして、プレビュー ストリームを含むプレビュー要素内の四角形を特定します。 このメソッドは、「MediaCapture を使った基本的な写真、ビデオ、およびオーディオのキャプチャ」に示されている基本的なメディア キャプチャのコード例で定義されているクラス メンバー変数を使います。

public Rect GetPreviewStreamRectInControl()
{
    var result = new Rect();

    var previewResolution = _mediaCapture.VideoDeviceController.GetMediaStreamProperties(MediaStreamType.VideoPreview) as VideoEncodingProperties;

    // In case this function is called before everything is initialized correctly, return an empty result
    if (PreviewControl == null || PreviewControl.ActualHeight < 1 || PreviewControl.ActualWidth < 1 ||
        previewResolution == null || previewResolution.Height == 0 || previewResolution.Width == 0)
    {
        return result;
    }

    var streamWidth = previewResolution.Width;
    var streamHeight = previewResolution.Height;

    // For portrait orientations, the width and height need to be swapped
    if (_displayOrientation == DisplayOrientations.Portrait || _displayOrientation == DisplayOrientations.PortraitFlipped)
    {
        streamWidth = previewResolution.Height;
        streamHeight = previewResolution.Width;
    }

    // Start by assuming the preview display area in the control spans the entire width and height both (this is corrected in the next if for the necessary dimension)
    result.Width = PreviewControl.ActualWidth;
    result.Height = PreviewControl.ActualHeight;

    // If UI is "wider" than preview, letterboxing will be on the sides
    if ((PreviewControl.ActualWidth / PreviewControl.ActualHeight > streamWidth / (double)streamHeight))
    {
        var scale = PreviewControl.ActualHeight / streamHeight;
        var scaledWidth = streamWidth * scale;

        result.X = (PreviewControl.ActualWidth - scaledWidth) / 2.0;
        result.Width = scaledWidth;
    }
    else // Preview stream is "wider" than UI, so letterboxing will be on the top+bottom
    {
        var scale = PreviewControl.ActualWidth / streamWidth;
        var scaledHeight = streamHeight * scale;

        result.Y = (PreviewControl.ActualHeight - scaledHeight) / 2.0;
        result.Height = scaledHeight;
    }

    return result;
}

ConvertUiTapToPreviewRect ヘルパー メソッドは、引数として、タップ イベントの場所、目的のフォーカス領域のサイズ、GetPreviewStreamRectInControl ヘルパー メソッドで取得したプレビュー ストリームを含む四角形を受け取ります。 このメソッドは、これらの値とデバイスの現在の向きを使って、目的の地域を含むプレビュー ストリーム内の四角形を計算します。 ここでも、このメソッドは、「MediaCapture を使った写真とビデオのキャプチャ」に示されている基本的なメディア キャプチャのコード例で定義されているクラス メンバー変数を使います。

private Rect ConvertUiTapToPreviewRect(Point tap, Size size, Rect previewRect)
{
    // Adjust for the resulting focus rectangle to be centered around the position
    double left = tap.X - size.Width / 2, top = tap.Y - size.Height / 2;

    // Get the information about the active preview area within the CaptureElement (in case it's letterboxed)
    double previewWidth = previewRect.Width, previewHeight = previewRect.Height;
    double previewLeft = previewRect.Left, previewTop = previewRect.Top;

    // Transform the left and top of the tap to account for rotation
    switch (_displayOrientation)
    {
        case DisplayOrientations.Portrait:
            var tempLeft = left;

            left = top;
            top = previewRect.Width - tempLeft;
            break;
        case DisplayOrientations.LandscapeFlipped:
            left = previewRect.Width - left;
            top = previewRect.Height - top;
            break;
        case DisplayOrientations.PortraitFlipped:
            var tempTop = top;

            top = left;
            left = previewRect.Width - tempTop;
            break;
    }

    // For portrait orientations, the information about the active preview area needs to be rotated
    if (_displayOrientation == DisplayOrientations.Portrait || _displayOrientation == DisplayOrientations.PortraitFlipped)
    {
        previewWidth = previewRect.Height;
        previewHeight = previewRect.Width;
        previewLeft = previewRect.Top;
        previewTop = previewRect.Left;
    }

    // Normalize width and height of the focus rectangle
    var width = size.Width / previewWidth;
    var height = size.Height / previewHeight;

    // Shift rect left and top to be relative to just the active preview area
    left -= previewLeft;
    top -= previewTop;

    // Normalize left and top
    left /= previewWidth;
    top /= previewHeight;

    // Ensure rectangle is fully contained within the active preview area horizontally
    left = Math.Max(left, 0);
    left = Math.Min(1 - width, left);

    // Ensure rectangle is fully contained within the active preview area vertically
    top = Math.Max(top, 0);
    top = Math.Min(1 - height, top);

    // Create and return resulting rectangle
    return new Rect(left, top, width, height);
}

手動フォーカス

手動フォーカスの手法では、スライダー コントロールを使って、キャプチャ デバイスの現在フォーカスの深度を設定します。 ラジオ ボタンを使って、手動フォーカスのオンとオフを切り替えます。

<Slider Name="FocusSlider" IsEnabled="{Binding ElementName=ManualFocusRadioButton,Path=IsChecked}" ValueChanged="FocusSlider_ValueChanged"/>
<TextBlock Text="{Binding ElementName=FocusSlider,Path=Value,FallbackValue='0'}"/>
<RadioButton Content="Manual" Name="ManualFocusRadioButton" Checked="ManualFocusRadioButton_Checked" IsChecked="False"/>

現在のキャプチャ デバイスで FocusControl がサポートされているかどうかを確認するには、Supported プロパティを確認します。 コントロールがサポートされている場合は、この機能の UI を表示し、有効にすることができます。

フォーカス値は、デバイスでサポートされている範囲内である必要があり、サポートされているステップ サイズのインクリメントである必要があります。 現在のデバイスでサポートされている値を取得するには、MinMax、および Step プロパティを確認します。これらのプロパティは、対応するスライダー コントロールのプロパティを設定するために使用されます。

値が設定されたときにイベントがトリガーされないように、ValueChanged イベント ハンドラーの登録を解除した後、スライダー コントロールの値を FocusControl の現在値に設定します。

var focusControl = _mediaCapture.VideoDeviceController.FocusControl;

if (focusControl.Supported)
{
    FocusSlider.Visibility = Visibility.Visible;
    ManualFocusRadioButton.Visibility = Visibility.Visible;

    FocusSlider.Minimum = focusControl.Min;
    FocusSlider.Maximum = focusControl.Max;
    FocusSlider.StepFrequency = focusControl.Step;
    

    FocusSlider.ValueChanged -= FocusSlider_ValueChanged;
    FocusSlider.Value = focusControl.Value;
    FocusSlider.ValueChanged += FocusSlider_ValueChanged;
}
else
{
    FocusSlider.Visibility = Visibility.Collapsed;
    ManualFocusRadioButton.Visibility = Visibility.Collapsed;
}

アプリが以前に UnlockAsync を呼び出してフォーカスのロックを解除していた場合は、手動フォーカスのラジオ ボタンの Checked イベント ハンドラーで、FocusControl オブジェクトを取得し、LockAsync を呼び出します。

private async void ManualFocusRadioButton_Checked(object sender, RoutedEventArgs e)
{
    var focusControl = _mediaCapture.VideoDeviceController.FocusControl;
    await focusControl.LockAsync();
}

手動フォーカス スライダーの ValueChanged イベント ハンドラーで、コントロールの現在の値を取得し、SetValueAsync を呼び出してフォーカス値を設定します。

private async void FocusSlider_ValueChanged(object sender, Windows.UI.Xaml.Controls.Primitives.RangeBaseValueChangedEventArgs e)
{
    var value = (sender as Slider).Value;
    await _mediaCapture.VideoDeviceController.FocusControl.SetValueAsync((uint)value);
}

フォーカス ライトの有効化

サポートされているデバイスで、デバイスのフォーカスを支援するフォーカス アシスト ライトを有効にすることができます。 この例では、チェック ボックスを使って、フォーカス アシスト ライトを有効または無効にします。

<CheckBox Content="Assist Light" Name="FocusLightCheckBox" IsEnabled="{Binding ElementName=TapFocusRadioButton,Path=IsChecked}"
                  Checked="FocusLightCheckBox_CheckedChanged" Unchecked="FocusLightCheckBox_CheckedChanged"/>

現在のキャプチャ デバイスで FlashControl がサポートされているかどうかを確認するには、Supported プロパティを確認します。 また、AssistantLightSupported を確認してアシスト ライトがサポートされていることも確認します。 これらがいずれもサポートされている場合は、この機能の UI を表示し、有効にすることができます。

var focusControl = _mediaCapture.VideoDeviceController.FocusControl;

if (focusControl.Supported)
{

    FocusLightCheckBox.Visibility = (_mediaCapture.VideoDeviceController.FlashControl.Supported &&
                                     _mediaCapture.VideoDeviceController.FlashControl.AssistantLightSupported) ? Visibility.Visible : Visibility.Collapsed;
}
else
{
    FocusLightCheckBox.Visibility = Visibility.Collapsed;
}

CheckedChanged イベント ハンドラーで、キャプチャ デバイスの FlashControl オブジェクトを取得します。 AssistantLightEnabled プロパティを設定して、フォーカス ライトを有効または無効にします。

private void FocusLightCheckBox_CheckedChanged(object sender, RoutedEventArgs e)
{
    var flashControl = _mediaCapture.VideoDeviceController.FlashControl;

    flashControl.AssistantLightEnabled = (FocusLightCheckBox.IsChecked == true);
}

ISO 速度

IsoSpeedControl によって、写真やビデオのキャプチャ時に使用される ISO 速度を設定できます。

この例では、スライダー コントロールを使って現在の露出補正値を調整し、チェック ボックスを使って自動 ISO 速度調整のオンとオフを切り替えます。

<Slider Name="IsoSlider" ValueChanged="IsoSlider_ValueChanged"/>
<TextBlock Text="{Binding ElementName=IsoSlider,Path=Value}" Visibility="{Binding ElementName=IsoSlider,Path=Visibility}"/>
<CheckBox Name="IsoAutoCheckBox" Content="Auto" Checked="IsoAutoCheckBox_CheckedChanged" Unchecked="IsoAutoCheckBox_CheckedChanged"/>

現在のキャプチャ デバイスで IsoSpeedControl がサポートされているかどうかを確認するには、Supported プロパティを確認します。 コントロールがサポートされている場合は、この機能の UI を表示し、有効にすることができます。 自動 ISO 速度調整が現在アクティブであるかどうかを示すために、チェック ボックスのオンの状態を Auto プロパティの値に設定します。

ISO 速度値は、デバイスでサポートされている範囲内である必要があり、サポートされているステップ サイズのインクリメントである必要があります。 現在のデバイスでサポートされている値を取得するには、MinMax、および Step プロパティを確認します。これらのプロパティは、対応するスライダー コントロールのプロパティを設定するために使用されます。

値が設定されたときにイベントがトリガーされないように、ValueChanged イベント ハンドラーの登録を解除した後、スライダー コントロールの値を IsoSpeedControl の現在値に設定します。

private void UpdateIsoControlCapabilities()
{
    var isoSpeedControl = _mediaCapture.VideoDeviceController.IsoSpeedControl;

    if (isoSpeedControl.Supported)
    {
        IsoAutoCheckBox.Visibility = Visibility.Visible;
        IsoSlider.Visibility = Visibility.Visible;

        IsoAutoCheckBox.IsChecked = isoSpeedControl.Auto;
        
        IsoSlider.Minimum = isoSpeedControl.Min;
        IsoSlider.Maximum = isoSpeedControl.Max;
        IsoSlider.StepFrequency = isoSpeedControl.Step;

        IsoSlider.ValueChanged -= IsoSlider_ValueChanged;
        IsoSlider.Value = isoSpeedControl.Value;
        IsoSlider.ValueChanged += IsoSlider_ValueChanged;
    }
    else
    {
        IsoAutoCheckBox.Visibility = Visibility.Collapsed;
        IsoSlider.Visibility = Visibility.Collapsed;
    }
}

ValueChanged イベント ハンドラーで、コントロールの現在の値を取得し、SetValueAsync を呼び出して ISO 速度を設定します。

private async void IsoSlider_ValueChanged(object sender, Windows.UI.Xaml.Controls.Primitives.RangeBaseValueChangedEventArgs e)
{
    var value = (sender as Slider).Value;
    await _mediaCapture.VideoDeviceController.IsoSpeedControl.SetValueAsync((uint)value);
}

自動 ISO 速度チェック ボックスの CheckedChanged イベント ハンドラーで、SetAutoAsync を呼び出すことによって、自動 ISO 速度調整をオンにします。 自動 ISO 速度調整をオフにするには、SetValueAsync を呼び出して、スライダー コントロールの現在の値を渡します。

private async void IsoAutoCheckBox_CheckedChanged(object sender, RoutedEventArgs e)
{
    var autoIso = (sender as CheckBox).IsChecked == true;

    if (autoIso)
    {
        await _mediaCapture.VideoDeviceController.IsoSpeedControl.SetAutoAsync();
    }
    else
    {
        await _mediaCapture.VideoDeviceController.IsoSpeedControl.SetValueAsync((uint)IsoSlider.Value);
    }
}

光学式手ブレ補正

光学式手ぶれ補正 (OIS) は、ハードウェア キャプチャ デバイスを機械的に操作して、キャプチャしたビデオ ストリームを安定させるもので、デジタルの手ぶれ補正を上回る結果を得られます。 OIS がサポートされていないデバイスでは、VideoStabilizationEffect を使用して、キャプチャしたビデオにデジタル手ブレ補正を行うことができます。 詳しくは、「ビデオ キャプチャの効果」をご覧ください。

現在のデバイスで OIS がサポートされているかどうかを確認するには、OpticalImageStabilizationControl.Supported プロパティをチェックします。

OIS コントロールでは、3 つのモード (オン、オフ、自動) がサポートされています。自動モードでは、OIS によってメディア キャプチャが改善されるかどうかをデバイスが動的に判断し、改善される場合は OIS が有効になります。 現在のデバイスで特定のモードがサポートされているかどうかを確認するには、OpticalImageStabilizationControl.SupportedModes コレクションに目的のモードが含まれているかどうかをチェックします。

OIS を有効または無効にするには、OpticalImageStabilizationControl.Mode を目的のモードに設定します。

private void SetOpticalImageStabilizationMode(OpticalImageStabilizationMode mode)
{
    if (!_mediaCapture.VideoDeviceController.OpticalImageStabilizationControl.Supported)
    {
        ShowMessageToUser("Optical image stabilization not available");
        return;
    }

    var stabilizationModes = _mediaCapture.VideoDeviceController.OpticalImageStabilizationControl.SupportedModes;

    if (!stabilizationModes.Contains(mode))
    {
        ShowMessageToUser("Optical image stabilization setting not supported");
        return;
    }

    _mediaCapture.VideoDeviceController.OpticalImageStabilizationControl.Mode = mode;
}

電源周波数

一部のカメラ デバイスでは、現在の環境の AC 電源周波数を認識し、それに応じたアンチフリッカー処理をサポートします。 電源周波数の自動認識をサポートするデバイスもあれば、周波数を手動で設定する必要があるデバイスもあります。 次のコード例は、デバイスの電源周波数のサポートを判別し、必要に応じて、周波数を手動で設定する方法を示します。

まず PowerlineFrequency 型の出力パラメーターを渡して VideoDeviceController メソッド TryGetPowerlineFrequency を呼び出します。この呼び出しが失敗した場合、現在のデバイスでは電源周波数の制御がサポートされていません。 機能がサポートされている場合、自動モードの設定を試みることで、自動モードがサポートされているかどうかを確認できます。 これを行うには、TrySetPowerlineFrequency を呼び出して、値 Auto で渡します。呼び出しに成功した場合、自動電源周波数機能がサポートされていることを意味します。 デバイスで電源周波数の制御はサポートされているが、周波数の自動検出はサポートされていない場合、TrySetPowerlineFrequency を使って周波数を手動で設定できます。 次の例で、MyCustomFrequencyLookup は、デバイスの現在の場所における正しい周波数を判定するために実装するカスタム メソッドです。

 PowerlineFrequency getFrequency;

 if (! _mediaCapture.VideoDeviceController.TryGetPowerlineFrequency(out getFrequency))
 {
     // Powerline frequency is not supported on this device.
     return;
 }

 if (! _mediaCapture.VideoDeviceController.TrySetPowerlineFrequency(PowerlineFrequency.Auto))
 {
     // Set the frequency manually
     PowerlineFrequency setFrequency = MyCustomFrequencyLookup();
     if (_mediaCapture.VideoDeviceController.TrySetPowerlineFrequency(setFrequency))
     {
         System.Diagnostics.Debug.WriteLine(String.Format("Powerline frequency manually set to {0}.", setFrequency));
     }
 }

ホワイト バランス

WhiteBalanceControl によって、写真やビデオのキャプチャ時に使用されるホワイト バランスを設定できます。

この例では、ComboBox コントロールを使って組み込みの色温度のプリセットを選択し、スライダー コントロールを使って手動でホワイト バランスを調整します。

<Slider Name="WbSlider" ValueChanged="WbSlider_ValueChanged"/>
<TextBlock Name="WbTextBox" Text="{Binding ElementName=WbSlider,Path=Value}" Visibility="{Binding ElementName=WbSlider,Path=Visibility}"/>
<ComboBox Name="WbComboBox" SelectionChanged="WbComboBox_SelectionChanged"/>

現在のキャプチャ デバイスで WhiteBalanceControl がサポートされているかどうかを確認するには、Supported プロパティを確認します。 コントロールがサポートされている場合は、この機能の UI を表示し、有効にすることができます。 コンボ ボックスの項目を、ColorTemperaturePreset 列挙体の値に設定します。 また、選ばれた項目を、Preset プロパティの現在の値に設定します。

手動コントロールの場合、ホワイト バランス値は、デバイスでサポートされている範囲内である必要があり、サポートされているステップ サイズのインクリメントである必要があります。 現在のデバイスでサポートされている値を取得するには、MinMax、および Step プロパティを確認します。これらのプロパティは、対応するスライダー コントロールのプロパティを設定するために使用されます。 手動コントロールを有効にする前に、サポートされている最小値と最大値の間の範囲がステップ サイズよりも大きいことを確認します。 このようになっていない場合、手動コントロールは、現在のデバイスではサポートされません。

値が設定されたときにイベントがトリガーされないように、ValueChanged イベント ハンドラーの登録を解除した後、スライダー コントロールの値を WhiteBalanceControl の現在値に設定します。

           var whiteBalanceControl = _mediaCapture.VideoDeviceController.WhiteBalanceControl;

           if (whiteBalanceControl.Supported)
           {
               WbSlider.Visibility = Visibility.Visible;
               WbComboBox.Visibility = Visibility.Visible;

               if (WbComboBox.ItemsSource == null)
               {
                   WbComboBox.ItemsSource = Enum.GetValues(typeof(ColorTemperaturePreset)).Cast<ColorTemperaturePreset>();
               }

               WbComboBox.SelectedItem = whiteBalanceControl.Preset;

               if (whiteBalanceControl.Max - whiteBalanceControl.Min > whiteBalanceControl.Step)
               {

                   WbSlider.Minimum = whiteBalanceControl.Min;
                   WbSlider.Maximum = whiteBalanceControl.Max;
                   WbSlider.StepFrequency = whiteBalanceControl.Step;

                   WbSlider.ValueChanged -= WbSlider_ValueChanged;
                   WbSlider.Value = whiteBalanceControl.Value;
                   WbSlider.ValueChanged += WbSlider_ValueChanged;
               }
               else
               {
                   WbSlider.Visibility = Visibility.Collapsed;
               }
           }
           else
           {
               WbSlider.Visibility = Visibility.Collapsed;
               WbComboBox.Visibility = Visibility.Collapsed;
           }

色温度プリセットのコンボ ボックスの SelectionChanged イベント ハンドラーで、現在選択されているプリセットを取得し、SetPresetAsync を呼び出してコントロールの値を設定します。 選択されたプリセット値が Manual でない場合は、手動のホワイト バランス スライダーを無効にします。

private async void WbComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
    if(!_isPreviewing)
    {
        // Do not set white balance values unless the preview stream is running.
        return;
    }

    var selected = (ColorTemperaturePreset)WbComboBox.SelectedItem;
    WbSlider.IsEnabled = (selected == ColorTemperaturePreset.Manual);
    await _mediaCapture.VideoDeviceController.WhiteBalanceControl.SetPresetAsync(selected);

}

ValueChanged イベント ハンドラーで、コントロールの現在の値を取得し、SetValueAsync を呼び出してホワイト バランス値を設定します。

private async void WbSlider_ValueChanged(object sender, Windows.UI.Xaml.Controls.Primitives.RangeBaseValueChangedEventArgs e)
{
    if (!_isPreviewing)
    {
        // Do not set white balance values unless the preview stream is running.
        return;
    }

    var value = (sender as Slider).Value;
    await _mediaCapture.VideoDeviceController.WhiteBalanceControl.SetValueAsync((uint)value);
}

重要

ホワイト バランスの調整は、プレビュー ストリームが実行中であるときにのみサポートされます。 ホワイト バランス値またはプリセットを設定する前に、プレビュー ストリームが実行されていることを確認します。

重要

ColorTemperaturePreset.Auto プリセット値は、ホワイト バランス レベルを自動調整するようにシステムに指示します。 ホワイト バランス レベルが各フレームで同じである必要がある写真シーケンスのキャプチャなど、一部のシナリオでは、現在の自動値にコントロールをロックすることもできます。 これを行うには、SetPresetAsync を呼び出して、Manual プリセットを指定します。SetValueAsync を使って、コントロールの値を設定しないでください。 これにより、デバイスは現在の値にロックされます。 現在のコントロールの値を読み取って、返された値を SetValueAsync に渡すことはしないでください。この値が正しいことは保証されないためです。

ズーム

ZoomControl によって、写真やビデオのキャプチャ時に使用されるズーム レベルを設定できます。

この例では、スライダー コントロールを使って、現在のズーム レベルを調整します。 次のセクションでは、画面上のピンチ ジェスチャに基づいてズームを調整する方法を示します。

<Slider Name="ZoomSlider" Grid.Row="0" Orientation="Vertical" HorizontalAlignment="Center" VerticalAlignment="Stretch" ValueChanged="ZoomSlider_ValueChanged"/>
<TextBlock Grid.Row="1" HorizontalAlignment="Center" Text="{Binding ElementName=ZoomSlider,Path=Value}"/>

現在のキャプチャ デバイスで ZoomControl がサポートされているかどうかを確認するには、Supported プロパティを確認します。 コントロールがサポートされている場合は、この機能の UI を表示し、有効にすることができます。

ズーム レベル値は、デバイスでサポートされている範囲内である必要があり、サポートされているステップ サイズのインクリメントである必要があります。 現在のデバイスでサポートされている値を取得するには、MinMax、および Step プロパティを確認します。これらのプロパティは、対応するスライダー コントロールのプロパティを設定するために使用されます。

値が設定されたときにイベントがトリガーされないように、ValueChanged イベント ハンドラーの登録を解除した後、スライダー コントロールの値を ZoomControl の現在値に設定します。

var zoomControl = _mediaCapture.VideoDeviceController.ZoomControl;

if (zoomControl.Supported)
{
    ZoomSlider.Visibility = Visibility.Visible;

    ZoomSlider.Minimum = zoomControl.Min;
    ZoomSlider.Maximum = zoomControl.Max;
    ZoomSlider.StepFrequency = zoomControl.Step;
    
    ZoomSlider.ValueChanged -= ZoomSlider_ValueChanged;
    ZoomSlider.Value = zoomControl.Value;
    ZoomSlider.ValueChanged += ZoomSlider_ValueChanged;
}
else
{
    ZoomSlider.Visibility = Visibility.Collapsed;
}

ValueChanged イベント ハンドラーで、Value プロパティをズーム スライダー コントロールの現在の値に設定して、ZoomSettings クラスの新しいインスタンスを作成します。 ZoomControlSupportedModes プロパティに ZoomTransitionMode.Smooth が含まれている場合、デバイスがズーム レベルのスムーズな切り替えをサポートしていることを意味します。 このモードではユーザー エクスペリエンスが向上するため、通常、ZoomSettings オブジェクトの Mode プロパティにはこの値を使います。

最後に、ZoomSettings オブジェクトを、ZoomControl オブジェクトの Configure メソッドに渡すことによって、現在のズーム設定を変更します。

private void ZoomSlider_ValueChanged(object sender, Windows.UI.Xaml.Controls.Primitives.RangeBaseValueChangedEventArgs e)
{
    var level = (float)ZoomSlider.Value;
    var settings = new ZoomSettings { Value = level };

    var zoomControl = _mediaCapture.VideoDeviceController.ZoomControl;
    if (zoomControl.SupportedModes.Contains(ZoomTransitionMode.Smooth))
    {
        settings.Mode = ZoomTransitionMode.Smooth;
    }
    else
    {
        settings.Mode = zoomControl.SupportedModes.First();
    }

    zoomControl.Configure(settings);
}

ピンチ ジェスチャを使ったスムーズなズーム

前のセクションで説明したように、スムーズ ズームがサポートされているキャプチャ デバイスでスムーズ ズーム モードを使用すると、異なるデジタル ズーム レベル間での切り替えがスムーズになります。これによりユーザーは、キャプチャ操作中にズーム レベルを動的に調整することができます。切り替えを個々に行う必要がなく、不快感もありません。 このセクションでは、ピンチ ジェスチャに応答してズーム レベルを調整する方法について説明します。

まず、ZoomControl.Supported プロパティをチェックして、現在のデバイスでデジタル ズーム コントロールがサポートされているかどうかを確認します。 次に、ZoomControl.SupportedModes の値として ZoomTransitionMode.Smooth が含まれているかどうかをチェックすることによって、スムーズ ズーム モードが利用可能かどうかを確認します。

private bool IsSmoothZoomSupported()
{
    if (!_mediaCapture.VideoDeviceController.ZoomControl.Supported)
    {
        ShowMessageToUser("Digital zoom is not supported on this device.");
        return false;
    }

    var zoomModes = _mediaCapture.VideoDeviceController.ZoomControl.SupportedModes;

    if (!zoomModes.Contains(ZoomTransitionMode.Smooth))
    {
        ShowMessageToUser("Smooth zoom not supported");
        return false;
    }

    return true;
}

マルチタッチ操作対応デバイスでは、2 本指でのピンチ ジェスチャに基づいてズーム倍率を調整するのが一般的です。 ピンチ ジェスチャを有効にするには、CaptureElement コントロールの ManipulationMode プロパティを ManipulationModes.Scale に設定します。 次に、ピンチ ジェスチャでサイズ変更されたときに発生する ManipulationDelta イベントを登録します。

private void RegisterPinchGestureHandler()
{
    if (!IsSmoothZoomSupported())
    {
        return;
    }

    // Enable pinch/zoom gesture for the preview control
    PreviewControl.ManipulationMode = ManipulationModes.Scale;
    PreviewControl.ManipulationDelta += PreviewControl_ManipulationDelta;
}

ManipulationDelta イベント用のハンドラーでは、ユーザーのピンチ ジェスチャの変化に基づいてズーム倍率を更新します。 ManipulationDelta.Scale 値は、ピンチ ジェスチャによるズーム倍率の変化を表します。たとえば、ピンチ サイズがわずかに大きくなった場合は 1.0 よりわずかに大きい数値、ピンチ サイズがわずかに小さくなった場合は 1.0 よりわずかに小さい数値になります。 この例では、ズーム コントロールの現在の値にスケール デルタを掛けています。

ズーム倍率を設定する前に、デバイスでサポートされている (ZoomControl.Min プロパティで示されている) 最小値より小さい値になっていないか確認する必要があります。 また、値が ZoomControl.Max 値以下であることを確認します。 最後に、ズーム倍率が、デバイスでサポートされているズーム ステップ サイズの倍数 (Step プロパティで示されている) になっていることを確認する必要があります。 ズーム倍率がこれらの要件を満たしていない場合は、キャプチャ デバイスでズーム レベルを設定しようとすると、例外がスローされます。

キャプチャ デバイスでズーム レベルを設定するには、新しい ZoomSettings オブジェクトを作成します。 Mode プロパティを ZoomTransitionMode.Smooth に設定し、Value プロパティを目的のズーム倍率に設定します。 最後に、ZoomControl.Configure を呼び出して、デバイスの新しいズーム値を設定します。 デバイスは新しいズーム値への切り替えをスムーズに行います。

private void PreviewControl_ManipulationDelta(object sender, ManipulationDeltaRoutedEventArgs e)
{
    var zoomControl = _mediaCapture.VideoDeviceController.ZoomControl;

    // Example zoom factor calculation based on size of scale gesture
    var zoomFactor = zoomControl.Value * e.Delta.Scale;

    if (zoomFactor < zoomControl.Min) zoomFactor = zoomControl.Min;
    if (zoomFactor > zoomControl.Max) zoomFactor = zoomControl.Max;
    zoomFactor = zoomFactor - (zoomFactor % zoomControl.Step);

    var settings = new ZoomSettings();
    settings.Mode = ZoomTransitionMode.Smooth;
    settings.Value = zoomFactor;

    _mediaCapture.VideoDeviceController.ZoomControl.Configure(settings);

}