2016-12-02 14 views
0

Я работаю над универсальным приложением Windows в платформе Windows 10. Предполагается, что приложение использует камеру для захвата штрих-кода и делает что-то полезное со штрих-кодом. Пока что он отлично работает с захватом и переводом штрих-кода (с использованием библиотеки ZXing). Я могу использовать его для захвата штрих-кода один за другим, нажав кнопку один раз для каждого штрих-кода.Фонарик камеры в моем универсальном приложении для 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, чтобы попробовать тестовое приложение выше, я прокомментировал все, что связано с библиотекой ZXing в тестовом приложении.

Пользователь может решить проблему, оставив эту страницу (и обратно в главное меню), а затем перейдя вправо на ту же страницу. Это сбрасывает что-то в программе и снова активирует функцию автофокуса. Очевидно, что это нехорошее обходное решение, потому что пользователю нужно делать это для каждого отдельного штрих-кода. Обратите внимание, что тестовое приложение, показанное выше, имеет только одну страницу и не имеет главного меню. Таким образом, вы не сможете увидеть это обходное решение, используя тестовое приложение выше.

Я попытался обход этого путем сброса MediaCapture после того, как вы сделали каждую фотографию. Это делается путем вызова ReleaseCapture() и InitCapture() в моем тестовом приложении, показанном выше. К сожалению, это не только замедляет каждый захват штрих-кода, но также вызывает срабатывание System.ObjectDisposedException об объекте не инициализируется или что-то в этом роде. Во всяком случае, я предпочитаю исправить исходную проблему вместо использования обходного пути.

Кстати, на моем ПК разработки у меня есть Windows 10 Professional и Visual Studio 2015 Professional. Телефон Windows, который я использую, - это Microsoft Lumia 640 LTE с Windows 10 Moblile версии 1511 OS-Built 10.0.10586.107.

Пожалуйста, помогите мне решить эту проблему. Также приветствуем любое предложение.

Заранее спасибо.

Джей Чан

+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). Поэтому, если кто-то хочет использовать этот метод, ему необходимо проверить, есть ли у устройства фонарик или факел перед сбросом носителя захвата. Конечно, если устройство не имеет фонарика или фонарика, нет необходимости использовать этот метод в любом случае. –