Win10/UWP 扫描二维码

在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


  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
转载的东西: 本来zxing的c++部分不是为windows准备的,在windows编译应该用mingw比较合适。但我不熟悉这个。今天试一下,似乎可以在VS2008编译。虽然有很多问题,不过都可以解决的。 大概有如下问题: 1。isnan, NAN, INFINITY, fmax等一些常量或函数找不到,这是linux与windows包含文件的差异。自己创建就行,我做在nan.cpp和nan.h之。 2。文件同名:可以把那些文件编译到不同目录,这样就不会干扰了。默认是编译到同一个目录。 3。变长数组的语法:GCC支持变长的数组变量,比如 void gcc(int len) { int data[len]; } 但VC不支持,所以很多地方都要改过来。我的做法是:查到它所有的调用之处,找一个比较大的数值来取代len。 4。iconv.h: 要下载: http://gnuwin32.sourceforge.net/packages/libiconv.htm 需要DLL和lib导入库。我上传的代码不用iconv。通过设置NO_ICONV,可以不需要libiconv,但是扫描结果也没有转换,需要调用方自己做字符集转换。 经过这些,应该可以编译了。 编译它的示例: 这要求有ImageMagick,直接下载一个安装, 安装完成后,新建一个windows控制台项目,导入示例,设置好ImageMagick和zxing头文件和库文件目录。编译后,运行。 我放在zxtest项目。 根据示例,写pascal接口,这部分代码放在ZXingDLL。 通过分析,LuminanceSource应该是一个zxing分析图像的接口,要从这个派生出来一个类才能让zxing工作。示例是用MagickBitmapSource ,它用了ImageMagick库,太大,所以我分析了源码,发现只要输出灰度就行了,这样我在DELPHI获取图像,然后转成灰度图,再转进来。具体看我的DELPHI和lazarus代码。 上传的压缩包没有带dll,只有工程文件,谁有VS2008编译一下吧。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值