Advanced photo capture for Windows Phone 8

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

This topic describes how you can use the Windows.Phone.Media.Capture APIs for advanced photo capture scenarios. It describes the classes you need to use, and the primary steps that are required to capture a photo. The API provides a variety of camera and photo properties that you can use to fine-tune your app’s photography. Compared to the PhotoCamera API, Windows.Phone.Media.Capture offers better managed code performance and provides methods for native code. For more info, see Advanced capture properties for Windows Phone 8 and Camera APIs for native code (Windows Phone 8).

This topic contains the following sections.

Class overview

Here are some of the classes you can use to capture photos and save them to the media library.

Class

Description

PhotoCaptureDevice

A capture device represents the camera. This capture device is for capturing photos. Use the AudioVideoCaptureDevice class for capturing video.

CameraCaptureSequence

A capture sequence is a unit of work for capturing frames.

CameraCaptureFrame

A frame represents a photo in a capture sequence.

KnownCameraGeneralProperties

Gets/sets general camera properties.

KnownCameraPhotoProperties

Gets/sets photo properties.

MediaLibrary

Used to save photos to the phone’s media library.

MemoryStream

A stream used to copy image data from a frame to the media library.

Directives and capabilities

When using these classes, add the following directives to new Windows Phone projects.

// Directives
using Windows.Phone.Media.Capture;   // For advanced capture APIs
using Microsoft.Xna.Framework.Media; // For the media library
using System.IO;                     // For the memory stream

To access the camera and media library, you need to specify capabilities in the app manifest file, WMAppManifest.xml. The following capabilities provide access to the front and back camera and media library in Windows Phone 8.

<Capability Name="ID_CAP_ISV_CAMERA"/>
<Capability Name="ID_CAP_MEDIALIB_PHOTO"/>

There are additional capabilities and hardware requirements that you may want to consider adding to your camera app. For more info, see App capabilities and hardware requirements for Windows Phone 8.

Creating the capture device

To create a photo capture device object, use the OpenAsync method. This method requires you to specify the camera that you want to use (using the CameraSensorLocation enumeration) and the initial capture resolution of the camera. The initial preview resolution is automatically assigned based on the initial capture resolution and the screen resolution of the phone. Later on, you can set the resolution with the SetCaptureResolutionAsync and SetPreviewResolutionAsync methods. To find out which resolutions are available on the phone, use the GetAvailableCaptureResolutions and GetAvailablePreviewResolutions methods.

The following example uses the first item in the supportedResolutions list to create the photo capture device.

// Check to see if the camera is available on the device.
if (PhotoCaptureDevice.AvailableSensorLocations.Contains(CameraSensorLocation.Back) ||
    PhotoCaptureDevice.AvailableSensorLocations.Contains(CameraSensorLocation.Front))
{
    // Initialize the camera, when available.
    if (PhotoCaptureDevice.AvailableSensorLocations.Contains(CameraSensorLocation.Back))
    {
        // Use the back camera.
        System.Collections.Generic.IReadOnlyList<Windows.Foundation.Size> SupportedResolutions = 
            PhotoCaptureDevice.GetAvailableCaptureResolutions(CameraSensorLocation.Back);
        Windows.Foundation.Size res = SupportedResolutions[0];
        this.captureDevice = await PhotoCaptureDevice.OpenAsync(CameraSensorLocation.Back, res);
    }
    else
    {
        // Otherwise, use the front camera.
        System.Collections.Generic.IReadOnlyList<Windows.Foundation.Size> SupportedResolutions = 
            PhotoCaptureDevice.GetAvailableCaptureResolutions(CameraSensorLocation.Front);
        Windows.Foundation.Size res = SupportedResolutions[0];
        this.captureDevice = await PhotoCaptureDevice.OpenAsync(CameraSensorLocation.Front, res);
    }
    ...
    ...
    ...

    //Set the VideoBrush source to the camera.
    viewfinderBrush.SetSource(this.captureDevice);

    // The event is fired when the shutter button receives a half press.
    CameraButtons.ShutterKeyHalfPressed += OnButtonHalfPress;

    // The event is fired when the shutter button receives a full press.
    CameraButtons.ShutterKeyPressed += OnButtonFullPress;

    // The event is fired when the shutter button is released.
    CameraButtons.ShutterKeyReleased += OnButtonRelease; }
else
{
    // The camera is not available.
    this.Dispatcher.BeginInvoke(delegate()
    {
        // Write message.
        txtDebug.Text = "A Camera is not available on this phone.";
    });
}

Cameras on Windows Phone are optional, so all apps need to check the phone to see if a camera exists. You can use the static property PhotoCaptureDeviceAvailableSensorLocations()()() to check for cameras, as shown in this example.

Creating the capture sequence

The capture sequence is the unit of work that is sent to the phone’s CPU. You use it to define what you want to happen when you initiate the capture. The capture sequence is created from a method on the photo capture device. The only parameter that you need to specify is the number of frames that you want to be included in the sequence. In this release, that value will always be 1. When you initiate the capture, the frame will be captured immediately.

Note

In this release, the CameraCaptureSequence class supports only single-frame capture. As a result, you must specify a single frame when you call the CreateCaptureSequence method.

The following example shows how to create a capture sequence.

// Create a capture sequence object with 1 frame.
CameraCaptureSequence seq;
seq = cam.CreateCaptureSequence(1);

Specifying camera properties

When capturing photos, you can use the KnownCameraGeneralProperties and the KnownCameraPhotoProperties methods to specify camera and photo settings. Use the SetProperty method to set properties that affect all frames in the capture sequence. For more info about what properties are available, see Advanced capture properties for Windows Phone 8.

Note

Not all properties are supported by each phone. Use the GetSupportedPropertyValues or the GetSupportedPropertyRange method to determine which property values you can use.

The following code shows some settings that are applied to the capture device. These properties are applied to the frame in the capture sequence.

// Set camera properties.
cam.SetProperty(KnownCameraPhotoProperties.FlashMode, FlashState.On);
cam.SetProperty(KnownCameraGeneralProperties.PlayShutterSoundOnCapture, true);
cam.SetProperty(KnownCameraGeneralProperties.AutoFocusRange, AutoFocusRange.Infinity);

Specifying frame properties

You can also set properties on an individual frame.

// Set the frame properties.
seq.Frames[0].DesiredProperties[KnownCameraPhotoProperties.SceneMode] 
   = CameraSceneMode.Portrait;

The DesiredProperties property is like a “wish list.” Each phone is limited in the number and combinations of properties that it can apply to frames; properties specified with DesiredProperties are not guaranteed. To see which properties were actually used after the capture, use the frame’s AppliedProperties property.

Important Note:

The PrepareCaptureSequenceAsync method must follow all DesiredProperties assignments. If you change a property after you prepare the capture sequence, you need to call PrepareCaptureSequenceAsync again.

Assigning a capture stream

You can work with a frame from managed or native code. From managed code, use the frame’s CaptureStream property to assign the frame’s image data to a memory stream. A memory stream can be used to route image data to the media library.

MemoryStream captureStream1 = new MemoryStream();

// Assign the capture stream.
seq.Frames[0].CaptureStream = captureStream1.AsOutputStream();

Tip

Use the ThumbnailStream property if you want to display a thumbnail image of the frame after it has been captured.

Preparing the capture sequence

Before you can capture a frame, you need to prepare the capture sequence. You do this by calling the PrepareCaptureSequenceAsync method. This sends the configuration data to the CPU. Note that if you change a property after preparing the capture sequence, you must call PrepareCaptureSequenceAsync again.

// Prepare the capture sequence.
await cam.PrepareCaptureSequenceAsync(seq);

Capturing a frame and saving it to the media library

When the user is ready to take a photo, start the capture with the StartCaptureAsync method. The await keyword asynchronously “waits” for the capture to complete. When that code is returned, you can perform operations on the frame data. In this example, the capture stream from the frame is used to save an image to the Camera Roll folder in the media library.

public async void Capture()
{
   await seq.StartCaptureAsync();

   // Set the stream position to the beginning.
   captureStream1.Seek(0, SeekOrigin.Begin);

   MediaLibrary library = new MediaLibrary();
   Picture picture1 = library.SavePictureToCameraRoll("image1", captureStream1);

}

Like many APIs that use streams, the MediaLibrary class does not manipulate the current position of the stream before acting on it. This allows you to use a subset of the stream, if desired. In this example, the Seek method is used to set the position of the stream back to the beginning so that the whole image is saved to the Camera Roll folder.

If you intend to reuse a MemoryStream object after a capture, it is important to set the length of the stream to zero using SetLength. If you don’t, the next capture will be appended to the end of the stream.

Tip

Use the MediaLibrarySavePicture()()() method to save pictures to the Saved Pictures folder in the media library.

Additional capture methods for native code

Windows Phone 8 provides additional capture methods that you can use with native code. For more info, see Camera APIs for native code (Windows Phone 8).