我正在使用Windows 10平台上的通用Windows应用程序。该应用程序应该使用相机捕获条形码,并使用条形码做一些有用的事情。到目前为止,它可以很好地捕获和翻译条形码(使用ZXing Library)。我可以通过单击每个条形码一次按钮来一个接一个地捕获条形码。
但是我需要它在光线不足的情况下工作。我想让相机在光线不足的情况下自动打开手电筒(或手电筒)。我发现在我拍摄第一张照片之前,相机可以在光线不足的情况下自动打开手电筒(或手电筒)。不知何故,手电筒在第一张照片后自动关闭。只要用户仍然停留在我的应用程序的同一页面(并且只要环境昏暗),我希望它保持打开状态。请帮我解决这个问题。
到目前为止,我可以确定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手机是Microsoft Lumia 640 LTE,Windows 10 Moblile版本1511 OS-Built 10.0.10586.107。
请帮我解决这个问题。也欢迎任何建议。
提前致谢。
杰伊陈答案 0 :(得分: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手机中尝试过此功能。他们都工作。
希望这有助于某人。
杰伊陈