Hey guys!
One of my latest Windows (Phone) 8.1 projects includes taking photos. It can be done quite easy with the CameraCaptureTask. Unfortunately this is only working on Windows Phone 8 and Windows Phone 8.1 (Silverlight). If you want to build Universal Apps you have to use the Windows Runtime which doesn't have this API.
To enable your app to take photos in the Windows Runtime you have to use the MediaCapture class in the Windows.Media.Capture namespace. You will have to do a little more work but once you write it for Windows Phone you just stick it into the Shared folder and you can use it in the Windows 8.1 project as well.
Let's now dig into the code a bit and see what we need to do.
First we need to declare a local variable:
private MediaCapture _captureManager;
Now that we have this in place let's initialize our capture object
private async void InitializeCamera()
{
var videoDevices = await DeviceInformation.FindAllAsync(DeviceClass.VideoCapture);
var rearCamera = videoDevices.First(item => item.EnclosureLocation != null &&
item.EnclosureLocation.Panel == Windows.Devices.Enumeration.Panel.Back);
_captureManager = new MediaCapture();
await _captureManager.InitializeAsync(new MediaCaptureInitializationSettings
{
VideoDeviceId = rearCamera.Id
});
capturePreview.Source = _captureManager;
await _captureManager.StartPreviewAsync();
}
Let's just quickly look at the code. On some phones the front facing camera is the default one. Unless you want your app to be yet another selfie app you will have to grab the ID of the rear facing camera and pass this into the initialization method for our MediaCapture object.
After that you only have one more thing to do and that's to add and XAML control to display you a preview of what you are going to take a photo.
You do this by adding this line of XAML code into the view
<CaptureElement x:Name="capturePreview" Stretch="UniformToFill"/>
Once you have that you can set its source to be the MediaCapture object and start your preview.
Now that you have all in place you can hit F5 and run your app either on the emulator or deploy it to a device. If you do that you will notice that once you hold your phone in landscape mode everything is looking good. If you turn the phone to portrait mode you will get a surprise. The preview is rotated counter clockwise by 90 degrees. That's because the expected orientation on all devices is landscape with the camera in the middle of the device. But since you are on a phone this doesn't apply.
What you have to do is add one line of magic before you initialize your preview control.
_captureManager.SetPreviewRotation(VideoRotation.Clockwise90Degrees);
capturePreview.Source = _captureManager;
await _captureManager.StartPreviewAsync();
Now if you run your app you will notice it looking good in portrait mode but not in landscape (oh boy...)
What we have to do is to set the preview rotation depending on the orientation of the phone. To achive this we have to use the SimpleOrientationSensor class.
You will have to modify your app a little bit more to get the desired behaviour. So lets start!
First we need another local variable for our sensor
private SimpleOrientationSensor _sensor;
Then we have to initialize it...
private void InitializeSensor()
{
_sensor = SimpleOrientationSensor.GetDefault();
if (_sensor != null)
{
_sensor.OrientationChanged += OrientationChanged;
}
}
..and create an event handler for the orientation change.
void OrientationChanged(SimpleOrientationSensor sender,
SimpleOrientationSensorOrientationChangedEventArgs args)
{
if (_captureManager == null)
return;
var orientation = args.Orientation;
if (orientation == SimpleOrientation.Rotated90DegreesCounterclockwise ||
orientation == SimpleOrientation.Rotated270DegreesCounterclockwise)
{
_captureManager.SetPreviewRotation(VideoRotation.None);
}
else
{
_captureManager.SetPreviewRotation(VideoRotation.Clockwise90Degrees);
}
}
Now we have everything to see what we are going to take a photo of. The only thing left is to take the photo and save it to the storage. One of the ways is like this.
private async void TakePhotoClick(object sender, RoutedEventArgs e)
{
var imgFormat = ImageEncodingProperties.CreateJpeg();
var file = await ApplicationData.Current.LocalFolder.CreateFileAsync(
"photo.jpg",
CreationCollisionOption.GenerateUniqueName);
await _captureManager.CapturePhotoToStorageFileAsync(imgFormat, file);
var photo = new BitmapImage(new Uri(file.Path));
}
Now that you have the photo you can use it however you want inside your app. It's stored locally into your application storage so that no other app can access it (it would be a different story if you stored it to the camera roll).
I hope you liked this tutorial and if you have any questions leave them in the comments below.
If you are to lazy to code, you can grab the source code from here.
Until next time, happy coding :)