CameraService

The ICameraService allows a developer to use the PhotoCamera class in an MVVM manner.

It is important that the service must be started and stopped to retrieve values

There is also an article available about this service: WP7 Mango and Unit Testing the Camera

Starting and stopping the service

The PhotoCamera documentation continuously states that the camera object must be created and disposed properly. In the service, this is encapsulated by the Start and Stop methods. To start the service, use the code below:

var dependencyResolver = this.GetDependencyResolver();
var cameraService = dependencyResolver.Resolve<ICameraService>();
cameraService.CaptureThumbnailAvailable += OnCameraServiceCaptureThumbnailAvailable;
cameraService.CaptureImageAvailable += OnCameraServiceCaptureImageAvailable;
cameraService.Start();

To stop the service, use the code below: (note: the Close method on a view model is feature of Catel):

protected override void Close()
{
    var dependencyResolver = this.GetDependencyResolver();
    var cameraService = dependencyResolver.Resolve<ICameraService>();
    cameraService.Stop();
    cameraService.CaptureThumbnailAvailable -= OnCameraServiceCaptureThumbnailAvailable;
    cameraService.CaptureImageAvailable -= OnCameraServiceCaptureImageAvailable;
}

Capturing images

To capture images, several things must be done. The first action to accomplish is to subscribe to the ICameraService.CaptureImageAvailable event. The next step is to invoke the CaptureImage method like shown below:

CameraService.CaptureImage();

The last part is very important. You will need to read the image stream from the CaptureImageAvailable event:

BitmapImage bitmap = new BitmapImage();
bitmap.SetSource(e.ImageStream);

Showing a video of camera in a view

To show a preview of the camera input on the phone, first subscribe to the ICameraService.CaptureThumbnailImageAvailable event. Next step is to create a property on the view model:

/// <summary>
/// Gets or sets the current photo.
/// </summary>
public BitmapImage CurrentPhoto
{
    get { return GetValue<BitmapImage>(CurrentPhotoProperty); }
    set { SetValue(CurrentPhotoProperty, value); }
}


/// <summary>
/// Register the CurrentPhoto property so it is known in the class.
/// </summary>
public static readonly PropertyData CurrentPhotoProperty = RegisterProperty("CurrentPhoto", typeof(BitmapImage));

This property definition is a Catel property, but if you prefer using a different MVVM framework or your own property definition style, you are free to do that as well.

In the view, use the Image control to show the current photo:

<Image Grid.Row="0" Source="{Binding CurrentPhoto}" />

Last but not least, we need to update the CurrentPhoto property when a new thumbnail is available.

private void OnCameraServiceCaptureThumbnailAvailable(object sender, ContentReadyEventArgs e)
{
    BitmapImage bitmap = new BitmapImage();
    bitmap.SetSource(e.ImageStream);
    CurrentPhoto = bitmap;
}

Instantiating the test implementation

The test implementation of the ICameraService needs to be instantiated with an image. The service will use this image to create an animation. The animation that will be applied is the image scrolling to the right pixel by pixel.

To instantiate the test service, add an image to the Windows Phone project and set its build action to Resource. Then instantiate the service like in the code below:

var testImage = new BitmapImage();
var streamResourceInfo = Application.GetResourceStream(new Uri("/MyAssembly;component/Resources/Images/MyImage.png", UriKind.RelativeOrAbsolute));
testImage.CreateOptions = BitmapCreateOptions.None;
testImage.SetSource(streamResourceInfo.Stream);
_testCameraService = new CameraService(testImage);
serviceLocator.RegisterInstance<ICameraService>(_testCameraService);

By default, the ICameraService will generate a new thumbnail image every 50 milliseconds. It is possible to customize this with a constructor overload.

Customizing camera settings for testing

Sometimes it is required to test different resolutions. One way to do this is to buy all available Windows Phone devices and test the software on all the cameras. An easier way is to use the ICameraService and customize the camera options to test how the application responds to the different settings.

The settings are stored in the CameraServiceTestData class. This class allows customizing all the properties normally found on the PhotoCamera class. For example, to only allow the primary camera (because front facing cameras are not supported by all devices), use the following code:

var cameraTestSettings = new CameraServiceTestData();
cameraTestSettings.SupportedCameraTypes = CameraType.Primary;
cameraService.UpdateTestData(cameraTestSettings);

It is also possible to change the thumbnail and final resolution of the images:

var cameraTestSettings = new CameraServiceTestData();
cameraTestSettings.PreviewResolution = new Size(400, 800);
cameraTestSettings.Resolution = new Size(1200, 2400);
cameraService.UpdateTestData(cameraTestSettings);