How To Scan QRCode For UWP (2)

这篇随笔主要介绍照相预览功能,重要使用的是MediaCapture对象,MediaCapture对象还可以用来处理录音和录制视频,本文只讨论照相功能。

1:查找摄像头

后置摄像头优先,找不到后置摄像头就返回找到的可用的摄像头列表的第一个。

 1 /// <summary>
 2         /// Queries the available video capture devices to try and find one mounted on the desired panel.
 3         /// </summary>
 4         /// <param name="desiredPanel">The panel on the device that the desired camera is mounted on.</param>
 5         /// <returns>A DeviceInformation instance with a reference to the camera mounted on the desired panel if available,
 6         ///          any other camera if not, or null if no camera is available.</returns>
 7         private static async Task<DeviceInformation> FindCameraDeviceByPanelAsync(Windows.Devices.Enumeration.Panel desiredPanel)
 8         {
 9             // Get available devices for capturing pictures.
10             var allVideoDevices = await DeviceInformation.FindAllAsync(DeviceClass.VideoCapture);
11 
12             // Get the desired camera by panel.
13             DeviceInformation desiredDevice = allVideoDevices.FirstOrDefault(x => x.EnclosureLocation != null && x.EnclosureLocation.Panel == desiredPanel);
14 
15             // If there is no device mounted on the desired panel, return the first device found.
16             return desiredDevice ?? allVideoDevices.FirstOrDefault();
17         }

2:初始Camera

首先需要创建一个MediaCapture实例,MediaCapture类位于Windows.Media.Capture命名空间。然后需要允许App访问Camera,需要修改Package.appxmanifest文件,选择Capabilities Tab 勾选中 Microphone  & Webcam。 调用MediaCapture.InitializeAsync方法并指定要初始化上一步找到的Camera。

如果MediaCapture使用的过程中抛出了Error,此时就需要释放MediaCapture资源,可以在MediaCapture的Failed事件来处理。

此外还使用了isInitialized 标志位来判断是否已经成功初始化了Camera。

3:预览

需要调用MediaCapture.StartPreviewAsync(),在预览过程中使用了DisplayRequest对象RequestActive方法来防止设备屏幕休眠。
同样使用了isPreviewing来判断Camera是否处于预览状态。
经过三个步骤后,就可以正常预览Camera了。

MediaCapture对象的StopPreviewAsync方法用来停止预览,停止预览后,设备就可以允许睡眠了,需要调用DisplayRequest对象RequestRelease。

4:其他

当App转换为Suspending状态时,先使用SuspendingOperation.GetDeferral()请求延迟挂起操作,释放完MediaCapture资源,最后调用SuspendingDeferral.Complete() 通知操作系统App已经准好被挂起了。当App转换为Resuming状态时,需要再次开启Camera。
可以分别处理Application.Current.Suspending跟Application.Current.Resuming事件。

 

附上代码:

  1 using System;
  2 using System.Linq;
  3 using System.Threading.Tasks;
  4 using Windows.ApplicationModel;
  5 using Windows.Devices.Enumeration;
  6 using Windows.Media.Capture;
  7 using Windows.System.Display;
  8 using Windows.UI.Core;
  9 using Windows.UI.Popups;
 10 using Windows.UI.Xaml;
 11 using Windows.UI.Xaml.Controls;
 12 using Windows.UI.Xaml.Navigation;
 13 
 14 // The Blank Page item template is documented at http://go.microsoft.com/fwlink/?LinkId=402352&clcid=0x409
 15 
 16 namespace ScanQRCode
 17 {
 18     /// <summary>
 19     /// An empty page that can be used on its own or navigated to within a Frame.
 20     /// </summary>
 21     public sealed partial class MainPage : Page
 22     {
 23         const int borderThickness = 5;
 24 
 25         private MediaCapture mediaCapture;
 26         private bool isInitialized = false;
 27         private bool isPreviewing = false;
 28 
 29         // Prevent the screen from sleeping while the camera is running.
 30         private readonly DisplayRequest displayRequest = new DisplayRequest();
 31 
 32         public MainPage()
 33         {
 34             this.InitializeComponent();
 35 
 36             // Useful to know when to initialize/clean up the camera
 37             Application.Current.Suspending += Application_Suspending;
 38             Application.Current.Resuming += Application_Resuming;
 39         }
 40 
 41         /// <summary>
 42         /// Occures on app suspending. Stops camera if initialized.
 43         /// </summary>
 44         /// <param name="sender"></param>
 45         /// <param name="e"></param>
 46         private async void Application_Suspending(object sender, SuspendingEventArgs e)
 47         {
 48             // Handle global application events only if this page is active.
 49             if (Frame.CurrentSourcePageType == typeof(MainPage))
 50             {
 51                 var deferral = e.SuspendingOperation.GetDeferral();
 52 
 53                 await CleanupCameraAsync();
 54 
 55                 deferral.Complete();
 56             }
 57         }
 58 
 59         /// <summary>
 60         /// Occures on app resuming. Initializes camera if available.
 61         /// </summary>
 62         /// <param name="sender"></param>
 63         /// <param name="o"></param>
 64         private async void Application_Resuming(object sender, object o)
 65         {
 66             // Handle global application events only if this page is active
 67             if (Frame.CurrentSourcePageType == typeof(MainPage))
 68             {
 69                 await StartCameraAsync();
 70             }
 71         }
 72 
 73         private void InitFocusRec()
 74         {
 75             leftTopBorder.BorderThickness = new Thickness(borderThickness, borderThickness, 0, 0);
 76             rightTopBorder.BorderThickness = new Thickness(0, borderThickness, borderThickness, 0);
 77             leftBottomBorder.BorderThickness = new Thickness(borderThickness, 0, 0, borderThickness);
 78             rightBottomBorder.BorderThickness = new Thickness(0, 0, borderThickness, borderThickness);
 79 
 80             var borderLength = 20;
 81             leftTopBorder.Width = leftTopBorder.Height = borderLength;
 82             rightTopBorder.Width = rightTopBorder.Height = borderLength;
 83             leftBottomBorder.Width = leftBottomBorder.Height = borderLength;
 84             rightBottomBorder.Width = rightBottomBorder.Height = borderLength;
 85 
 86             var focusRecLength = Math.Min(ActualWidth / 2, ActualHeight / 2);
 87             scanGrid.Width = scanGrid.Height = focusRecLength;
 88             scanCavas.Width = scanCavas.Height = focusRecLength;
 89 
 90             scanStoryboard.Stop();
 91             scanLine.X2 = scanCavas.Width - 20;
 92             scanAnimation.To = scanCavas.Height;
 93 
 94             scanStoryboard.Begin();
 95         }
 96 
 97         private void Page_SizeChanged(object sender, SizeChangedEventArgs e)
 98         {
 99             InitFocusRec();
100         }
101 
102         protected override async void OnNavigatedTo(NavigationEventArgs e)
103         {
104             await StartCameraAsync();
105         }
106 
107         private async Task StartCameraAsync()
108         {
109             if (!isInitialized)
110             {
111                 await InitializeCameraAsync();
112             }
113 
114             if (isInitialized)
115             {
116                 PreviewControl.Visibility = Visibility.Visible;
117             }
118         }
119 
120         /// <summary>
121         /// Queries the available video capture devices to try and find one mounted on the desired panel.
122         /// </summary>
123         /// <param name="desiredPanel">The panel on the device that the desired camera is mounted on.</param>
124         /// <returns>A DeviceInformation instance with a reference to the camera mounted on the desired panel if available,
125         ///          any other camera if not, or null if no camera is available.</returns>
126         private static async Task<DeviceInformation> FindCameraDeviceByPanelAsync(Windows.Devices.Enumeration.Panel desiredPanel)
127         {
128             // Get available devices for capturing pictures.
129             var allVideoDevices = await DeviceInformation.FindAllAsync(DeviceClass.VideoCapture);
130 
131             // Get the desired camera by panel.
132             DeviceInformation desiredDevice = allVideoDevices.FirstOrDefault(x => x.EnclosureLocation != null && x.EnclosureLocation.Panel == desiredPanel);
133 
134             // If there is no device mounted on the desired panel, return the first device found.
135             return desiredDevice ?? allVideoDevices.FirstOrDefault();
136         }
137 
138         /// Initializes the MediaCapture
139         /// </summary>
140         private async Task InitializeCameraAsync()
141         {
142             if (mediaCapture == null)
143             {
144                 // Attempt to get the back camera if one is available, but use any camera device if not.
145                 var cameraDevice = await FindCameraDeviceByPanelAsync(Windows.Devices.Enumeration.Panel.Back);
146 
147                 if (cameraDevice == null)
148                 {
149                     //No camera device!
150                     return;
151                 }
152 
153                 // Create MediaCapture and its settings.
154                 mediaCapture = new MediaCapture();
155 
156                 // Register for a notification when something goes wrong
157                 mediaCapture.Failed += MediaCapture_Failed;
158 
159                 var settings = new MediaCaptureInitializationSettings { VideoDeviceId = cameraDevice.Id };
160 
161                 // Initialize MediaCapture
162                 try
163                 {
164                     await mediaCapture.InitializeAsync(settings);
165                     isInitialized = true;
166                 }
167                 catch (UnauthorizedAccessException)
168                 {
169                     await ShowMessage("Denied access to the camera.");
170                 }
171                 catch (Exception ex)
172                 {
173                     await ShowMessage("Exception when init MediaCapture. " + ex.Message);
174                 }
175 
176                 // If initialization succeeded, start the preview.
177                 if (isInitialized)
178                 {
179                     await StartPreviewAsync();
180                 }
181             }
182         }
183 
184         /// <summary>
185         /// Starts the preview after making a request to keep the screen on and unlocks the UI.
186         /// </summary>
187         private async Task StartPreviewAsync()
188         {
189             // Prevent the device from sleeping while the preview is running.
190             displayRequest.RequestActive();
191 
192             // Set the preview source in the UI.
193             PreviewControl.Source = mediaCapture;
194             // Start the preview.
195             try
196             {
197                 await mediaCapture.StartPreviewAsync();
198                 isPreviewing = true;
199             }
200             catch (Exception ex)
201             {
202                 await ShowMessage("Exception starting preview." + ex.Message);
203             }
204         }
205 
206 
207         /// <summary>
208         /// Handles MediaCapture failures. Cleans up the camera resources.
209         /// </summary>
210         /// <param name="sender"></param>
211         /// <param name="errorEventArgs"></param>
212         private async void MediaCapture_Failed(MediaCapture sender, MediaCaptureFailedEventArgs errorEventArgs)
213         {
214             await CleanupCameraAsync();
215         }
216 
217 
218         /// <summary>
219         /// Cleans up the camera resources (after stopping the preview if necessary) and unregisters from MediaCapture events.
220         /// </summary>
221         private async Task CleanupCameraAsync()
222         {
223             if (isInitialized)
224             {
225                 if (isPreviewing)
226                 {
227                     // The call to stop the preview is included here for completeness, but can be
228                     // safely removed if a call to MediaCapture.Dispose() is being made later,
229                     // as the preview will be automatically stopped at that point
230                     await StopPreviewAsync();
231                 }
232 
233                 isInitialized = false;
234             }
235 
236             if (mediaCapture != null)
237             {
238                 mediaCapture.Failed -= MediaCapture_Failed;
239                 mediaCapture.Dispose();
240                 mediaCapture = null;
241             }
242         }
243 
244         /// <summary>
245         /// Stops the preview and deactivates a display request, to allow the screen to go into power saving modes, and locks the UI
246         /// </summary>
247         /// <returns></returns>
248         private async Task StopPreviewAsync()
249         {
250             try
251             {
252                 isPreviewing = false;
253                 await mediaCapture.StopPreviewAsync();
254             }
255             catch (Exception ex)
256             {
257                 // Use the dispatcher because this method is sometimes called from non-UI threads.
258                 await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, async () =>
259                 {
260                     await ShowMessage("Exception stopping preview. " + ex.Message);
261                 });
262             }
263 
264             // Use the dispatcher because this method is sometimes called from non-UI threads.
265             await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
266             {
267                 PreviewControl.Source = null;
268 
269                 // Allow the device to sleep now that the preview is stopped.
270                 displayRequest.RequestRelease();
271             });
272         }
273 
274         private async Task ShowMessage(string message)
275         {
276             var messageDialog = new MessageDialog(message);
277             await messageDialog.ShowAsync();
278         }
279     }
280 }

 

posted @ 2017-07-28 17:34  supperwu  阅读(402)  评论(0编辑  收藏  举报