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

然后创建一个页面,前台代码如下:

 1 <Page.BottomAppBar>
 2         <CommandBar>
 3             <CommandBar.Content>
 4                 <Grid/>
 5             </CommandBar.Content>
 6             <AppBarButton Icon="Scan" Label="Scan Images" x:Name="Bar_ScanFiles" Click="Bar_ScanFiles_Click"/>
 7         </CommandBar>
 8     </Page.BottomAppBar>
 9
10     <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}" >
11         <Viewbox>
12             <Grid>
13                 <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">
14                     <Path.RenderTransform>
15                         <TransformGroup>
16                             <TransformGroup.Children>
17                                 <RotateTransform Angle="0" />
18                                 <ScaleTransform ScaleX="0.5" ScaleY="0.5" />
19                             </TransformGroup.Children>
20                         </TransformGroup>
21                     </Path.RenderTransform>
22                 </Path>
23             </Grid>
24         </Viewbox>
25
26         <GridView x:Name="ImgList"></GridView>
27
28 </Grid>

后台代码如下:

  1 /// <summary>
  2       /// 开始扫描
  3       /// </summary>
  4       /// <param name="sender"></param>
  5       /// <param name="e"></param>
  6       private async void Bar_ScanFiles_Click(object sender, RoutedEventArgs e)
  7       {
  8           var scanner = await GetScanner();
  9           if (scanner == null) return;
 10
 11           //保存至用户图片库
 12           //var results = await scanner.ScanFilesToFolderAsync(scanner.DefaultScanSource, KnownFolders.PicturesLibrary);
 13
 14           //取消任务的Token
 15           cancellationToken = new CancellationTokenSource();
 16
 17           //扫描中的对话框
 18           ContentDialog dialog = new ContentDialog();
 19           dialog.Title = new TextBlock { Text = "扫描中...", FontSize = 14 };
 20           dialog.Content = new Scaning() { Width = 200, Height = 200 };
 21           dialog.PrimaryButtonText = "取消";
 22           dialog.PrimaryButtonClick += (s, a) =>
 23           {
 24               cancellationToken.Cancel();
 25               cancellationToken.Token.Register(() =>
 26               {
 27                   dialog.Hide();
 28               });
 29           };
 30           dialog.ShowAsync();
 31           try
 32           {
 33              //获取预览 ->直接返回 Stream 不过图片质量很差
 34              //IRandomAccessStream stream = new InMemoryRandomAccessStream();
 35              //await scanner.ScanPreviewToStreamAsync(scanner.DefaultScanSource, stream).AsTask(cancellationToken.Token);
 36
 37              //扫描 -> 获取到扫描完成的文件
 38              var files = await Scanner.ScanFilesToFolderAsync(Scanner.DefaultScanSource, KnownFolders.SavedPictures).AsTask(cancellationToken.Token);
 39
 40              for (int i = 0; i < files.ScannedFiles.Count; i++)
 41              {
 42                  //创建文件读取流
 43                  using (var fileStream = await files.ScannedFiles[i].OpenStreamForReadAsync())
 44                  {
 45                      var bitmap = new BitmapImage();
 46                      await bitmap.SetSourceAsync(fileStream.AsRandomAccessStream());
 47                      ImgList.Items.Add(new Image { Source = bitmap });
 48                  }
 49                  //用完流后删除下图片
 50                  await Task.Factory.StartNew(() => File.Delete(files.ScannedFiles[i].Path));
 51              }
 52           }
 53           catch (TaskCanceledException)
 54           {
 55               Debug.WriteLine("A task was canceled.");
 56           }
 57           catch (Exception)
 58           {
 59               Debug.WriteLine("扫描出错");
 60           }
 61           finally
 62           {
 63               dialog.Hide();
 64           }
 65       }
 66
 67       /// <summary>
 68       /// 获取扫描仪对象
 69       /// </summary>
 70       /// <returns>ImageScanner</returns>
 71       private async Task<ImageScanner> GetScanner()
 72       {
 73           try
 74           {
 75               var device = await DeviceInformation.FindAllAsync(DeviceClass.ImageScanner);
 76               var scanner = await ImageScanner.FromIdAsync(device.FirstOrDefault().Id);
 77               return scanner;
 78           }
 79           catch (Exception)
 80           {
 81               await OpenScannerWithError("你可以尝试以下操作后重试:\r\n1、未发现可用的扫描仪设备\r\n2、没有安装适合的WIA2.0兼容驱动程序",
 82                   true, "重试", true, "取消",
 83                   () => { Bar_ScanFiles_Click(null, null); });
 84               return null;
 85           }
 86       }
 87
 88       /// <summary>
 89       /// 弹出错误提示
 90       /// </summary>
 91       /// <param name="error">错误描述</param>
 92       /// <param name="hasPrimaryBtn">是否具有主按钮</param>
 93       /// <param name="primaryBtnText">主按钮Text</param>
 94       /// <param name="hasSecondaryBtn">是否具有副按钮</param>
 95       /// <param name="secondaryBtnText">副按钮Text</param>
 96       /// <param name="primaryBtnClick">主按钮点击后执行的方法</param>
 97       /// <param name="secondaryBtnClick">副按钮点击后执行的方法</param>
 98       /// <returns>null</returns>
 99       private async Task OpenScannerWithError(string error, bool hasPrimaryBtn = false, string primaryBtnText = null, bool hasSecondaryBtn = false, string secondaryBtnText = null, Action primaryBtnClick = null, Action secondaryBtnClick = null)
100       {
101           ContentDialog dialog = new ContentDialog();
102           var dialogTitle = new StackPanel();
103
104           dialogTitle.Children.Add(new TextBlock { Text = "出错啦 ( ▼-▼ )", Foreground = new SolidColorBrush(Colors.Red) });
105
106           var dialogContent = new StackPanel() { Margin = new Thickness(0, 12, 0, 0) };
107
108           dialogContent.Children.Add(new TextBlock { Text = error });
109
110           dialog.Title = dialogTitle;
111
112           dialog.Content = dialogContent;
113
114           if (hasPrimaryBtn)
115           {
116               dialog.PrimaryButtonText = "重试";
117               if (primaryBtnClick != null)
118               {
119                   dialog.Hide();
120                   dialog.PrimaryButtonClick += (s, a) =>
121                   {
122                       primaryBtnClick();
123                   };
124               }
125           }
126
127           if (hasSecondaryBtn)
128           {
129               dialog.SecondaryButtonText = "取消";
130
131               dialog.SecondaryButtonClick += (s, a) =>
132               {
133                   dialog.Hide();
134                   if (secondaryBtnClick != null)
135                   {
136                       secondaryBtnClick();
137                   }
138               };
139           }
140           await dialog.ShowAsync();
141       }

用到的一个UserControl –> Scaning, 是用来显示扫描中动画的,前台代码如下:

 1 <UserControl
 2     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
 3     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
 4     xmlns:local="using:ScannerDeviceSample.UserControls"
 5     xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
 6     xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
 7     xmlns:Interactivity="using:Microsoft.Xaml.Interactivity" xmlns:Core="using:Microsoft.Xaml.Interactions.Core" xmlns:Media="using:Microsoft.Xaml.Interactions.Media"
 8     x:Class="ScannerDeviceSample.UserControls.Scaning"
 9     mc:Ignorable="d"
10     d:DesignHeight="200"
11     d:DesignWidth="200">
12     <UserControl.Resources>
13         <Storyboard x:Name="ScaningStoryboard" AutoReverse="True" RepeatBehavior="Forever">
14             <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(CompositeTransform.TranslateY)" Storyboard.TargetName="recScanning">
15                 <EasingDoubleKeyFrame KeyTime="0" Value="0"/>
16                 <EasingDoubleKeyFrame KeyTime="0:0:2" Value="-200"/>
17             </DoubleAnimationUsingKeyFrames>
18         </Storyboard>
19     </UserControl.Resources>
20
21     <Interactivity:Interaction.Behaviors>
22         <Core:EventTriggerBehavior EventName="Loaded">
23             <Media:ControlStoryboardAction Storyboard="{StaticResource ScaningStoryboard}"/>
24         </Core:EventTriggerBehavior>
25     </Interactivity:Interaction.Behaviors>
26
27     <Grid>
28         <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">
29             <Path.RenderTransform>
30                 <TransformGroup>
31                     <RotateTransform Angle="0" />
32                     <ScaleTransform ScaleX="0.8" ScaleY="1" />
33                 </TransformGroup>
34             </Path.RenderTransform>
35         </Path>
36         <Rectangle x:Name="recScanning"   Height="2" RenderTransformOrigin="0.5,0.5" VerticalAlignment="Bottom" d:LayoutOverrides="Height">
37             <Rectangle.RenderTransform>
38                 <CompositeTransform/>
39             </Rectangle.RenderTransform>
40             <Rectangle.Projection>
41                 <PlaneProjection/>
42             </Rectangle.Projection>
43             <Rectangle.Fill>
44                 <LinearGradientBrush EndPoint="0,0.5" StartPoint="1,0.5">
45                     <GradientStop Color="#331CF106" Offset="0.15"/>
46                     <GradientStop Color="#331CF106" Offset="0.85"/>
47                     <GradientStop Color="#FF1CF106" Offset="0.5"/>
48                 </LinearGradientBrush>
49             </Rectangle.Fill>
50         </Rectangle>
51     </Grid>
52 </UserControl>

最后的效果:

推荐一个UWP开发群:53078485 大家可以进来一起学习~~

时间: 2024-10-13 00:50:13

Win10/UWP 让你的App使用上扫描仪的相关文章

Win10 UWP开发系列:使用VS2015 Update2+ionic开发第一个Cordova App

安装VS2015 Update2的过程是非常曲折的.还好经过不懈的努力,终于折腾成功了. 如果开发Cordova项目的话,推荐大家用一下ionic这个框架,效果还不错.对于Cordova.PhoneGap.ionic.AngularJS这些框架或库的关系,我个人理解是这样,PhoneGap是一个商业项目,用来实现HTML5式的跨平台开发,后来Adobe公司将其中的核心代码开源,就是Cordova,Cordova只负责实现JavaScript调用原生代码的功能,是一个壳,而壳里具体用什么样式,在H

Win10/UWP开发—使用Cortana语音与App后台Service交互

上篇文章中我们介绍了使用Cortana调用前台App,不熟悉的移步到:Win10/UWP开发—使用Cortana语音指令与App的前台交互,这篇我们讲讲如何使用Cortana调用App的后台任务,相比调用前台的App,调用后台任务有个有点就是App不用被启动即可为用户提供服务. 要想使用Cortana调用App后台任务,首先我们需要定义VCD文件,我们依旧使用上篇中的代码,让它支持Cortana调用后台任务. 创建后台任务 新增一个[Windows运行时组件]项目,暂时起名叫做:XiaoMiBa

Xbox One上的Win10 UWP版《地图》是什么样?

此前Xbox One已经推送了Win10一周年更新系统,也称Xbox One夏季更新.得益于UWP平台,Win10 Mobile和Windows10 PC上的<Windows地图>应用也登陆了Xbox One设备,提供方向指导.丰富地图数据,甚至是3D鸟瞰模式等. Windows地图还允许你同步收藏地点,与Cortana集成,使用二八杠命令等,目前Windows地图已经在Xbox One Win10一周年更新预览版上可用. Xbox One上的Windows地图功能与PC.手机版类似,不过不再

Win10 UWP开发系列:实现Master/Detail布局

在开发XX新闻的过程中,UI部分使用了Master/Detail(大纲/细节)布局样式.Win10系统中的邮件App就是这种样式,左侧一个列表,右侧是详情页面.关于这种 样式的说明可参看MSDN文档:https://msdn.microsoft.com/zh-cn/library/windows/apps/xaml/dn997765.aspx 样式如下: 在微软官方的Sample里,有这种样式的代码示例,下载地址:https://github.com/Microsoft/Windows-univ

Win10 UWP系列:关于错误 0x80073CF9及一个小bug的解决

原文:Win10 UWP系列:关于错误 0x80073CF9及一个小bug的解决 最近一直在开发XX的uwp版本,也是边摸索边做,最近遇到几个比较奇怪的问题,记录于此. 1.项目可用部署到PC,但无法部署到手机,提示以下错误: 错误 : DEP0001 : 意外错误: Install failed. Please contact your software vendor. (Exception from HRESULT: 0x80073CF9 为了方便开发,我将常用的类库引用好.默认的几个页面做

Win10 UWP应用发布流程

简介 Win10 UWP应用作为和Win8.1 UAP应用不同的一种新应用形式,其上传至Windows应用商店的流程也有了一些改变. 这篇博文记录了我们发布一款Win10 UWP应用的基本流程,希望为广大开发者提供参考. 创建新提交 1.登陆至应用商店 https://dev.windows.com/,选择[提交你的应用] 2.创建新应用 3.填写应用名称并检查可用性.成功应用商店将保留该名称 4.开始提交.在提交过程中,需要填写应用信息和上传程序包. 进行提交 5.在新建的提交任务中,可以看到

Win10 UWP开发实现Bing翻译

微软在WP上的发展从原来的Win7到Win8,Win8.1,到现在的Win10 UWP,什么是UWP,UWP即Windows 10 中的Universal Windows Platform简称.即Windows通用应用平台,在Win 10 Mobile/Surface(Windows平板电脑)/PC/Xbox/HoloLens等平台上运行,uwp不同于传统pc上的exe应用也跟只适用于手机端的app有本质区别.它并不是为某一个终端而设计,而是可以在所有windows10设备上运行. 简单的说,u

Win10/UWP新特性—SharedStorageAccessManager 共享文件

首先先给大家推荐一个UWP/Win10开发者群:53078485  里面有很多大婶,还有很多学习资源,欢迎大家来一起讨论Win10开发! 在UWP开发中,微软提供了一个新的特性叫做SharedStorageAccessManager,它允许我们的App根据指定的文件生成一个FileToken来共享此文件,其他App可以使用SharedStorageAccessManager. RedeemTokenForFileAsync(fileToken);方法根据FileToken来获取到共享的文件.这样

win10 uwp 重启软件

原文:win10 uwp 重启软件 在16299支持在软件自己重启,不需要让用户点击关闭然后启动,虽然我还不知道这个有什么用.本文告诉大家如何让软件关闭重新打开 首先需要使用的版本是 16299 ,然后使用 RequestRestartAsync 方法就可以关闭软件重新打开. 下面就是简单的软件 <StackPanel> <TextBlock Margin="100" HorizontalAlignment="Center" Text="