How to use camera focus in an app for Windows Phone 8

[ This article is for Windows Phone 8 developers. If you’re developing for Windows 10, see the latest documentation. ]

Starting with Windows Phone OS 7.1, you can programmatically access the phone’s camera using the Microsoft.Devices..::.PhotoCamera class. This topic describes how to programmatically initiate autofocus and enable touch-focus functionality in your Windows Phone app. It is a continuation of How to create a base camera app for Windows Phone 8 and assumes you have already created the base camera project in that topic.

Tip

Starting with Windows Phone 8, apps can use the PhotoCaptureDevice class for advanced capture scenarios. PhotoCaptureDevice allows apps to control photo properties such as ISO, exposure compensation, and manual focus position (when available on the phone). This topic doesn’t demonstrate PhotoCaptureDevice; for more info about this class, see Advanced photo capture for Windows Phone 8.

This topic corresponds to the Basic Camera Sample.

This topic contains the following sections.

Initiating autofocus

In this section, you add a button to the UI and add the necessary logic in the code-behind file to initiate autofocus when the AF button is tapped. The event handlers for the AF button are added in the OnNavigatedTo method and removed in the OnNavigatingFrom method. Not all phones support autofocus, so the IsFocusSupported property is used to check if the API is available. Attempting to focus while a capture is in progress will cause an exception; use try/catch syntax with calls to the Focus()()() method.

To initiate autofocus

  1. Open your base camera project created in How to create a base camera app for Windows Phone 8.

  2. In the main page XAML file, MainPage.xaml, add the following code in the StackPanel element, after the Button element named ShutterButton. This code is the button for camera focus.

    <Button Name="AFButton" Content="AF" Click="focus_Clicked" FontSize="26" FontWeight="ExtraBold" Height="75"/>
    

    When this button is clicked, it calls the focus_Clicked method, a method that is created later in this topic.

Note

The software autofocus button in this exercise is only for demonstrating programmatic access to the PhotoCamera API. To optimize the experience for the app user, we recommend that your app uses the hardware shutter button on the camera for this functionality. For info about how to implement the hardware shutter button, see How to access the hardware camera shutter button in Windows Phone 8.

  1. In the code-behind file for the main page, MainPage.xaml.cs, add the following code to the OnNavigatedTo(NavigationEventArgs) method. This code implements the AutoFocusCompleted event handler.

    
    // The event is fired when autofocus is complete.
    cam.AutoFocusCompleted += new EventHandler<CameraOperationCompletedEventArgs>(cam_AutoFocusCompleted);
    
    ' The event is fired when autofocus is complete.
    AddHandler cam.AutoFocusCompleted, AddressOf cam_AutoFocusCompleted
    
  2. In MainPage.xaml.cs, add the following code to the OnNavigatedTo method, just after the Disable UI comment.

    AFButton.IsEnabled = false;
    
    AFButton.IsEnabled = False
    

    This code disables the autofocus button. It’s used when a camera isn’t available on the phone.

  3. In MainPage.xaml.cs, add the following code to the OnNavigatingFrom(NavigatingCancelEventArgs) method after calling the Dispose method. This code helps release memory related to the camera.

    cam.AutoFocusCompleted -= cam_AutoFocusCompleted;
    
    RemoveHandler cam.AutoFocusCompleted, AddressOf cam_AutoFocusCompleted
    
  4. In MainPage.xaml.cs, add the following code to the MainPage class. This code implements the event handler for the focus_Clicked event by initiating the camera focus operation.

        // Provide autofocus in the viewfinder.
        private void focus_Clicked(object sender, System.Windows.RoutedEventArgs e)
        {
            if (cam.IsFocusSupported == true)
            {
                //Focus when a capture is not in progress.
                try
                {
                    cam.Focus();
                }
                catch (Exception focusError)
                {
                    // Cannot focus when a capture is in progress.
                    this.Dispatcher.BeginInvoke(delegate()
                    {
                        txtDebug.Text = focusError.Message;
                    });
                }
            }
            else
            {
                // Write message to UI.
                this.Dispatcher.BeginInvoke(delegate()
                {
                    txtDebug.Text = "Camera does not support programmable autofocus.";
                });
            }
        }
    
        'Provide autofocus in the viewfinder.
        Private Sub focus_Clicked(ByVal sender As Object, ByVal e As System.Windows.RoutedEventArgs)
    
            If cam.IsFocusSupported = True Then
                ' Focus when a capture is not in progress.
                Try
                    cam.Focus()
    
                Catch focusError As Exception
                    ' Cannot focus when a capture is in progress.
                    Me.Dispatcher.BeginInvoke(Sub() txtDebug.Text = focusError.Message)
    
                End Try
            Else
                ' Write message to UI.
                Me.Dispatcher.BeginInvoke(Sub() txtDebug.Text = "Camera does not support programmable autofocus.")
    
            End If
        End Sub
    
  5. In MainPage.xaml.cs, add the following code to the MainPage class. This code implements the AutoFocusCompleted event handler to write a message to the TextBlock named txtDebug. The BeginInvoke method is required because the UI of the app runs on a different thread.

Note

The AutoFocusCompleted event occurs after the focus operation is completed. Both methods, Focus()()() and FocusAtPoint(Double, Double), initiate the focus operation.

``` csharp
    void cam_AutoFocusCompleted(object sender, CameraOperationCompletedEventArgs e)
    {
        Deployment.Current.Dispatcher.BeginInvoke(delegate()
        {
            // Write message to UI.
            txtDebug.Text = "Autofocus has completed.";

        });
    }
```

``` vb
    Private Sub cam_AutoFocusCompleted(ByVal sender As Object, ByVal e As CameraOperationCompletedEventArgs)

        Me.Dispatcher.BeginInvoke(Sub()
                                      ' Write message to UI.
                                      txtDebug.Text = "Autofocus has completed."

                                  End Sub)

    End Sub
```
  1. On a phone, run the app by selecting the Debug | Start Debugging menu command.

Enabling touch-focus with FocusAtPoint

In this section, you add some brackets to the UI (to show where the viewfinder was tapped) and add the necessary logic in the code-behind file to initiate a focus at the point where the viewfinder was tapped. The FocusAtPoint(Double, Double) method is used to implement touch focus.

The event handlers for the canvas tap are added in the OnNavigatedTo method. Not all phones support focus at point, so the IsFocusAtPointSupported property is used to check if the API is available. Attempting to focus while a capture is in progress will cause an exception; use try/catch syntax with calls to the FocusAtPoint(Double, Double) method.

Note

This section assumes you have already completed the previous section, Initiating Autofocus.

To implement touch focus

  1. In the main page XAML file, MainPage.xaml, add the following code within the Canvas control, below the Canvas.Background element that contains the video brush named viewfinderBrush.

                <!-- Brackets for Touch Focus -->
                <TextBlock 
                    x:Name="focusBrackets" 
                    Text="[   ]" 
                    FontSize="40"
                    Visibility="Collapsed"/>
    

    This code is a TextBlock element that contains brackets that are used to indicate where a focus is occurring. The brackets are only shown when the camera is focusing.

  2. In the code-behind file for the main page, MainPage.xaml.cs, add the following code to the OnNavigatedTo(NavigationEventArgs) method.

        // The event is fired when the viewfinder is tapped (for focus).
        viewfinderCanvas.Tap += new EventHandler<GestureEventArgs>(focus_Tapped);
    
        ' The event is fired when the viewfinder is tapped (for focus).
        AddHandler viewfinderCanvas.Tap, AddressOf focus_Tapped
    

    This code handles the event handler for the canvas tap. When the user taps on the viewfinder to initiate touch focus, the focus_Tapped method is called.

  3. On MainPage.xaml.cs, add the following code to the MainPage class.

            // Provide touch focus in the viewfinder.
            void focus_Tapped(object sender, GestureEventArgs e)
            {
                if (cam != null)
                {
                    if (cam.IsFocusAtPointSupported == true)
                    {
                        try
                        {
                            // Determine the location of the tap.
                            Point tapLocation = e.GetPosition(viewfinderCanvas);
    
                            // Position the focus brackets with the estimated offsets.
                            focusBrackets.SetValue(Canvas.LeftProperty, tapLocation.X - 30);
                            focusBrackets.SetValue(Canvas.TopProperty, tapLocation.Y - 28);
    
                            // Determine the focus point.
                            double focusXPercentage = tapLocation.X / viewfinderCanvas.Width;
                            double focusYPercentage = tapLocation.Y / viewfinderCanvas.Height;
    
                            // Show the focus brackets and focus at point.
                            focusBrackets.Visibility = Visibility.Visible;
                            cam.FocusAtPoint(focusXPercentage, focusYPercentage);
    
                            // Write a message to the UI.
                            this.Dispatcher.BeginInvoke(delegate()
                            {
                                txtDebug.Text = String.Format("Camera focusing at point: {0:N2} , {1:N2}", focusXPercentage, focusYPercentage);
                            });
                        }
                        catch (Exception focusError)
                        {
                            // Cannot focus when a capture is in progress.
                            this.Dispatcher.BeginInvoke(delegate()
                            {
                                // Write a message to the UI.
                                txtDebug.Text = focusError.Message;
                                // Hide focus brackets.
                                focusBrackets.Visibility = Visibility.Collapsed;
                            });
                        }
                    }
                    else
                    {
                        // Write a message to the UI.
                        this.Dispatcher.BeginInvoke(delegate()
                        {
                            txtDebug.Text = "Camera does not support FocusAtPoint().";
                        });
                    }
                }
            }
    
        ' Provide touch focus in the viewfinder.
        Private Sub focus_Tapped(ByVal sender As Object, ByVal e As GestureEventArgs)
            If cam IsNot Nothing Then
                If cam.IsFocusAtPointSupported = True Then
    
                    Try
                        ' Determine the location of the tap.
                        Dim tapLocation As Point = e.GetPosition(viewfinderCanvas)
    
                        ' Position the focus brackets with the estimated offsets.
                        focusBrackets.SetValue(Canvas.LeftProperty, tapLocation.X - 30)
                        focusBrackets.SetValue(Canvas.TopProperty, tapLocation.Y - 28)
    
                        ' Determine the focus point.
                        Dim focusXPercentage As Double = tapLocation.X / viewfinderCanvas.Width
                        Dim focusYPercentage As Double = tapLocation.Y / viewfinderCanvas.Height
    
    
                        ' Show the focus brackets and focus at point.
                        focusBrackets.Visibility = Visibility.Visible
                        cam.FocusAtPoint(focusXPercentage, focusYPercentage)
    
                        ' Write a message to the UI.
                        Me.Dispatcher.BeginInvoke(Sub() txtDebug.Text =
                            String.Format("Camera focusing at point: {0:N2} , {1:N2}", focusXPercentage, focusYPercentage))
    
                    Catch focusError As Exception
    
                        ' Cannot focus when a capture is in progress.
                        Me.Dispatcher.BeginInvoke(Sub()
                                                      ' Write message to UI.
                                                      txtDebug.Text = focusError.Message
    
                                                      ' Hide focus brackets.
                                                      focusBrackets.Visibility = Windows.Visibility.Collapsed
                                                  End Sub)
                    End Try
    
                Else
                    ' Write a message to the UI.
                    Me.Dispatcher.BeginInvoke(Sub() txtDebug.Text =
                        String.Format("Camera does not support FocusAtPoint()."))
    
                End If
            End If
        End Sub
    

    This code enables touch focus by positioning the focus brackets (using estimated coordinates), determining the focus points, showing the focus brackets, and initiating focus at a point corresponding to the tap location.

    The X and Y position of the brackets correspond to the top-left of the TextBlock control. When positioning the brackets, some amount is subtracted from the coordinates to better position the brackets “around” the tap location.

    The FocusAtPoint(Double, Double) method parameters are based on a percentage of the image. To simplify this code, the camera viewfinder image was deliberately displayed on the same control that would trigger the tap event, the Canvas control named viewfinderCanvas. With this approach, the coordinates from the GestureEventArgs passed to the focus_Tapped method are directly relative to the Canvas control width and height.

  4. In MainPage.xaml.cs, add the following code to the cam_AutoFocusCompleted method, within the BeginInvoke call and just after the txtDebug statement.

        // Hide the focus brackets.
        focusBrackets.Visibility = Visibility.Collapsed;
    
        ' Hide the focus brackets.
        focusBrackets.Visibility = Windows.Visibility.Collapsed
    

    This code hides the focus brackets after the focus operation has completed.

See Also

Other Resources

Advanced photo capture for Windows Phone 8

Capturing video for Windows Phone 8

Lenses for Windows Phone 8

How to use the camera capture task for Windows Phone 8