Controles manuales de la cámara para la captura de fotos y vídeos

En este artículo se muestra cómo usar los controles manuales del dispositivo para habilitar escenarios mejorados de captura de fotos y vídeos, incluida la estabilización óptica de imagen y el zoom suave.

Todos los controles descritos en este artículo se agregan a la aplicación con el mismo patrón. En primer lugar, compruebe si el control es compatible con el dispositivo actual en el que se ejecuta la aplicación. Si el control es compatible, establezca el modo deseado para el control. Normalmente, si un control determinado no es compatible con el dispositivo actual, debe deshabilitar u ocultar el elemento de interfaz de usuario que permite al usuario habilitar la característica.

El código de este artículo se ha adaptado del ejemplo de SDK de controles manuales de la cámara. Puede descargar el ejemplo para ver el código usado en contexto o para usar el ejemplo como punto de partida para su propia aplicación.

Nota:

Este artículo se basa en los conceptos y el código analizados en Captura básica de fotos, audio y vídeo con MediaCapture, donde se describen los pasos para implementar la captura básica de fotos y vídeo. Se recomienda que te familiarices con el patrón de captura de multimedia básico de ese artículo antes de pasar a escenarios de captura más avanzados. El código que encontrarás en este artículo se ha agregado suponiendo que la aplicación ya tiene una instancia de MediaCapture inicializada correctamente.

Todas las API de control de dispositivos que se describen en este artículo forman parte del espacio de nombres Windows.Media.Devices.

using Windows.Media.Devices;

Exposición

ExposureControl permite establecer la velocidad del obturador utilizada durante la captura de fotos o vídeos.

En este ejemplo se usa un control deslizante para ajustar el valor de exposición actual y una casilla para alternar el ajuste automático de exposición.

<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"/>

Compruebe si el dispositivo de captura actual admite ExposureControl comprobando la propiedad Compatible. Si el control es compatible, puede mostrar y habilitar la interfaz de usuario para esta característica. Establezca el estado activado de la casilla para indicar si el ajuste de exposición automática está activo actualmente en el valor de la propiedad Automático.

El valor de exposición debe estar dentro del intervalo admitido por el dispositivo y debe ser un incremento del tamaño de paso admitido. Obtenga los valores admitidos para el dispositivo actual comprobando las propiedades Min, Max y Paso, que se usan para establecer las propiedades correspondientes del control deslizante.

Establezca el valor del control deslizante en el valor actual de ExposureControl después de anular el registro del controlador de eventos ValueChanged para que el evento no se desencadene cuando se establezca el valor.

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

En el controlador de eventos ValueChanged, obtenga el valor actual del control y establezca el valor de exposición llamando a 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);
}

En el controlador de eventos CheckedChanged de la casilla exposición automática, active o desactive el ajuste de exposición automática llamando a SetAutoAsync y pasando un valor booleano.

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

Importante

El modo de exposición automática solo se admite mientras se ejecuta la secuencia de vista previa. Asegúrese de que la secuencia de vista previa se está ejecutando antes de activar la exposición automática.

Compensación de exposición

ExposureCompensationControl permite establecer la compensación de exposición utilizada durante la captura de fotos o vídeos.

En este ejemplo se usa un control deslizante para ajustar el valor de compensación de exposición actual.

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

Compruebe si el dispositivo de captura actual admite ExposureCompensationControl comprobando la propiedad Compatible. Si el control es compatible, puede mostrar y habilitar la interfaz de usuario para esta característica.

El valor de compensación de exposición debe estar dentro del intervalo admitido por el dispositivo y debe ser un incremento del tamaño de paso admitido. Obtenga los valores admitidos para el dispositivo actual comprobando las propiedades Min, Max y Paso, que se usan para establecer las propiedades correspondientes del control deslizante.

Establezca el valor del control deslizante en el valor actual de ExposureCompensationControl después de anular el registro del controlador de eventos ValueChanged para que el evento no se desencadene cuando se establezca el valor.

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

En el controlador de eventos ValueChanged, obtenga el valor actual del control y establezca el valor de exposición llamando a 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);
}

Intermitente

FlashControl permite habilitar o deshabilitar el flash o habilitar el flash automático, en que el sistema determina dinámicamente si se debe usar el flash. Este control también permite habilitar la reducción automática de ojos rojos en los dispositivos que lo admiten. Esta configuración se aplica a la captura de fotos. TorchControl es un control independiente para encender o desactivar la linterna para la captura de vídeo.

En este ejemplo se usa un conjunto de botones de radio para permitir que el usuario cambie entre la configuración de encendido, apagado y flash automático. También se proporciona una casilla para permitir alternar la reducción de ojos rojos y la linterna de vídeo.

<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"/>

Compruebe si el dispositivo de captura actual admite FlashControl comprobando la propiedad Compatible. Si el control es compatible, puede mostrar y habilitar la interfaz de usuario para esta característica. Si se admite FlashControl, es posible que se admita o no se admita la reducción automática de ojos rojos, por lo que debe comprobar la propiedad RedEyeReductionSupported antes de habilitar la interfaz de usuario. Dado que TorchControl es independiente del control de flash, también debe comprobar su propiedad Compatible antes de usarlo.

En el controlador de eventos Comprobado de cada uno de los botones de radio del flash, habilite o deshabilite la configuración de flash correspondiente. Tenga en cuenta que para establecer el flash para que siempre se use, debe establecer la propiedad Habilitado en verdadero y la propiedad Automático en falso.

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

En el controlador de la casilla de reducción de ojos rojos, establezca la propiedad RedEyeReduction en el valor adecuado.

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

Por último, en el controlador de la casilla de linterna de vídeo, establezca la propiedad Habilitado en el valor adecuado.

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.");
    }
}

Nota:

En algunos dispositivos, la linterna no emitirá luz aunque TorchControl.Enabled está establecida en verdadero, a menos que el dispositivo tenga una secuencia de vista previa en ejecución y esté capturando vídeo activamente. El orden recomendado de las operaciones es activar la vista previa del vídeo, activar la linterna estableciendo Habilitado en true y, a continuación, iniciar la captura de vídeo. En algunos dispositivos, la linterna se encenderá una vez iniciada la vista previa. En otros dispositivos, la linterna puede no encenderse hasta que se inicie la captura de vídeo.

Foco

El objeto FocusControl, el enfoque automático continuo, el enfoque con un toque y el enfoque manual admiten tres métodos comunes para ajustar el foco de la cámara. Una aplicación de cámara puede admitir los tres métodos, pero para mejorar la legibilidad en este artículo se describe cada técnica por separado. En esta sección también se describe cómo habilitar la luz de asistencia de enfoque.

Autofoco continuo

Al habilitar el autofoco continuo, se indica a la cámara que ajuste el foco dinámicamente para intentar mantener enfocado el sujeto de la foto o el vídeo. En este ejemplo se usa un botón de radio para activar y desactivar el autofoco continuo.

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

Compruebe si el dispositivo de captura actual admite FocusControl comprobando la propiedad Compatible. A continuación, determine si se admite el autofoco continuo comprobando la lista SupportedFocusModes para ver si contiene el valor FocusMode.Continuous y, si es así, muestra el botón de radio de autofoco continuo.

var focusControl = _mediaCapture.VideoDeviceController.FocusControl;

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

En el controlador de eventos Checked para el botón de radio de autofoco continuo, use la propiedad VideoDeviceController.FocusControl para obtener una instancia del control. Llame a UnlockAsync para desbloquear el control en caso de que la aplicación haya llamado anteriormente a LockAsync para habilitar uno de los otros modos de enfoque.

Cree un nuevo objeto FocusSettings y establezca la propiedad Mode en Continuous. Establezca la propiedad AutoFocusRange en un valor adecuado para el escenario de la aplicación o seleccionado por el usuario desde la interfaz de usuario. Pase el objeto FocusSettings al método Configure y, a continuación, llame a FocusAsync para iniciar el autofoco continuo.

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

Importante

El modo de autofoco solo se admite mientras se ejecuta la secuencia de vista previa. Asegúrese de que la secuencia de vista previa se está ejecutando antes de activar el autofoco continuo.

Tocar para enfocar

La técnica de tocar para enfocar usa FocusControl y RegionsOfInterestControl para especificar una subdivisión del marco de captura donde el dispositivo de captura debe enfocar. La región de enfoque la determina el usuario que toca la pantalla en la que se muestra la secuencia de vista previa.

En este ejemplo se usa un botón de radio para habilitar y deshabilitar el modo de tocar para enfocar.

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

Compruebe si el dispositivo de captura actual admite FocusControl comprobando la propiedad Compatible. Se debe admitir RegionsOfInterestControl y al menos una región para poder usar esta técnica. Compruebe las propiedades AutoFocusSupported y MaxRegions para determinar si se va a mostrar u ocultar el botón de radio de pulsar para enfocar.

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

En el controlador de eventos Checked para el botón de radio de tocar para enfocar, use la propiedad VideoDeviceController.FocusControl para obtener una instancia del control. Llame a LockAsync para bloquear el control en caso de que la aplicación haya llamado previamente a UnlockAsync para habilitar el autofoco continuo y, a continuación, espere a que el usuario toque la pantalla para cambiar el foco.

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
}

En este ejemplo se enfoca una región cuando el usuario toca la pantalla y, a continuación, se quita el foco de esa región cuando el usuario vuelve a tocarla, como si se tratara de un botón de alternancia. Use una variable booleana para realizar un seguimiento del estado de alternancia actual.

bool _isFocused = false;

El siguiente paso consiste en escuchar el evento cuando el usuario toca la pantalla controlando el evento Tapped de CaptureElement que muestra actualmente la secuencia de vista previa de captura. Si la cámara no está mostrando actualmente la vista previa o si el modo de pulsar para enfocar está deshabilitado, vuelva desde el controlador sin hacer nada.

Si la variable de seguimiento _isFocused está en false y la cámara no está actualmente en el proceso de enfoque (determinado por la propiedad FocusState del FocusControl), inicie el proceso de tocar para enfocar. Obtenga la posición de la pulsación del usuario de los argumentos del evento pasados al controlador. En este ejemplo también se aprovecha la oportunidad para elegir el tamaño de la región que se enfocará. En este caso, el tamaño es 1/4 de la dimensión más pequeña del elemento de captura. Pase la posición de pulsación y el tamaño de la región al método auxiliar TapToFocus que se define en la sección siguiente.

Si el botón de alternancia _isFocused está establecido en true, la pulsación del usuario debe borrar el enfoque de la región anterior. Esto se hace en el método auxiliar TapUnfocus que se muestra a continuación.

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

En el método auxiliar TapToFocus, establezca primero el conmutador _isFocused en true para que el siguiente toque de la pantalla quite el enfoque de la región tocada.

La siguiente tarea de este método auxiliar es determinar el rectángulo dentro de la secuencia de vista previa que se asignará al control de enfoque. Esto requiere dos pasos. El primer paso es determinar el rectángulo que ocupa la secuencia de vista previa dentro del control CaptureElement. Esto depende de las dimensiones de la secuencia de vista previa y de la orientación del dispositivo. El método auxiliar GetPreviewStreamRectInControl, que se muestra al final de esta sección, realiza esta tarea y devuelve el rectángulo que contiene la secuencia de vista previa.

La siguiente tarea de TapToFocus es convertir la ubicación de pulsación y el tamaño del rectángulo de enfoque deseado, que se determinaron dentro del controlador de eventos CaptureElement.Tapped, en coordenadas dentro de la secuencia de captura. El método auxiliar ConvertUiTapToPreviewRect, que se muestra más adelante en esta sección, realiza esta conversión y devuelve el rectángulo, en coordenadas de flujo de captura, donde se solicitará el enfoque.

Ahora que se ha obtenido el rectángulo de destino, cree un nuevo objeto RegionOfInterest y establezca la propiedad Bounds en el rectángulo de destino obtenido en los pasos anteriores.

Obtenga el FocusControl del dispositivo de captura. Cree un nuevo objeto FocusSettings y establezca Mode y AutoFocusRange en los valores deseados, después de comprobar que son compatibles con FocusControl. Llame a Configure en FocusControl para activar la configuración e indicar al dispositivo que empiece a enfocar la región especificada.

A continuación, obtenga las regiones del dispositivo de captura RegionsOfInterestControl y llame a SetRegionsAsync para establecer la región activa. Se pueden establecer varias regiones de interés en los dispositivos que lo admiten, pero en este ejemplo solo se establece una región.

Por último, llame a FocusAsync en FocusControl para iniciar el enfoque.

Importante

Al implementar tocar para enfocar, es importante el orden de las operaciones. Debe llamar a estas API en el orden siguiente:

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

En el método auxiliar TapUnfocus, obtenga RegionsOfInterestControl y llame a ClearRegionsAsync para borrar la región registrada con el control dentro del método auxiliar TapToFocus. A continuación, obtenga FocusControl y llame a FocusAsync para que el dispositivo vuelva a enfocar sin una región de interés.

private async Task TapUnfocus()
{
    _isFocused = false;

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

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

El método auxiliar GetPreviewStreamRectInControl usa la resolución de la secuencia de vista previa y la orientación del dispositivo para determinar el rectángulo dentro del elemento de vista previa que contiene la secuencia de vista previa, recortando cualquier relleno de pantalla ancha que el control pueda proporcionar para mantener la relación de aspecto de la secuencia. Este método usa variables de miembro de clase definidas en el código de ejemplo de captura multimedia básica que se encuentra en Captura básica de fotos, vídeos y audio con 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;
}

El método auxiliar ConvertUiTapToPreviewRect toma como argumentos la ubicación del evento de pulsación, el tamaño deseado de la región de enfoque y el rectángulo que contiene la secuencia de vista previa obtenida del método auxiliar GetPreviewStreamRectInControl. Este método usa estos valores y la orientación actual del dispositivo para calcular el rectángulo dentro de la secuencia de vista previa que contiene la región deseada. De nuevo, este método usa variables de miembro de clase definidas en el código de ejemplo de captura multimedia básica que se encuentra en Captura de fotos y vídeos con 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);
}

Enfoque manual

La técnica de enfoque manual usa un control Slider para establecer la profundidad de enfoque actual del dispositivo de captura. Se usa un botón de radio para activar y desactivar el enfoque manual.

<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"/>

Compruebe si el dispositivo de captura actual admite FocusControl comprobando la propiedad Compatible. Si el control es compatible, puede mostrar y habilitar la interfaz de usuario para esta característica.

El valor de enfoque debe estar dentro del intervalo admitido por el dispositivo y debe ser un incremento del tamaño de paso admitido. Obtenga los valores admitidos para el dispositivo actual comprobando las propiedades Min, Max y Paso, que se usan para establecer las propiedades correspondientes del control deslizante.

Establezca el valor del control deslizante en el valor actual de FocusControl después de anular el registro del controlador de eventos ValueChanged para que el evento no se desencadene cuando se establezca el valor.

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

En el controlador de eventos Checked para el botón de radio de enfoque manual, obtenga el objeto FocusControl y llame a LockAsync en caso de que la aplicación haya desbloqueado previamente el enfoque con una llamada a UnlockAsync.

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

En el controlador de eventos ValueChanged del control deslizante de enfoque manual, obtenga el valor actual del control y establezca el valor de enfoque llamando a 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);
}

Habilitar la luz de enfoque

En los dispositivos que lo admiten, puede habilitar una luz de asistencia de enfoque para ayudar al enfoque del dispositivo. En este ejemplo se usa una casilla para habilitar o deshabilitar la luz de asistencia de enfoque.

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

Compruebe si el dispositivo de captura actual admite FlashControl comprobando la propiedad Compatible. Compruebe también AssistantLightSupported para asegurarse de que también se admite la luz de asistencia. Si ambos son compatibles, puede mostrar y habilitar la interfaz de usuario para esta característica.

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

En el controlador de eventos CheckedChanged, obtenga el objeto FlashControl de los dispositivos de captura. Establezca la propiedad AssistantLightEnabled para habilitar o deshabilitar la luz de enfoque.

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

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

Velocidad de ISO

IsoSpeedControl permite establecer la velocidad ISO utilizada durante la captura de fotos o vídeos.

En este ejemplo se usa un control deslizante para ajustar el valor de compensación de exposición actual y una casilla para alternar el ajuste automático de velocidad 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"/>

Compruebe si el dispositivo de captura actual admite IsoSpeedControl comprobando la propiedad Compatible. Si el control es compatible, puede mostrar y habilitar la interfaz de usuario para esta característica. Establezca el estado activado de la casilla para indicar si el ajuste de velocidad ISO automática está activo actualmente en el valor de la propiedad Automático.

El valor de velocidad ISO debe estar dentro del intervalo admitido por el dispositivo y debe ser un incremento del tamaño de paso admitido. Obtenga los valores admitidos para el dispositivo actual comprobando las propiedades Min, Max y Paso, que se usan para establecer las propiedades correspondientes del control deslizante.

Establezca el valor del control deslizante en el valor actual de IsoSpeedControl después de anular el registro del controlador de eventos ValueChanged para que el evento no se desencadene cuando se establezca el valor.

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

En el controlador de eventos ValueChanged, obtenga el valor actual del control y establezca el valor de velocidad ISO llamando a SetValueAsync.

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

En el controlador de eventos CheckedChanged de la casilla de velocidad ISO automática, active el ajuste automático de la velocidad ISO llamando a SetAutoAsync. Desactive el ajuste automático de la velocidad ISO llamando a SetValueAsync y pasando el valor actual del control deslizante.

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

Estabilización óptica de imágenes

La estabilización óptica de imágenes (OIS) estabiliza una secuencia de vídeo capturada manipulando mecánicamente el dispositivo de captura de hardware, lo que puede proporcionar un resultado superior a la estabilización digital. En los dispositivos que no admiten OIS, puede usar VideoStabilizationEffect para realizar la estabilización digital en el vídeo capturado. Para obtener más información, consulte Efectos para la captura de vídeo.

Determine si se admite OIS en el dispositivo actual comprobando la propiedad OpticalImageStabilizationControl.Supported.

El control OIS admite tres modos: activado, desactivado y automático, lo que significa que el dispositivo determina dinámicamente si OIS mejoraría la captura multimedia y, si es así, habilita OIS. Para determinar si se admite un modo determinado en un dispositivo, compruebe si la colección OpticalImageStabilizationControl.SupportedModes contiene el modo deseado.

Habilite o deshabilite OIS estableciendo OpticalImageStabilizationControl.Mode en el modo deseado.

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

Frecuencia de las líneas de alimentación

Algunos dispositivos de cámara admiten el procesamiento antiparpadeo que requiere conocer la frecuencia de CA de las líneas de alimentación en el entorno actual. Algunos dispositivos admiten la determinación automática de la frecuencia de la línea de alimentación, mientras que otros requieren que la frecuencia se establezca manualmente. En el ejemplo de código siguiente se muestra cómo determinar la compatibilidad con la frecuencia de la línea de alimentación en el dispositivo y, si es necesario, cómo establecer la frecuencia manualmente.

En primer lugar, llame al método VideoDeviceControllerTryGetPowerlineFrequency pasando un parámetro de salida de tipo PowerlineFrequency; si se produce un error en esta llamada, el control de frecuencia de la línea de alimentación no se admite en el dispositivo actual. Si se admite la característica, puede determinar si el modo automático está disponible en el dispositivo intentando establecer el modo automático. Para ello, llame a TrySetPowerlineFrequency y pase el valor Auto. Si la llamada se realiza correctamente, significa que se admite la frecuencia de la línea de alimentación automática. Si el controlador de frecuencia de la línea de alimentación se admite en el dispositivo, pero la detección automática de frecuencia no, todavía puede establecer manualmente la frecuencia mediante TrySetPowerlineFrequency. En este ejemplo, MyCustomFrequencyLookup es un método personalizado que se implementa para determinar la frecuencia correcta para la ubicación actual del dispositivo.

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

Balance de blancos

WhiteBalanceControl permite establecer el balance de blancos utilizado durante la captura de fotos o vídeos.

En este ejemplo se usa un control ComboBox para seleccionar entre los valores preestablecidos de temperatura de color integrados y un control Slider para el ajuste manual del balance de blancos.

<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"/>

Compruebe si el dispositivo de captura actual admite WhiteBalanceControl comprobando la propiedad Compatible. Si el control es compatible, puede mostrar y habilitar la interfaz de usuario para esta característica. Establezca los elementos del cuadro combinado en los valores de la enumeración ColorTemperaturePreset. Y establezca el elemento seleccionado en el valor actual de la propiedad Preset.

Para el control manual, el valor del balance de blancos debe estar dentro del intervalo admitido por el dispositivo y debe ser un incremento del tamaño de paso admitido. Obtenga los valores admitidos para el dispositivo actual comprobando las propiedades Min, Max y Paso, que se usan para establecer las propiedades correspondientes del control deslizante. Antes de habilitar el control manual, compruebe que el intervalo entre los valores mínimo y máximo admitidos es mayor que el tamaño del paso. Si no es así, el control manual no se admite en el dispositivo actual.

Establezca el valor del control deslizante en el valor actual de WhiteBalanceControl después de anular el registro del controlador de eventos ValueChanged para que el evento no se desencadene cuando se establezca el valor.

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

En el controlador de eventos SelectionChanged del cuadro combinado preestablecido de temperatura de color, obtenga el valor preestablecido seleccionado actualmente y establezca el valor del control llamando a SetPresetAsync. Si el valor preestablecido seleccionado no es Manual, deshabilite el control deslizante de balance de blancos 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);

}

En el controlador de eventos ValueChanged, obtenga el valor actual del control y establezca el valor de balance de blancos llamando a 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);
}

Importante

El ajuste del balance de blancos solo se admite mientras se ejecuta la secuencia de vista previa. Asegúrese de que la secuencia de vista previa se está ejecutando antes de establecer el valor del balance de blancos o el valor preestablecido.

Importante

El valor preestablecido ColorTemperaturePreset.Auto indica al sistema que ajuste automáticamente el nivel de balance de blancos. En algunos escenarios, como capturar una secuencia de fotos en la que los niveles de balance de blancos deben ser los mismos para cada fotograma, es posible que desee fijar el control en el valor automático actual. Para ello, llame a SetPresetAsync y especifique el valor preestablecido Manual y no establezca un valor en el control mediante SetValueAsync. Esto hará que el dispositivo fije el valor actual. No intente leer el valor de control actual y, a continuación, pasar el valor devuelto a SetValueAsync porque no se garantiza que este valor sea correcto.

Zoom

ZoomControl permite establecer el nivel de zoom utilizado durante la captura de fotos o vídeos.

En este ejemplo se usa un control Slider para ajustar el nivel de zoom actual. En la sección siguiente se muestra cómo ajustar el zoom en función de un gesto de reducir en la pantalla.

<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}"/>

Compruebe si el dispositivo de captura actual admite ZoomControl comprobando la propiedad Compatible. Si el control es compatible, puede mostrar y habilitar la interfaz de usuario para esta característica.

El valor de nivel de zoom debe estar dentro del intervalo admitido por el dispositivo y debe ser un incremento del tamaño de paso admitido. Obtenga los valores admitidos para el dispositivo actual comprobando las propiedades Min, Max y Paso, que se usan para establecer las propiedades correspondientes del control deslizante.

Establezca el valor del control deslizante en el valor actual de ZoomControl después de anular el registro del controlador de eventos ValueChanged para que el evento no se desencadene cuando se establezca el valor.

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

En el controlador de eventos ValueChanged, cree una nueva instancia de la clase ZoomSettings estableciendo la propiedad Value en el valor actual del control deslizante de zoom. Si la propiedad SupportedModes de ZoomControl contiene ZoomTransitionMode.Smooth, significa que el dispositivo admite transiciones suaves entre los niveles de zoom. Dado que estos modos proporcionan una mejor experiencia de usuario, normalmente querrá usar este valor para la propiedad Mode del objeto ZoomSettings.

Por último, cambie la configuración de zoom actual pasando el objeto ZoomSettings al método Configure del objeto ZoomControl.

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

Zoom suave mediante gesto de reducir

Como se explicó en la sección anterior, en los dispositivos que lo admiten, el modo de zoom suave permite al dispositivo de captura realizar una transición sin problemas entre los niveles de zoom digital, lo que permite al usuario ajustar dinámicamente el nivel de zoom durante la operación de captura sin transiciones discretas y molestas. En esta sección se describe cómo ajustar el nivel de zoom en respuesta a un gesto de reducir.

En primer lugar, determine si el control de zoom digital es compatible con el dispositivo actual comprobando la propiedad ZoomControl.Supported. A continuación, determine si el modo de zoom suave está disponible comprobando ZoomControl.SupportedModes para ver si contiene el valor 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;
}

En un dispositivo multitáctil habilitado, un escenario típico es ajustar el factor de zoom en función de un gesto de reducir con dos dedos. Establezca la propiedad ManipulationMode del control CaptureElement en ManipulationModes.Scale para habilitar el gesto de reducir. A continuación, regístrese para el evento ManipulationDelta que se genera cuando el gesto de reducir cambia el tamaño.

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

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

En el controlador del evento ManipulationDelta, actualice el factor de zoom en función del cambio en el gesto de reducir del usuario. El valor ManipulationDelta.Scale representa el cambio en la escala del gesto de reducir, de modo que un pequeño aumento del tamaño del gesto es un número ligeramente mayor que 1,0 y una pequeña disminución en el tamaño del gesto es un número ligeramente menor que 1,0. En este ejemplo, el valor actual del control de zoom se multiplica por la diferencia de escala.

Antes de establecer el factor de zoom, debe asegurarse de que el valor no sea menor que el valor mínimo admitido por el dispositivo, como se indica en la propiedad ZoomControl.Min. Además, asegúrese de que el valor sea menor o igual que el valor ZoomControl.Max. Por último, debe asegurarse de que el factor de zoom sea un múltiplo del tamaño del paso de zoom admitido por el dispositivo, como se indica en la propiedad Step. Si el factor de zoom no cumple estos requisitos, se producirá una excepción al intentar establecer el nivel de zoom en el dispositivo de captura.

Establezca el nivel de zoom en el dispositivo de captura mediante la creación de un nuevo objeto ZoomSettings. Establezca la propiedad Mode en ZoomTransitionMode.Smooth y, a continuación, establezca la propiedad Value en el factor de zoom deseado. Por último, llame a ZoomControl.Configure para establecer el nuevo valor de zoom en el dispositivo. El dispositivo pasará sin problemas al nuevo valor de zoom.

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

}