In Windows Phone Silverlight (8.0 and 8.1) we can use Camera Capture Task to capture a picture using build-in camera. It’s quite easy and we don’t have to do much to make it work.
When writing a Windows Runtime App , the situation it’s little different – we cannot use above Task as it doen’t exist in the API. We will have to use MediaCapture class.
First what we have to do is to initialize the class – within this step we will also need to declare which camera we wish to use and set the resolution. The sample code can look like this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
private static async Task<DeviceInformation> GetCameraID(Windows.Devices.Enumeration.Panel desiredCamera) { // get available devices for capturing pictures DeviceInformation deviceID = (await DeviceInformation.FindAllAsync(DeviceClass.VideoCapture)) .FirstOrDefault(x => x.EnclosureLocation != null && x.EnclosureLocation.Panel == desiredCamera); if (deviceID != null) return deviceID; else throw new Exception(string.Format("Camera of type {0} doesn't exist.", desiredCamera)); } async private void InitCameraBtn_Click(object sender, RoutedEventArgs e) { var cameraID = await GetCameraID(Windows.Devices.Enumeration.Panel.Back); captureManager = new MediaCapture(); await captureManager.InitializeAsync(new MediaCaptureInitializationSettings { StreamingCaptureMode = StreamingCaptureMode.Video, PhotoCaptureSource = PhotoCaptureSource.VideoPreview, AudioDeviceId = string.Empty, VideoDeviceId = cameraID.Id }); var maxResolution = captureManager.VideoDeviceController.GetAvailableMediaStreamProperties(MediaStreamType.Photo).Aggregate((i1, i2) => (i1 as VideoEncodingProperties).Width > (i2 as VideoEncodingProperties).Width ? i1 : i2); await captureManager.VideoDeviceController.SetMediaStreamPropertiesAsync(MediaStreamType.Photo, maxResolution); } |
Choosing camera device is quite obvious – most mobile devices nowadays have at least two cameras and we should pick one (on my Phone default is Front camera). The code above identifies the ID of Back camera and then initializes MediaCapture class with suitable properties. Why do we have to set the resolution after initialization? – there is probably a default one. Yes that’s right, but if we don’t set the proper resolution then our taken photo can suffer strange stripes on its sides (Pic. 1).
So we have our class initialized, it’s prepared to take photos, but it will be nice to see what we will be in our picture. Here comes CaptureElement class with help. Using it in XAML is very simple:
1 |
<CaptureElement x:Name="capturePreview" Stretch="Uniform" Height="200" Width="300"/> |
When we have it defined, then we can start previewing:
1 2 3 4 5 6 7 |
async private void StartPreviewBtn_Click(object sender, RoutedEventArgs e) { // rotate to see preview vertically captureManager.SetPreviewRotation(VideoRotation.Clockwise90Degrees); capturePreview.Source = captureManager; await captureManager.StartPreviewAsync(); } |
To stop it – just call
await captureManager.StopPreviewAsync();
Finally when we can take our photo – the API enables to capture photo to StorageFile or to Stream:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
async private void TakePhotoBtn_Click(object sender, RoutedEventArgs e) { // create a file StorageFile photoFile = await ApplicationData.Current.LocalFolder.CreateFileAsync("myFirstPhoto.jpg", CreationCollisionOption.ReplaceExisting); // take a photo with choosen Encoding await captureManager.CapturePhotoToStorageFileAsync(ImageEncodingProperties.CreateJpeg(), photoFile); // we can also take a photo to memory stream // InMemoryRandomAccessStream memStream = new InMemoryRandomAccessStream(); // await captureManager.CapturePhotoToStreamAsync(ImageEncodingProperties.CreateJpegXR(), memStream); // show a photo on screen BitmapImage bitmapToShow = new BitmapImage(new Uri(photoFile.Path)); imagePreivew.Source = bitmapToShow; // show image on screen inside Image control defined in XAML } |
After invoking the method we should see the photo in Image control (of course if we had defined one).
What is important – remember always to Dispose() your MediaCapture class, stop previewing and handle possible errors. Also protect the initializing method from being invoked few times at the same moment – it can hang your Phone or camera so that any other app won’t be able to use it.
Each post's copyright held by the original author. All rights reserved.
You sir are the best! I have been looking for a blog to explain this to me for a few days now. Thanks
is this code for desktop app or windows phone app , while using in windows phone app 8.1 ,gives error of captureelement not found , i want to use back phone camera to capture the photo, which class have to use for capturing the photo with advanced property for windows phone 8.1 ?
It’s hard to say from so little information what can be a problem. Please check if you are targeting Windows Runtime (not Silverlight), hence CaptureElement is only for Runtime.
I have followed this “tutorial” almost to the T (my capture element is using up the whole space instead of being 200×300 but this doesn’t make a difference) and I get this results:
1. (When not using the SetPreviewRotation) http://imgur.com/sapiiCe,leSWIyG#0 you can see that the image is horizontal in portrait mode and only is fullscreen when in landscape mode. 2. (When using the SetPreviewRotation) http://imgur.com/sapiiCe,leSWIyG#1 It’s now vertical in portrait but uses only a third of the screen and then doesn’t go fullscreen when in landscape mode. My question is how can I get it to be fullscreen in portrait mode. I know that I just have to hook up to the orientation changed event to rotate the image when in portrait but not in landscape but how can I make it look nice in portrait mode?
Never mind. Figured it out just after posting the question. Thanks for the article again
Also you will need to rotate your pictures after taking them to do that use Nokia Imaging SDK.
using (var imageSource = new StorageFileImageSource(file))
using (var filterEffect = new FilterEffect(imageSource))
using (var renderer = new JpegRenderer(filterEffect))
{
var imageInfo = await imageSource.GetInfoAsync();
var filter = new IFilter[]
{
new RotationFilter(imageRotationAngle)
};
filterEffect.Filters = filter;
var buffer = await renderer.RenderAsync();
await FileIO.WriteBufferAsync(rotatedImageFile, buffer);
BitmapImage bitmapImage = new BitmapImage(new Uri(rotatedImageFile.Path));
imageFiles.Add(rotatedImageFile);
previews.Add(new PhotoPreviewViewModel() { Image = bitmapImage });
}
hope this helps
Thank you for sharing the code, some people might find it usefull.
On emulator it works great. Debugging on my lumia 625 i’ve got an “access denied” message on line 16 (await captureManager.InitializeAsync() ). capabilitys: Microphone, Webcam and also tried with set all.
Anyone got a solution for this problem?
This also happens on Lumia 820. Previously working above code throws the exception (note also that MSDN example has similar problem). It seems that the issue appeard after one of the last updates. I’ve submitted this as a bug on dev user voice – hopefully it will be corrected soon.
It seems that with the recent update Microsoft has fixed the ‘access denied bug’.