我正在尝试在 WinUI 3 中从网络摄像头扫描二维码。我已经安装了 ZXing 和 AForge Video,但这些库在 WinUI 3 中无法正常工作。是否有任何解决方案或更兼容的替代方案?
ZXing(ZXing.NET是一个端口)完全与平台无关,因此只要您可以捕获某种“位图”(RGB等),无论它在给定平台上意味着什么,它都可以很好地与任何技术一起使用.
这是 WinUI3(确保您安装了最新的 WinUI3 nuget)示例应用程序,它执行两件事:
可以轻松更改代码以读取 XZing 支持的任何条形码(EAN13 等)。它包含 XZing 和 WinRT 的 SoftwareBitmap 之间的薄适配层(我从 XZing.NET 代码复制):
这是 WinUI3 页面的 XAML:
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="30" />
<RowDefinition Height="30" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Button Click="Button_Click">Toggle Capture</Button>
<TextBox x:Name="textBox" Grid.Row="1" />
<MediaPlayerElement
x:Name="player"
Grid.Row="2"
Width="600"
Height="600"
AutoPlay="True" />
</Grid>
WinUI3页面中的代码(您需要安装XZing.NET nuget包):
public sealed partial class MainPage : Page
{
private readonly SoftwareBitmapBarcodeReader _reader;
private MediaCapture _capture;
private MediaFrameReader _frameReader;
private MediaSource _mediaSource;
public MainPage()
{
InitializeComponent();
// set various xzing options (beware, all formats like All_1D can divide perf by orders of magnitude)
_reader = new SoftwareBitmapBarcodeReader
{
AutoRotate = true
};
_reader.Options.PossibleFormats = new[] { BarcodeFormat.QR_CODE };
_reader.Options.TryHarder = true;
}
private async void Button_Click(object sender, RoutedEventArgs e)
{
if (_capture == null)
{
await InitializeCaptureAsync();
return;
}
await TerminateCaptureAsync();
}
private async Task InitializeCaptureAsync()
{
// get first capture device (change this if you want)
var sourceGroup = (await MediaFrameSourceGroup.FindAllAsync())?.FirstOrDefault();
if (sourceGroup == null)
return; // not found!
// init capture & initialize
_capture = new MediaCapture();
await _capture.InitializeAsync(new MediaCaptureInitializationSettings
{
SourceGroup = sourceGroup,
SharingMode = MediaCaptureSharingMode.SharedReadOnly,
MemoryPreference = MediaCaptureMemoryPreference.Cpu, // to ensure we get SoftwareBitmaps
});
// initialize source
var source = _capture.FrameSources[sourceGroup.SourceInfos[0].Id];
// create reader to get frames & pass reader to player to visualize the webcam
_frameReader = await _capture.CreateFrameReaderAsync(source, MediaEncodingSubtypes.Bgra8);
_frameReader.FrameArrived += OnFrameArrived;
await _frameReader.StartAsync();
_mediaSource = MediaSource.CreateFromMediaFrameSource(source);
player.Source = _mediaSource;
}
private void OnFrameArrived(MediaFrameReader sender, MediaFrameArrivedEventArgs args)
{
var bmp = sender.TryAcquireLatestFrame()?.VideoMediaFrame?.SoftwareBitmap;
if (bmp == null)
return;
var result = _reader.Decode(bmp);
if (result != null)
{
// found a QR CODE
DispatcherQueue.TryEnqueue(() =>
{
textBox.Text = result.BarcodeFormat + ": " + result.Text;
});
}
}
private async Task TerminateCaptureAsync()
{
player.Source = null;
_mediaSource?.Dispose();
_mediaSource = null;
if (_frameReader != null)
{
_frameReader.FrameArrived -= OnFrameArrived;
await _frameReader.StopAsync();
_frameReader?.Dispose();
_frameReader = null;
}
_capture?.Dispose();
_capture = null;
}
}
// this is the thin layer that allows you to use XZing over WinRT's SoftwareBitmap
public class SoftwareBitmapBarcodeReader : BarcodeReader<SoftwareBitmap>
{
public SoftwareBitmapBarcodeReader()
: base(bmp => new SoftwareBitmapLuminanceSource(bmp))
{
}
}
// from https://github.com/micjahn/ZXing.Net/blob/master/Source/lib/BitmapLuminanceSource.SoftwareBitmap.cs
public class SoftwareBitmapLuminanceSource : BaseLuminanceSource
{
protected SoftwareBitmapLuminanceSource(int width, int height)
: base(width, height)
{
}
public SoftwareBitmapLuminanceSource(SoftwareBitmap softwareBitmap)
: base(softwareBitmap.PixelWidth, softwareBitmap.PixelHeight)
{
if (softwareBitmap.BitmapPixelFormat != BitmapPixelFormat.Gray8)
{
using SoftwareBitmap convertedSoftwareBitmap = SoftwareBitmap.Convert(softwareBitmap, BitmapPixelFormat.Gray8);
convertedSoftwareBitmap.CopyToBuffer(luminances.AsBuffer());
return;
}
softwareBitmap.CopyToBuffer(luminances.AsBuffer());
}
protected override LuminanceSource CreateLuminanceSource(byte[] newLuminances, int width, int height)
=> new SoftwareBitmapLuminanceSource(width, height) { luminances = newLuminances };
}
这是编码“Hello World”的二维码的结果: