2016-12-02 38 views
0

我正在使用Windows 10平臺的通用Windows應用程序。應用程序應該使用相機捕獲條形碼,並對條形碼執行一些有用的操作。到目前爲止,捕捉和翻譯條形碼工作正常(使用ZXing Library)。我可以通過單擊每個條形碼一次的按鈕來一次接一個地捕獲條形碼。我的通用Windows應用程序中的相機手電筒僅適用於一次

但我需要它在光線不足的情況下工作。我想讓攝像頭在光線不足的情況下自動打開手電筒(或手電筒)。我發現相機可以在弱光情況下自動打開手電筒(或手電筒)之前我拍了第一張照片。不知何故,第一張照片後手電筒會自動關閉。只要用戶仍然留在我的應用程序的同一頁面(只要環境很暗),我就希望它保持開啓狀態。請幫我解決這個問題。

到目前爲止,我可以確定MediaCapture.CapturePhotoToStorageFileAsync()是關閉手電筒的命令。

下面是一個工作測試程序,以解決這個問題。

它是在測試程序MainPage.xaml中的程序文​​件:

<Page 
    x:Class="TestApp.MainPage" 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    xmlns:local="using:TestApp" 
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
    mc:Ignorable="d"> 

    <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"> 
     <CaptureElement Name="captureElement" 
         Stretch="UniformToFill" 
         Margin="32,-93,34.5,181.5" 
         d:LayoutOverrides="LeftPosition, RightPosition, TopPosition, BottomPosition" RenderTransformOrigin="0.5,0.5" UseLayoutRounding="False" d:LayoutRounding="Auto" > 
     <CaptureElement.RenderTransform> 
      <CompositeTransform Rotation="90"/> 
     </CaptureElement.RenderTransform> 
     </CaptureElement> 
     <Button x:Name="btnCapture" Content="Capture Barcode" HorizontalAlignment="Left" Margin="10,0,0,203" VerticalAlignment="Bottom" Height="64" BorderThickness="2,2,4,4" Background="#33FFFFFF" BorderBrush="Black" FontSize="20" FontWeight="Bold" Click="btnCapture_OnClick" Width="340"/> 
     <Button x:Name="btnTerminateApp" Content="Terminate This App" HorizontalAlignment="Stretch" Height="66" Margin="10,0,10,42" VerticalAlignment="Bottom" Background="#33FFFFFF" BorderBrush="Black" BorderThickness="2,2,4,4" FontWeight="Bold" d:LayoutOverrides="LeftPosition, RightPosition" Click="btnTerminateApp_OnClick" FontSize="20"/> 

    </Grid> 
</Page> 

它是在測試程序MainPage.xaml.cs中的程序文​​件:

using System; 
using System.Collections.Generic; 
using System.IO; 
using System.Linq; 
using System.Runtime.InteropServices.WindowsRuntime; 
using Windows.Foundation; 
using Windows.Foundation.Collections; 
using Windows.Graphics.Imaging;  // For BitmapDecoder. 
using Windows.Media.Capture;   // For MediaCapture. 
using Windows.Media.Devices;   // For FocusSettings, FocusMode, AutoFocusRange. 
using Windows.Media.MediaProperties; // For ImageEncodingProperties. 
using Windows.Media.Playback;   // For MediaPlayer.Volume. 
using Windows.Storage;     // For StorageFile. 
using Windows.Storage.Streams;   // For IRandomAccessStream. 
using Windows.UI.Popups;    // For MessageDialog(). 
using Windows.UI.Xaml; 
using Windows.UI.Xaml.Controls; 
using Windows.UI.Xaml.Controls.Primitives; 
using Windows.UI.Xaml.Data; 
using Windows.UI.Xaml.Input; 
using Windows.UI.Xaml.Media; 
using Windows.UI.Xaml.Media.Imaging; // For WriteableBitmap. 
using Windows.UI.Xaml.Navigation; 
//using ZXing;       // For BarcodeFormat. 

// The Blank Page item template is documented 
// at http://go.microsoft.com/fwlink/?LinkId=402352&clcid=0x409 

namespace TestApp 
    { 
    /// <summary> 
    /// An empty page that can be used on its own or navigated to within a Frame. 
    /// </summary> 
    public sealed partial class MainPage : Page 
     { 
     private MediaCapture captureMgr { get; set; } 

     public MainPage() 
     { 
     this.InitializeComponent(); 
     this.InitCapture(); 
     } 

     private void btnTerminateApp_OnClick(object sender, RoutedEventArgs e) 
     { 
     this.ReleaseCapture(); 
     Application.Current.Exit(); 
     } 

     private async void btnCapture_OnClick(object sender, RoutedEventArgs e) 
     // Capture the barcode photo and translate it into a barcode number. And then 
     // use the barcode number to mark the piece as checked out. 
     { 
     // Capture the barcode and translate it into a barcode number. 

     //....Capture the barcode photo from the camera to a storage-file. 
     ImageEncodingProperties fmtImage = ImageEncodingProperties.CreateJpeg(); 
     StorageFile storefile = await ApplicationData.Current.LocalFolder.CreateFileAsync 
      (
      "BarcodePhoto.jpg", 
      CreationCollisionOption.GenerateUniqueName 
      ); 
     await this.captureMgr.CapturePhotoToStorageFileAsync(fmtImage, storefile); 

     //....Convert the barcode photo in the storage file into a writeable-bitmap. 
     IRandomAccessStream stream = await storefile.OpenAsync(FileAccessMode.Read); 
     BitmapDecoder decoderBmp = await BitmapDecoder.CreateAsync(stream); 
     WriteableBitmap bmp = new WriteableBitmap((int)decoderBmp.PixelWidth, 
                (int)decoderBmp.PixelHeight); 
     bmp.SetSource(stream); 

     //....We are done with the temporary barcode image file. Delete it. 
     await storefile.DeleteAsync(); 

     ////....Translate the barcode photo from the writeable-bitmap into a barcode number. 
     // 
     //ZXing.BarcodeReader bcodeReader = new ZXing.BarcodeReader(); 
     // 
     //BarcodeFormat[] aAllowedFormat = new BarcodeFormat[] { BarcodeFormat.CODE_39 }; 
     //bcodeReader.Options.PossibleFormats = aAllowedFormat; 
     // // We only want it to deal with one barcode format. Hopefully this will reduce the 
     // // chance of reading the barcode number wrong, or speed up the decoding process. 
     // // Note that this option only works if we includes "Microphone" as a required 
     // // DeviceCapability of this app in Package.appmanifest. If we don't include 
     // // "Microphone", we will get an unhandled exception here. 
     // 
     //bcodeReader.Options.TryHarder = true; // Try this option to see if we can reduce the 
     //          // chance of failing to translate the 
     //          // barcode into a number. So far no problem 
     //          // as of 11/21/2016. 
     // 
     //var result = bcodeReader.Decode(bmp); 
     //if (result == null) 
     // return; 
     } 

     private async void InitCapture() 
     // Initialize everything about MediaCapture. 
     { 
     this.captureMgr = new MediaCapture(); 
     await this.captureMgr.InitializeAsync(); 

     // Skip the steps to set the photo resolution to the second lowest in order 
     // not to make this test program too big. 

     // Start the camera preview. 
     captureElement.Source = this.captureMgr; 
     await this.captureMgr.StartPreviewAsync(); 

     // Set the camera to auto-focus. 
     var settings = new FocusSettings { Mode   = FocusMode.Continuous, 
              AutoFocusRange = AutoFocusRange.FullRange }; 
     await this.captureMgr.VideoDeviceController.FocusControl.UnlockAsync(); 
     this.captureMgr.VideoDeviceController.FocusControl.Configure(settings); 
     await this.captureMgr.VideoDeviceController.FocusControl.FocusAsync(); 

     // Turn on the flashlight in case the lighting is dim. Without enough 
     // lighting, the auto-focus feature of the camera cannot work. 
     var cameraFlashLight = this.captureMgr.VideoDeviceController.FlashControl; 
     if (cameraFlashLight.Supported) 
      { 
      if (cameraFlashLight.PowerSupported) 
       cameraFlashLight.PowerPercent = 100; 
      cameraFlashLight.Enabled = true; 
      } 
     // ////////////////////////// 
     // Tried replacing flashlight with torch. But get the same problem. 
     // ////////////////////////// 
     //var cameraTorch = this.captureMgr.VideoDeviceController.TorchControl; 
     //if (cameraTorch.Supported) 
     // { 
     // if (cameraTorch.PowerSupported) 
     //  cameraTorch.PowerPercent = 100; 
     // cameraTorch.Enabled = true; 
     // } 
     // ////////////////////////// 
     } 

     private async void ReleaseCapture() 
     { 
     captureElement.Source = null; 
     await this.captureMgr.StopPreviewAsync(); 
     this.captureMgr.Dispose(); 
     } 
     } 
    } 

爲了不強迫人們安裝ZXing Library只是爲了試用上面的測試應用程序,我已經在測試應用程序中評論了與ZXing Library相關的所有內容。

用戶可以通過離開該頁面(回到主菜單)然後返回到同一頁面來解決該問題。這會重置程序中的某些內容,並使自動手電筒功能再次運行。顯然,這不是一個很好的解決方法,因爲用戶需要爲每一個條碼採取這樣的操作。請注意,上面顯示的測試應用程序只有一個頁面,並沒有主菜單。因此,您將無法使用上述測試應用程序查看此解決方法。

我試圖通過在拍攝每張照片後重置MediaCapture來解決此問題。這是通過在我上面顯示的測試應用程序中調用ReleaseCapture()和InitCapture()來完成的。不幸的是,這不僅會減慢條碼的每次捕獲速度,而且還會觸發System.ObjectDisposedException關於對象未初始化或類似的事情。無論如何,我更喜歡修復原來的問題,而不是使用解決方法。

順便說一下,在我的開發PC中,我有Windows 10 Professional和Visual Studio 2015 Professional。我使用的Windows手機是帶有Windows 10 Moblile 1511操作系統 - 內置10.0.10586.107的Microsoft Lumia 640 LTE。

請幫我解決這個問題。也歡迎任何建議。

在此先感謝。

Jay Chan

+0

有什麼建議嗎?請告訴我。謝謝。 –

+0

我曾嘗試使用「燈」代替手電筒或手電筒。不幸的是,我正在測試的Windows Phone不支持Lamp API。以防萬一有人遇到同樣的問題,他可能想閱讀本文,以查看Lamp是否適合您:[link] https://msdn.microsoft.com/en-us/windows/uwp/audio -video-camera/camera-independent-flashlight –

+0

我已經在Lumia 640 build 1607上測試過你的代碼,閃光燈總是可以正常工作。請嘗試更新您的操作系統版本以建立1607. –

回答

0

打開這個解決方案很簡單。所有我需要做的是首先釋放它的CaptureElement復位,然後重新初始化,就像這樣:

this.ReleaseCapture(); 
this.InitCapture(); 

ReleaseCapture的最棘手的部分()是我無法處置的MediaCapture。否則,當我嘗試重新初始化CaptureElement時,程序會崩潰。因此,ReleaseCapture()是現在這個樣子:

private async void ReleaseCapture() 
    // Release the resources used for capturing photo. 
    { 
    try 
     { 
     captureElement.Source = null; 
     await this.captureMgr.StopPreviewAsync(); 

     ////////////// 
     // Don't dispose it. Otherwise, when we re-initialize it right after we have released it, the program will 
     // crash. We are better off don't do this here. When we are leaving the page, the page will release it 
     // anyway. 
     ////////////// 
     //this.captureMgr.Dispose(); 
     ///////////////////////////// 
     } 
    catch(Exception ex) 
     { 
     String sErrMsg = String.Concat("Fail to release resources related to the ", 
             "use of the camera. The error message is: ", 
             ex.Message); 
     await new MessageDialog(sErrMsg, "Error").ShowAsync(); 
     } 
    } 

其他的事情是,我需要我的時候初始化CaptureElement火炬更換使用閃光燈。原因是我更喜歡用火炬來持續照明。無可否認,這與這個問題無關。但是我提到這一點只是爲了解釋爲什麼這個版本InitCapture()從我原來的一個看起來不一樣:

private async void InitCapture() 
    // Initialize everything about MediaCapture. 
    { 
    this.captureMgr = new MediaCapture(); 
    await this.captureMgr.InitializeAsync(); 

    // Skip the steps to set the photo resolution to simplify 
    // the sample program. 

    // Start the camera preview. 
    captureElement.Source = this.captureMgr; 
    await this.captureMgr.StartPreviewAsync(); 

    // Ask the camera to auto-focus now. 
    var focusControl = this.captureMgr.VideoDeviceController.FocusControl; 
    var settings = new FocusSettings { Mode   = FocusMode.Continuous, 
             AutoFocusRange = AutoFocusRange.FullRange }; 
    focusControl.Configure(settings); 
    await focusControl.FocusAsync();  // Wait for the camera to focus 

    // Turn on the torch in case the lighting is dim. Without enough 
    // lighting, the auto-focus feature of the camera cannot work. 
    var cameraTorch = this.captureMgr.VideoDeviceController.TorchControl; 
    if (cameraTorch.Supported) 
     { 
     if (cameraTorch.PowerSupported) 
     cameraTorch.PowerPercent = 100; 
     cameraTorch.Enabled = true; 
     } 

    #region Error handling 
    MediaCaptureFailedEventHandler handler = (sender, e) => 
     { 
     System.Threading.Tasks.Task task = System.Threading.Tasks.Task.Run(async() => 
     { 
     await new MessageDialog("There was an error capturing the video from camera.", "Error").ShowAsync(); 
     }); 
     }; 

    this.captureMgr.Failed += handler; 
    #endregion 
    } 

我已經在三個不同的Windows Mobile手機10試過這種。他們都工作。

希望這可以幫助別人。

Jay Chan

+0

不知何故,如果手機沒有手電筒或手電筒(如Lumia 635),此方法(重置捕獲媒體)將導致頻繁的程序崩潰。因此,如果有人想要使用這種方法,他需要在重置捕獲媒體之前檢查設備是否帶有手電筒或手電筒。當然,如果設備沒有手電筒或手電筒,無論如何都不需要使用這種方法。 –

相關問題