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
- Directives and capabilities
- Creating the capture device
- Creating the capture sequence
- Specifying camera properties
- Specifying frame properties
- Assigning a capture stream
- Preparing the capture sequence
- Capturing a frame and saving it to the media library
- Additional capture methods for native code
Class overview
Here are some of the classes you can use to capture photos and save them to the media library.
Class |
Description |
---|---|
A capture device represents the camera. This capture device is for capturing photos. Use the AudioVideoCaptureDevice class for capturing video. |
|
A capture sequence is a unit of work for capturing frames. |
|
A frame represents a photo in a capture sequence. |
|
Gets/sets general camera properties. |
|
Gets/sets photo properties. |
|
Used to save photos to the phone’s media library. |
|
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).