Win10/UWP开发:让你的App使用上扫描仪

UWP的扫描仪功能现在被微软划分到了[Windows Desktop Extensions for the UWP]中,如果要使用扫描仪扫描图片到自己的App中,首先我们要添加[Windows Desktop Extensions for the UWP]的引用,这个dll中的所有类都是只能在Desktop设备上才能正常运行的。添加[Windows Desktop Extensions for the UWP]




扫描仪需要用Windows.Devices.Scanners 命名空间下的成员,有几个很重要的成员先介绍下:
ImageScanner 类
  • ImageScanner.DefaultScanSource       //获取为此扫描仪设备选择的默认扫描源
  • ImageScanner.DeviceId            //获取此扫描仪设备的 PnP 设备标识符
  • ImageScanner.FlatbedConfiguration    //获取并设置平板扫描单元的扫描设置,如扫描分辨率和颜色模式
  • ImageScanner.FromIdAsync        //创建基于扫描仪设备信息 ID 的 ImageScanner 对象的实例
  • ImageScanner.ScanFilesToFolderAsync        //扫描文件到文件夹 ,支持进度报告
  • ImageScanner.ScanPreviewToStreamAsync    //扫描文件到流

ImageScannerFlatbedConfiguration 类(这个类里面有很多属性都是和设置扫描仪有关的,主要的如下,其他就不一一列举了)

  • ImageScannerFlatbedConfiguration.ColorMode    //获取或设置平板扫描仪的颜色模式如黑白灰度等
  • ImageScannerFlatbedConfiguration.DesiredResolution    //获取或设置应用程序请求的扫描仪平板的水平和垂直扫描分辨率(以 DPI 为单位)
  • ImageScannerFlatbedConfiguration.Format        //获取或设置从扫描仪的平板到客户端应用程序的图像数据获取的当前文件传输格式。
  • ImageScannerFlatbedConfiguration.SelectedScanRegion    //获取或设置选定扫描区域的原始坐标(水平和垂直)和维度(宽度和高度)(以英寸为单位)

接下来,我们需要一台扫描仪,扫描仪装好驱动,并支持WIA 2.0 .我的是TOSHIBA 2008S
然后创建一个页面, 前台代码如下
<Page.BottomAppBar>
        <CommandBar>
            <CommandBar.Content>
                <Grid/>
            </CommandBar.Content>
            <AppBarButton Icon="Scan" Label="Scan Images" x:Name="Bar_ScanFiles" Click="Bar_ScanFiles_Click"/>
        </CommandBar>
    </Page.BottomAppBar>
 
    <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}" >
        <Viewbox>
            <Grid>
                <Path Data="M0,589.122C7.23756,591.35,15.1453,592.686,23.5452,592.686L734.433,592.686C742.831,592.686,750.74,591.35,758,589.122L746.228,633.25C746.228,642.477,735.684,650,722.639,650L35.3397,650C22.3137,650,11.7945,642.477,11.7945,633.25z M410.134,418.119L541.24,418.119 635.51,532.435 363.028,532.435z M209.217,402.719C198.74,402.719,195.772,408.064,187.462,416.255L73.5126,540.241C73.5126,547.715,81.9774,553.729,92.4548,553.729L378.964,553.729 665.473,553.729C675.95,553.729,684.484,547.715,684.484,540.241L570.516,416.255C562.228,408.064,559.258,402.719,548.757,402.719L378.964,402.719z M168.384,389.421L378.964,389.421 589.591,389.421C602.638,389.421,606.277,396.102,616.622,406.219L758,560.028C758,569.288,747.43,576.795,734.433,576.795L378.964,576.795 23.5452,576.795C10.5443,576.795,0,569.288,0,560.028L141.375,406.219C151.651,396.102,155.358,389.421,168.384,389.421z M164.949,0L378.966,0 593.029,0C606.078,-5E-06,616.621,7.50893,616.621,16.7822L616.621,358.018C616.621,367.277,606.078,374.785,593.029,374.785L378.966,374.785 164.949,374.785C151.925,374.785,141.379,367.277,141.379,358.018L141.379,16.7822C141.379,7.50893,151.925,-5E-06,164.949,0z" Stretch="Uniform" Fill="#FF434343" Width="160" Height="160" Margin="0,0,0,0" RenderTransformOrigin="0.5,0.5">
                    <Path.RenderTransform>
                        <TransformGroup>
                            <TransformGroup.Children>
                                <RotateTransform Angle="0" />
                                <ScaleTransform ScaleX="0.5" ScaleY="0.5" />
                            </TransformGroup.Children>
                        </TransformGroup>
                    </Path.RenderTransform>
                </Path>
            </Grid>
        </Viewbox>
 
        <GridView x:Name="ImgList"></GridView>
 
</Grid>


后台代码如下
/// <summary>
      /// 开始扫描
      /// </summary>
      /// <param name="sender"></param>
      /// <param name="e"></param>
      private async void Bar_ScanFiles_Click(object sender, RoutedEventArgs e)
      {
          var scanner = await GetScanner();
          if (scanner == null) return;
 
          //保存至用户图片库
          //var results = await scanner.ScanFilesToFolderAsync(scanner.DefaultScanSource, KnownFolders.PicturesLibrary);
 
          //取消任务的Token
          cancellationToken = new CancellationTokenSource();
 
          //扫描中的对话框
          ContentDialog dialog = new ContentDialog();
          dialog.Title = new TextBlock { Text = "扫描中...", FontSize = 14 };
          dialog.Content = new Scaning() { Width = 200, Height = 200 };
          dialog.PrimaryButtonText = "取消";
          dialog.PrimaryButtonClick += (s, a) =>
          {
              cancellationToken.Cancel();
              cancellationToken.Token.Register(() =>
              {
                  dialog.Hide();
              });
          };
          dialog.ShowAsync();
          try
          {
             //获取预览 ->直接返回 Stream 不过图片质量很差 
             //IRandomAccessStream stream = new InMemoryRandomAccessStream(); 
             //await scanner.ScanPreviewToStreamAsync(scanner.DefaultScanSource, stream).AsTask(cancellationToken.Token);
 
             //扫描 -> 获取到扫描完成的文件 
             var files = await Scanner.ScanFilesToFolderAsync(Scanner.DefaultScanSource, KnownFolders.SavedPictures).AsTask(cancellationToken.Token);
 
             for (int i = 0; i < files.ScannedFiles.Count; i++) 
             { 
                 //创建文件读取流 
                 using (var fileStream = await files.ScannedFiles[i].OpenStreamForReadAsync()) 
                 { 
                     var bitmap = new BitmapImage(); 
                     await bitmap.SetSourceAsync(fileStream.AsRandomAccessStream()); 
                     ImgList.Items.Add(new Image { Source = bitmap });
                 }
                 //用完流后删除下图片 
                 await Task.Factory.StartNew(() => File.Delete(files.ScannedFiles[i].Path)); 
             } 
          }
          catch (TaskCanceledException)
          {
              Debug.WriteLine("A task was canceled.");
          }
          catch (Exception)
          {
              Debug.WriteLine("扫描出错");
          }
          finally
          {
              dialog.Hide();
          }
      }
 
      /// <summary>
      /// 获取扫描仪对象
      /// </summary>
      /// <returns>ImageScanner</returns>
      private async Task<ImageScanner> GetScanner()
      {
          try
          {
              var device = await DeviceInformation.FindAllAsync(DeviceClass.ImageScanner);
              var scanner = await ImageScanner.FromIdAsync(device.FirstOrDefault().Id);
              return scanner;
          }
          catch (Exception)
          {
              await OpenScannerWithError("你可以尝试以下操作后重试:\r\n1、未发现可用的扫描仪设备\r\n2、没有安装适合的WIA2.0兼容驱动程序",
                  true, "重试", true, "取消",
                  () => { Bar_ScanFiles_Click(null, null); });
              return null;
          }
      }
 
      /// <summary>
      /// 弹出错误提示
      /// </summary>
      /// <param name="error">错误描述</param>
      /// <param name="hasPrimaryBtn">是否具有主按钮</param>
      /// <param name="primaryBtnText">主按钮Text</param>
      /// <param name="hasSecondaryBtn">是否具有副按钮</param>
      /// <param name="secondaryBtnText">副按钮Text</param>
      /// <param name="primaryBtnClick">主按钮点击后执行的方法</param>
      /// <param name="secondaryBtnClick">副按钮点击后执行的方法</param>
      /// <returns>null</returns>
      private async Task OpenScannerWithError(string error, bool hasPrimaryBtn = false, string primaryBtnText = null, bool hasSecondaryBtn = false, string secondaryBtnText = null, Action primaryBtnClick = null, Action secondaryBtnClick = null)
      {
          ContentDialog dialog = new ContentDialog();
          var dialogTitle = new StackPanel();
 
          dialogTitle.Children.Add(new TextBlock { Text = "出错啦 ( ▼-▼ )", Foreground = new SolidColorBrush(Colors.Red) });
 
          var dialogContent = new StackPanel() { Margin = new Thickness(0, 12, 0, 0) };
 
          dialogContent.Children.Add(new TextBlock { Text = error });
 
          dialog.Title = dialogTitle;
 
          dialog.Content = dialogContent;
 
          if (hasPrimaryBtn)
          {
              dialog.PrimaryButtonText = "重试";
              if (primaryBtnClick != null)
              {
                  dialog.Hide();
                  dialog.PrimaryButtonClick += (s, a) =>
                  {
                      primaryBtnClick();
                  };
              }
          }
 
          if (hasSecondaryBtn)
          {
              dialog.SecondaryButtonText = "取消";
 
              dialog.SecondaryButtonClick += (s, a) =>
              {
                  dialog.Hide();
                  if (secondaryBtnClick != null)
                  {
                      secondaryBtnClick();
                  }
              };
          }
          await dialog.ShowAsync();
      }


用到的一个 UserControl –> Scaning, 是用来显示扫描中动画的, 前台代码如下
<UserControl
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:ScannerDeviceSample.UserControls"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:Interactivity="using:Microsoft.Xaml.Interactivity" xmlns:Core="using:Microsoft.Xaml.Interactions.Core" xmlns:Media="using:Microsoft.Xaml.Interactions.Media"
    x:Class="ScannerDeviceSample.UserControls.Scaning"
    mc:Ignorable="d"
    d:DesignHeight="200"
    d:DesignWidth="200">
    <UserControl.Resources>
        <Storyboard x:Name="ScaningStoryboard" AutoReverse="True" RepeatBehavior="Forever">
            <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(CompositeTransform.TranslateY)" Storyboard.TargetName="recScanning">
                <EasingDoubleKeyFrame KeyTime="0" Value="0"/>
                <EasingDoubleKeyFrame KeyTime="0:0:2" Value="-200"/>
            </DoubleAnimationUsingKeyFrames>
        </Storyboard>
    </UserControl.Resources>
 
    <Interactivity:Interaction.Behaviors>
        <Core:EventTriggerBehavior EventName="Loaded">
            <Media:ControlStoryboardAction Storyboard="{StaticResource ScaningStoryboard}"/>
        </Core:EventTriggerBehavior>
    </Interactivity:Interaction.Behaviors>
 
    <Grid>
        <Path  Data="M2.8160041,17.083004L2.8160041,18.351004 15.944004,18.351004 15.944004,17.083004z M2.8160041,13.907004L2.8160041,15.174004 15.944004,15.174004 15.944004,13.907004z M2.8160041,10.731004L2.8160041,11.999004 15.944004,11.999004 15.944004,10.731004z M0,1.356853E-05L10.572985,1.356853E-05 10.572985,7.9669956 18.761999,7.9669956 18.761999,21.176014 0,21.176014z M11.945004,0L18.761988,6.6610196 11.945004,6.6610196z" Stretch="Uniform" Fill="Black" Width="128" Height="128" Margin="0,0,0,0" RenderTransformOrigin="0.5,0.5">
            <Path.RenderTransform>
                <TransformGroup>
                    <RotateTransform Angle="0" />
                    <ScaleTransform ScaleX="0.8" ScaleY="1" />
                </TransformGroup>
            </Path.RenderTransform>
        </Path>
        <Rectangle x:Name="recScanning"   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>
</UserControl>



最后的效果


具有设置选项的效果



本文出自:53078485群大咖Aran


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值