作者:手持三防加固平板電腦pad手持終端PDA定制專家 來源:www.quedicen.com 發布時間:2019-08-07 12:52 瀏覽量:
現在一維碼二維碼的應用場景越來越多,通過攝像頭來軟解條碼的方式也越來越多,下面研維工程師就為大家介紹一下通過攝像頭掃描一維碼/二維碼(windows系統):相機軟解碼方案的具體實施步驟,希望對大家有所啟迪。
1、首先打開VS2015開發環境,新建UWP工程,右鍵項目引用,打開Nuget包管理器搜索安裝:ZXing.Net.Mobile
2、該工程基于ZXing框架,應用部署于基于windows10系統的PDA手持設備之中,而非wince,請注意。
3、其中BarcodePage.xmal.cs后臺源碼如下:
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices.WindowsRuntime;
using System.Threading.Tasks;
using Windows.ApplicationModel;
using Windows.Devices.Enumeration;
using Windows.Foundation;
using Windows.Foundation.Collections;
using Windows.Graphics.Display;
using Windows.Graphics.Imaging;
using Windows.Media;
using Windows.Media.Capture;
using Windows.Media.Devices;
using Windows.Media.MediaProperties;
using Windows.Storage;
using Windows.Storage.FileProperties;
using Windows.Storage.Streams;
using Windows.UI.Core;
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;
using Windows.UI.Xaml.Navigation;
using ZXing;
// https://go.microsoft.com/fwlink/?LinkId=234238 上介紹了“空白頁”項模板
namespace SuperTools.Views
{
/// <summary>
/// 可用于自身或導航至 Frame 內部的空白頁。
/// </summary>
public sealed partial class BarcodePage : Page
{
private Result _result;
private MediaCapture _mediaCapture;
private DispatcherTimer _timer;
private bool IsBusy;
private bool _isPreviewing = false;
private bool _isInitVideo = false;
BarcodeReader barcodeReader;
private static readonly Guid RotationKey = new Guid("C380465D-2271-428C-9B83-ECEA3B4A85C1");
public BarcodePage()
{
barcodeReader = new BarcodeReader
{
AutoRotate = true,
Options = new ZXing.Common.DecodingOptions { TryHarder = true }
};
this.InitializeComponent();
this.NavigationCacheMode = NavigationCacheMode.Required;
Application.Current.Suspending += Application_Suspending;
Application.Current.Resuming += Application_Resuming;
}
private async void Application_Suspending(object sender, SuspendingEventArgs e)
{
// Handle global application events only if this page is active
if (Frame.CurrentSourcePageType == typeof(MainPage))
{
var deferral = e.SuspendingOperation.GetDeferral();
await CleanupCameraAsync();
deferral.Complete();
}
}
private void Application_Resuming(object sender, object o)
{
// Handle global application events only if this page is active
if (Frame.CurrentSourcePageType == typeof(MainPage))
{
InitVideoCapture();
}
}
protected override async void OnNavigatingFrom(NavigatingCancelEventArgs e)
{
// Handling of this event is included for completenes, as it will only fire when navigating between pages and this sample only includes one page
await CleanupCameraAsync();
}
protected override void OnNavigatedTo(NavigationEventArgs e)
{
base.OnNavigatedTo(e);
InitVideoCapture();
}
private async Task CleanupCameraAsync()
{
if (_isPreviewing)
{
await StopPreviewAsync();
}
_timer.Stop();
if (_mediaCapture != null)
{
_mediaCapture.Dispose();
_mediaCapture = null;
}
}
private void InitVideoTimer()
{
_timer = new DispatcherTimer();
_timer.Interval = TimeSpan.FromSeconds(1);
_timer.Tick += _timer_Tick;
_timer.Start();
}
private async Task StopPreviewAsync()
{
_isPreviewing = false;
await _mediaCapture.StopPreviewAsync();
// Use the dispatcher because this method is sometimes called from non-UI threads
await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
{
VideoCapture.Source = null;
});
}
private async void _timer_Tick(object sender, object e)
{
try
{
if (!IsBusy)
{
IsBusy = true;
var previewProperties = _mediaCapture.VideoDeviceController.GetMediaStreamProperties(MediaStreamType.VideoPreview) as VideoEncodingProperties;
VideoFrame videoFrame = new VideoFrame(BitmapPixelFormat.Bgra8, (int)previewProperties.Width, (int)previewProperties.Height);
VideoFrame previewFrame = await _mediaCapture.GetPreviewFrameAsync(videoFrame);
WriteableBitmap bitmap = new WriteableBitmap(previewFrame.SoftwareBitmap.PixelWidth, previewFrame.SoftwareBitmap.PixelHeight);
previewFrame.SoftwareBitmap.CopyToBuffer(bitmap.PixelBuffer);
await Task.Factory.StartNew(async () => { await ScanBitmap(bitmap); });
}
IsBusy = false;
await Task.Delay(50);
}
catch (Exception)
{
IsBusy = false;
}
}
/// <summary>
/// 解析二維碼圖片
/// </summary>
/// <param name="writeableBmp">圖片</param>
/// <returns></returns>
private async Task ScanBitmap(WriteableBitmap writeableBmp)
{
try
{
await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
{
_result = barcodeReader.Decode(writeableBmp.PixelBuffer.ToArray(), writeableBmp.PixelWidth, writeableBmp.PixelHeight, RGBLuminanceSource.BitmapFormat.Unknown);
if (_result != null)
{
//TODO: 掃描結果:_result.Text
}
});
}
catch (Exception)
{
}
}
private async void InitVideoCapture()
{
///攝像頭的檢測
var cameraDevice = await FindCameraDeviceByPanelAsync(Windows.Devices.Enumeration.Panel.Back);
if (cameraDevice == null)
{
System.Diagnostics.Debug.WriteLine("No camera device found!");
return;
}
var settings = new MediaCaptureInitializationSettings
{
StreamingCaptureMode = StreamingCaptureMode.Video,
MediaCategory = MediaCategory.Other,
AudioProcessing = AudioProcessing.Default,
VideoDeviceId = cameraDevice.Id
};
_mediaCapture = new MediaCapture();
await _mediaCapture.InitializeAsync(settings);
VideoCapture.Source = _mediaCapture;
await _mediaCapture.StartPreviewAsync();
var props = _mediaCapture.VideoDeviceController.GetMediaStreamProperties(MediaStreamType.VideoPreview);
props.Properties.Add(RotationKey, 90);
await _mediaCapture.SetEncodingPropertiesAsync(MediaStreamType.VideoPreview, props, null);
var focusControl = _mediaCapture.VideoDeviceController.FocusControl;
if (focusControl.Supported)
{
await focusControl.UnlockAsync();
var setting = new FocusSettings { Mode = FocusMode.Continuous, AutoFocusRange = AutoFocusRange.FullRange };
focusControl.Configure(setting);
await focusControl.FocusAsync();
}
_isPreviewing = true;
_isInitVideo = true;
InitVideoTimer();
}
private static async Task<DeviceInformation> FindCameraDeviceByPanelAsync(Windows.Devices.Enumeration.Panel desiredPanel)
{
var allVideoDevices = await DeviceInformation.FindAllAsync(DeviceClass.VideoCapture);
DeviceInformation desiredDevice = allVideoDevices.FirstOrDefault(x => x.EnclosureLocation != null && x.EnclosureLocation.Panel == desiredPanel);
return desiredDevice ?? allVideoDevices.FirstOrDefault();
}
}
}
4、其中BarcodePage.xmal頁面的源碼如下:
<Page
x:Class="SuperTools.Views.BarcodePage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:SuperTools.Views"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<Page.Transitions>
<TransitionCollection>
<NavigationThemeTransition>
<SlideNavigationTransitionInfo />
</NavigationThemeTransition>
</TransitionCollection>
</Page.Transitions>
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Grid x:Name="LayoutRoot" >
<Grid x:Name="ContentPanel" >
<!--視頻流預覽-->
<CaptureElement x:Name="VideoCapture" Stretch="UniformToFill"/>
<Grid Width="300" Height="300" x:Name="ViewGrid">
<Rectangle Width="3" Height="50" Fill="Orange" HorizontalAlignment="Left" VerticalAlignment="Top"/>
<Rectangle Width="3" Height="50" Fill="Orange" HorizontalAlignment="Right" VerticalAlignment="Top"/>
<Rectangle Width="3" Height="50" Fill="Orange" HorizontalAlignment="Left" VerticalAlignment="Bottom"/>
<Rectangle Width="3" Height="50" Fill="Orange" HorizontalAlignment="Right" VerticalAlignment="Bottom"/>
<Rectangle Width="50" Height="3" Fill="Orange" HorizontalAlignment="Left" VerticalAlignment="Top"/>
<Rectangle Width="50" Height="3" Fill="Orange" HorizontalAlignment="Right" VerticalAlignment="Top"/>
<Rectangle Width="50" Height="3" Fill="Orange" HorizontalAlignment="Left" VerticalAlignment="Bottom"/>
<Rectangle Width="50" Height="3" Fill="Orange" HorizontalAlignment="Right" VerticalAlignment="Bottom"/>
<Rectangle x:Name="recScanning" Margin="12,0,12,0" VerticalAlignment="Center" Height="2" Fill="Green" RenderTransformOrigin="0.5,0.5" />
</Grid>
</Grid>
</Grid>
</Grid>
</Page>