在Win10开发中,扫描二维码以及拍照都和以前的Windows 8.1 相同,是使用MediaCapture对象来获取图片或者视频预览数据,通过MediaCapture的CapturePhotoToStreamAsync()方法就可以拿到IRandomAccessStream流进行二维码解析或者做其他的图片操作,MediaCapture也提供了CapturePhotoToStorageFileAsync()方法来获取到IStorageFile流进行文件的操作。
下面贴下代码展示下Win10中的扫描二维码,就不一一讲解了,和以前的Windows8.1的方法类似,解析二维码用的 zxing.net 。
前台(需要注意的是用了Behaviors,记得添加 Behaviors SDK 的引用):
<Page.Resources>
<Storyboard x:Name="LineStoryboard" AutoReverse="True" RepeatBehavior="Forever">
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(CompositeTransform.TranslateY)" Storyboard.TargetName="recScanning">
<EasingDoubleKeyFrame KeyTime="0" Value="0"/>
<EasingDoubleKeyFrame KeyTime="0:0:1.5" Value="-269.94"/>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</Page.Resources>
<Interactivity:Interaction.Behaviors>
<Core:EventTriggerBehavior EventName="Loaded">
<Media:ControlStoryboardAction Storyboard="{StaticResource LineStoryboard}"/>
</Core:EventTriggerBehavior>
</Interactivity:Interaction.Behaviors>
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Grid x:Name="LayoutRoot" >
<Grid x:Name="ContentPanel" >
<!--视频流预览-->
<CaptureElement x:Name="VideoCapture"/>
<!--Tips-->
<TextBlock x:Name="tbkTip" Foreground="White" VerticalAlignment="Bottom" HorizontalAlignment="Center" Margin="36" Text="提示:请将二维码图案放置在取景框内"/>
<Grid Width="306" Height="306">
<Rectangle Width="3" Height="50" Fill="Red" HorizontalAlignment="Left" VerticalAlignment="Top"/>
<Rectangle Width="3" Height="50" Fill="Red" HorizontalAlignment="Right" VerticalAlignment="Top"/>
<Rectangle Width="3" Height="50" Fill="Red" HorizontalAlignment="Left" VerticalAlignment="Bottom"/>
<Rectangle Width="3" Height="50" Fill="Red" HorizontalAlignment="Right" VerticalAlignment="Bottom"/>
<Rectangle Width="50" Height="3" Fill="Red" HorizontalAlignment="Left" VerticalAlignment="Top"/>
<Rectangle Width="50" Height="3" Fill="Red" HorizontalAlignment="Right" VerticalAlignment="Top"/>
<Rectangle Width="50" Height="3" Fill="Red" HorizontalAlignment="Left" VerticalAlignment="Bottom"/>
<Rectangle Width="50" Height="3" Fill="Red" HorizontalAlignment="Right" VerticalAlignment="Bottom"/>
<Rectangle x:Name="recScanning" Margin="12,0,12,16" Height="2" RenderTransformOrigin="0.5,0.5" VerticalAlignment="Bottom" d:LayoutOverrides="Height">
<Rectangle.RenderTransform>
<CompositeTransform/>
</Rectangle.RenderTransform>
<Rectangle.Projection>
<PlaneProjection/>
</Rectangle.Projection>
<Rectangle.Fill>
<LinearGradientBrush EndPoint="0,0.5" StartPoint="1,0.5">
<GradientStop Color="#331CF106" Offset="0.15"/>
<GradientStop Color="#331CF106" Offset="0.85"/>
<GradientStop Color="#FF1CF106" Offset="0.5"/>
</LinearGradientBrush>
</Rectangle.Fill>
</Rectangle>
</Grid>
</Grid>
<!--扫描结果-->
<TextBlock x:Name="tbkResult" Grid.Row="1" Foreground="White" VerticalAlignment="Top" TextWrapping="Wrap" Margin="12,18" FontSize="25" Text="扫描结果:"/>
</Grid>
</Grid>
后台:
public sealed partial class MainPage : Page
{
private Result _result;
private readonly MediaCapture _mediaCapture = new MediaCapture();
private DispatcherTimer _timer;
private bool IsBusy;
public MainPage()
{
this.InitializeComponent();
}
protected override void OnNavigatedTo(NavigationEventArgs e)
{
base.OnNavigatedTo(e);
InitVideoCapture();
InitVideoTimer();
}
private void InitVideoTimer()
{
_timer = new DispatcherTimer();
_timer.Interval = TimeSpan.FromSeconds(3);
_timer.Tick += _timer_Tick;
_timer.Start();
}
private async void _timer_Tick(object sender, object e)
{
try
{
Debug.WriteLine(@"[INFO]开始扫描 -> " + DateTime.Now.ToString());
if (!IsBusy)
{
IsBusy = true;
IRandomAccessStream stream = new InMemoryRandomAccessStream();
await _mediaCapture.CapturePhotoToStreamAsync(ImageEncodingProperties.CreateJpeg(), stream);
var writeableBmp = await ReadBitmap(stream, ".jpg");
await Task.Factory.StartNew(async () => { await ScanBitmap(writeableBmp); });
}
IsBusy = false;
await Task.Delay(50);
}
catch (Exception)
{
IsBusy = false;
}
}
/// <summary>
/// 保存照片
/// </summary>
/// <param name="stream"></param>
/// <param name="fileName"></param>
/// <param name="photoOrientation"></param>
/// <returns></returns>
private static async Task ReencodeAndSavePhotoAsync(IRandomAccessStream stream, string fileName, PhotoOrientation photoOrientation = PhotoOrientation.Normal)
{
using (var inputStream = stream)
{
var decoder = await BitmapDecoder.CreateAsync(inputStream);
var file = await KnownFolders.PicturesLibrary.CreateFileAsync(fileName, CreationCollisionOption.GenerateUniqueName);
using (var outputStream = await file.OpenAsync(FileAccessMode.ReadWrite))
{
var encoder = await BitmapEncoder.CreateForTranscodingAsync(outputStream, decoder);
// Set the orientation of the capture
var properties = new BitmapPropertySet { { "System.Photo.Orientation", new BitmapTypedValue(photoOrientation, PropertyType.UInt16) } };
await encoder.BitmapProperties.SetPropertiesAsync(properties);
await encoder.FlushAsync();
}
}
}
static Guid DecoderIDFromFileExtension(string strExtension)
{
Guid encoderId;
switch (strExtension.ToLower())
{
case ".jpg":
case ".jpeg":
encoderId = BitmapDecoder.JpegDecoderId;
break;
case ".bmp":
encoderId = BitmapDecoder.BmpDecoderId;
break;
case ".png":
default:
encoderId = BitmapDecoder.PngDecoderId;
break;
}
return encoderId;
}
public static Size MaxSizeSupported = new Size(4000, 3000);
/// <summary>
/// 读取照片流 转为WriteableBitmap给二维码解码器
/// </summary>
/// <param name="fileStream"></param>
/// <param name="type"></param>
/// <returns></returns>
public async static Task<WriteableBitmap> ReadBitmap(IRandomAccessStream fileStream, string type)
{
WriteableBitmap bitmap = null;
try
{
Guid decoderId = DecoderIDFromFileExtension(type);
BitmapDecoder decoder = await BitmapDecoder.CreateAsync(decoderId, fileStream);
BitmapTransform tf = new BitmapTransform();
uint width = decoder.OrientedPixelWidth;
uint height = decoder.OrientedPixelHeight;
double dScale = 1;
if (decoder.OrientedPixelWidth > MaxSizeSupported.Width || decoder.OrientedPixelHeight > MaxSizeSupported.Height)
{
dScale = Math.Min(MaxSizeSupported.Width / decoder.OrientedPixelWidth, MaxSizeSupported.Height / decoder.OrientedPixelHeight);
width = (uint)(decoder.OrientedPixelWidth * dScale);
height = (uint)(decoder.OrientedPixelHeight * dScale);
tf.ScaledWidth = (uint)(decoder.PixelWidth * dScale);
tf.ScaledHeight = (uint)(decoder.PixelHeight * dScale);
}
bitmap = new WriteableBitmap((int)width, (int)height);
PixelDataProvider dataprovider = await decoder.GetPixelDataAsync(BitmapPixelFormat.Bgra8, BitmapAlphaMode.Straight, tf,
ExifOrientationMode.RespectExifOrientation, ColorManagementMode.DoNotColorManage);
byte[] pixels = dataprovider.DetachPixelData();
Stream pixelStream2 = bitmap.PixelBuffer.AsStream();
pixelStream2.Write(pixels, 0, pixels.Length);
//bitmap.SetSource(fileStream);
}
catch
{
}
return bitmap;
}
/// <summary>
/// 解析二维码图片
/// </summary>
/// <param name="writeableBmp">图片</param>
/// <returns></returns>
private async Task ScanBitmap(WriteableBitmap writeableBmp)
{
try
{
var barcodeReader = new BarcodeReader
{
AutoRotate = true,
Options = new ZXing.Common.DecodingOptions { TryHarder = true }
};
await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
{
_result = barcodeReader.Decode(writeableBmp);
});
if (_result != null)
{
Debug.WriteLine(@"[INFO]扫描到二维码:{result} ->" + _result.Text);
await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
{
tbkResult.Text = _result.Text;
});
}
}
catch (Exception)
{
}
}
private async void InitVideoCapture()
{
///摄像头的检测
var cameraDevice = await FindCameraDeviceByPanelAsync(Windows.Devices.Enumeration.Panel.Back);
if (cameraDevice == null)
{
Debug.WriteLine("No camera device found!");
return;
}
var settings = new MediaCaptureInitializationSettings
{
StreamingCaptureMode = StreamingCaptureMode.Video,
MediaCategory = MediaCategory.Other,
AudioProcessing = Windows.Media.AudioProcessing.Default,
VideoDeviceId = cameraDevice.Id
};
await _mediaCapture.InitializeAsync(settings);
VideoCapture.Source = _mediaCapture;
await _mediaCapture.StartPreviewAsync();
}
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();
}
}
效果:
本文出自:53078485群大咖Aran