Custom Camera Dialog For Windows Using UWP

Custom Camera Dialog For Windows Using UWP
 

Introduction

 
In this tutorial, we will learn how to create a custom dialog for camera view for Windows 10 using UWP. To achieve this, we need to use Web Camera and Storage features for Windows 10 operating system.
 

Steps

 
I have split the coding part into 5 steps as in the following.
 
Step 1 - Creating new UWP Project
Step 2 - Implementation of Camera Dialog
Step 3 - Implementation of Camera Output Storage
 
Step 1 - Creating new UWP Project
  • Create New Project by Selecting New Project à Universal Windows (UWP App) and click Next.

    Custom Camera Dialog For Windows Using UWP

  • Then configure your new project by entering the required details like Project name and click “Create” button to create your UWP project.

    Custom Camera Dialog For Windows Using UWP
Step 2 - Implementation of Camera Dialog
 
In this step, we will create a custom dialog for camera preview in UWP.
  • Create a custom content dialog by selecting “Add Item” à “Content Dialog” and named as “Camera Dialog”.
  • Then add the Capture Element in designer of the page as like below.
    1. <ContentDialog  
    2.     x:Class="UwpCamSample.CameraDialog"  
    3.     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"  
    4.     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"  
    5.     xmlns:local="using:UwpCamSample"  
    6.     xmlns:d="http://schemas.microsoft.com/expression/blend/2008"  
    7.     xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"  
    8.     mc:Ignorable="d"  
    9.     Title="Camera Dialog"  
    10.     PrimaryButtonText="Capture"  
    11.     SecondaryButtonText="Close"  
    12.     PrimaryButtonClick="ContentDialog_PrimaryButtonClick"  
    13.     SecondaryButtonClick="ContentDialog_SecondaryButtonClick"  
    14.     Margin="20">  
    15.   
    16.     <Grid>  
    17.         <CaptureElement Name="PreviewControl" Stretch="Uniform"/>  
    18.     </Grid>  
    19. </ContentDialog>  
  • We will use MediaCapture to capture CaptureElement result.
  • We will use DisplayRequest to detect the display interaction to extend battery power.
  • Start the preview for the capture element by initializing the media capture elements like in below code.
    1. private async Task StartPreviewAsync()  
    2. {  
    3.     try  
    4.     {  
    5.         mediaCapture = new MediaCapture();  
    6.         await mediaCapture.InitializeAsync();  
    7.         displayRequest.RequestActive();  
    8.         DisplayInformation.AutoRotationPreferences = DisplayOrientations.Landscape;  
    9.     }  
    10.     catch (UnauthorizedAccessException)  
    11.     {  
    12.         return;  
    13.     }  
    14.   
    15.     try  
    16.     {  
    17.         PreviewControl.Source = mediaCapture;  
    18.         await mediaCapture.StartPreviewAsync();  
    19.         isPreviewing = true;  
    20.     }  
    21.     catch (System.IO.FileLoadException)  
    22.     {  
    23.         mediaCapture.CaptureDeviceExclusiveControlStatusChanged += _mediaCapture_CaptureDeviceExclusiveControlStatusChanged;  
    24.     }  
    25. }  
  • The app should have camera permission and we can process Camera API permission like below.
    1. private async void _mediaCapture_CaptureDeviceExclusiveControlStatusChanged(MediaCapture sender, MediaCaptureDeviceExclusiveControlStatusChangedEventArgs args)  
    2. {  
    3.     if (args.Status == MediaCaptureDeviceExclusiveControlStatus.SharedReadOnlyAvailable)  
    4.     {  
    5.         //ShowMessageToUser("The camera preview can't be displayed because another app has exclusive access");  
    6.     }  
    7.     else if (args.Status == MediaCaptureDeviceExclusiveControlStatus.ExclusiveControlAvailable && !isPreviewing)  
    8.     {  
    9.         await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, async () =>  
    10.         {  
    11.             await StartPreviewAsync();  
    12.         });  
    13.     }  
    14. }  
  • The camera preview should be reset or disposed when the popup/dialog is closed.
    1. if (mediaCapture != null)  
    2. {  
    3.    if (isPreviewing)  
    4.    {  
    5.        await mediaCapture.StopPreviewAsync();  
    6.    }  
    7.   
    8.    await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>  
    9.    {  
    10.        PreviewControl.Source = null;  
    11.        if (displayRequest != null)  
    12.        {  
    13.            displayRequest.RequestRelease();  
    14.        }  
    15.   
    16.        mediaCapture.Dispose();  
    17.          
    18.     });  
    19. }  
Step 3 - Implementation of Camera Output Storage
 
In this step, we will process and save the captured preview into system.
  • To save the captured image to user defined path, will use StorageLibrary API and save the files to Pictures.
  • Use the below code snippet to save the output of the Camera Capture Element.
    1. var myPictures = await Windows.Storage.StorageLibrary.GetLibraryAsync(Windows.Storage.KnownLibraryId.Pictures);  
    2. StorageFile file = await myPictures.SaveFolder.CreateFileAsync("photo.jpg", CreationCollisionOption.GenerateUniqueName);  
    3.   
    4. using (var captureStream = new InMemoryRandomAccessStream())  
    5. {  
    6.     await mediaCapture.CapturePhotoToStreamAsync(ImageEncodingProperties.CreateJpeg(), captureStream);  
    7.   
    8.     using (var fileStream = await file.OpenAsync(FileAccessMode.ReadWrite))  
    9.     {  
    10.         var decoder = await BitmapDecoder.CreateAsync(captureStream);  
    11.         var encoder = await BitmapEncoder.CreateForTranscodingAsync(fileStream, decoder);  
    12.   
    13.         var properties = new BitmapPropertySet {  
    14.             {  
    15.                 "System.Photo.Orientation"new BitmapTypedValue(PhotoOrientation.Normal, PropertyType.UInt16)  
    16.             }  
    17.         };  
    18.         await encoder.BitmapProperties.SetPropertiesAsync(properties);  
    19.         await encoder.FlushAsync();  
    20.     }  
    21. }  
Full Code
 
You can find the full code for Camera Dialog below.
  1. using System;  
  2. using Windows.Foundation;  
  3. using Windows.UI.Xaml;  
  4. using Windows.UI.Xaml.Controls;  
  5. using Windows.UI.Xaml.Navigation;  
  6. using Windows.UI.Core;  
  7. using System.Threading.Tasks;  
  8. using Windows.Graphics.Display;  
  9. using Windows.Storage.Streams;  
  10. using Windows.Media.MediaProperties;  
  11. using Windows.Graphics.Imaging;  
  12. using Windows.Storage.FileProperties;  
  13. using Windows.Storage;  
  14. using Windows.Media.Capture;  
  15. using Windows.System.Display;  
  16.   
  17. // The Content Dialog item template is documented at https://go.microsoft.com/fwlink/?LinkId=234238  
  18.   
  19. namespace UwpCamSample  
  20. {  
  21.     public sealed partial class CameraDialog : ContentDialog  
  22.     {  
  23.         MediaCapture mediaCapture;  
  24.         DisplayRequest displayRequest = new DisplayRequest();  
  25.         bool isPreviewing;  
  26.   
  27.         //private static CameraDialog _instance = null;  
  28.         //public static CameraDialog Instance  
  29.         //{  
  30.         //    get  
  31.         //    {  
  32.         //        if (_instance == null)  
  33.         //            _instance = new CameraDialog();  
  34.         //        return _instance;  
  35.         //    }  
  36.         //    set  
  37.         //    {  
  38.         //    }  
  39.         //}  
  40.   
  41.         public CameraDialog()  
  42.         {  
  43.             this.InitializeComponent();  
  44.             StartPreviewAsync();  
  45.         }  
  46.   
  47.         private async void ContentDialog_SecondaryButtonClick(ContentDialog sender, ContentDialogButtonClickEventArgs args)  
  48.         {  
  49.             await CleanupCameraAsync();  
  50.         }  
  51.   
  52.         private async void ContentDialog_PrimaryButtonClick(ContentDialog sender, ContentDialogButtonClickEventArgs args)  
  53.         {  
  54.             var myPictures = await Windows.Storage.StorageLibrary.GetLibraryAsync(Windows.Storage.KnownLibraryId.Pictures);  
  55.             StorageFile file = await myPictures.SaveFolder.CreateFileAsync("photo.jpg", CreationCollisionOption.GenerateUniqueName);  
  56.   
  57.             using (var captureStream = new InMemoryRandomAccessStream())  
  58.             {  
  59.                 await mediaCapture.CapturePhotoToStreamAsync(ImageEncodingProperties.CreateJpeg(), captureStream);  
  60.   
  61.                 using (var fileStream = await file.OpenAsync(FileAccessMode.ReadWrite))  
  62.                 {  
  63.                     var decoder = await BitmapDecoder.CreateAsync(captureStream);  
  64.                     var encoder = await BitmapEncoder.CreateForTranscodingAsync(fileStream, decoder);  
  65.   
  66.                     var properties = new BitmapPropertySet {  
  67.             {  
  68.                 "System.Photo.Orientation"new BitmapTypedValue(PhotoOrientation.Normal, PropertyType.UInt16)  
  69.             }  
  70.         };  
  71.                     await encoder.BitmapProperties.SetPropertiesAsync(properties);  
  72.                     await encoder.FlushAsync();  
  73.                 }  
  74.             }  
  75.             await CleanupCameraAsync();  
  76.         }  
  77.   
  78.         private async Task StartPreviewAsync()  
  79.         {  
  80.             try  
  81.             {  
  82.                 mediaCapture = new MediaCapture();  
  83.                 await mediaCapture.InitializeAsync();  
  84.                 displayRequest.RequestActive();  
  85.                 DisplayInformation.AutoRotationPreferences = DisplayOrientations.Landscape;  
  86.             }  
  87.             catch (UnauthorizedAccessException)  
  88.             {  
  89.                 return;  
  90.             }  
  91.   
  92.             try  
  93.             {  
  94.                 PreviewControl.Source = mediaCapture;  
  95.                 await mediaCapture.StartPreviewAsync();  
  96.                 isPreviewing = true;  
  97.             }  
  98.             catch (System.IO.FileLoadException)  
  99.             {  
  100.                 mediaCapture.CaptureDeviceExclusiveControlStatusChanged += _mediaCapture_CaptureDeviceExclusiveControlStatusChanged;  
  101.             }  
  102.   
  103.         }  
  104.   
  105.         private async void _mediaCapture_CaptureDeviceExclusiveControlStatusChanged(MediaCapture sender, MediaCaptureDeviceExclusiveControlStatusChangedEventArgs args)  
  106.         {  
  107.             if (args.Status == MediaCaptureDeviceExclusiveControlStatus.SharedReadOnlyAvailable)  
  108.             {  
  109.                 //ShowMessageToUser("The camera preview can't be displayed because another app has exclusive access");  
  110.             }  
  111.             else if (args.Status == MediaCaptureDeviceExclusiveControlStatus.ExclusiveControlAvailable && !isPreviewing)  
  112.             {  
  113.                 await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, async () =>  
  114.                 {  
  115.                     await StartPreviewAsync();  
  116.                 });  
  117.             }  
  118.         }  
  119.   
  120.         private async Task CleanupCameraAsync()  
  121.         {  
  122.             if (mediaCapture != null)  
  123.             {  
  124.                 if (isPreviewing)  
  125.                 {  
  126.                     await mediaCapture.StopPreviewAsync();  
  127.                 }  
  128.   
  129.                 await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>  
  130.                 {  
  131.                     PreviewControl.Source = null;  
  132.                     if (displayRequest != null)  
  133.                     {  
  134.                         displayRequest.RequestRelease();  
  135.                     }  
  136.   
  137.                     mediaCapture.Dispose();  
  138.                     //mediaCapture = null;  
  139.                 });  
  140.             }  
  141.   
  142.         }  
  143.     }  
  144. }  

Output

Custom Camera Dialog For Windows Using UWP
 
Custom Camera Dialog For Windows Using UWP
 
Custom Camera Dialog For Windows Using UWP
 
Download Code
 
You can download the code from GitHub. If you have doubts, feel free to post a comment. If you like this article and it is useful to you, do like, share the article & star the repository on GitHub.