C#:使用Twain协议实现扫描仪连续扫描
如果用Twain协议实现一次扫描多张图片?相信有接触过Twain协议与扫描仪通信的朋友都遇到过这样的问题。按照网上的例子,在连续送纸的扫描仪中,调用一次却只能扫描一张图片,怎么破?
关于这个问题 我研究了好久,终于在困扰了我7天之后,我搞定了,下面分享一下我的解决经验。
新建一个ScanCommon类,在调用界面,写下调用扫描的方法:
1 ScanCommon scan = new RS_ScanCommon(fileName, this.Handle); 2 scan.PassDataBetweenForm += new RS_ScanCommon.PassDataBetweenFormHandler(scan_PassDataBetweenForm); 3 4 //是否连续扫描 5 scan.bContinuousScan = true; 6 scan.dtRow = dtRow; 7 this.Enabled = false; 8 scan.StartScan();
在ScanCommon类中,调用Twain的接口类(Twain类网络上可以找到,本文略),主要代码如下:

// 添加一个委托 public delegate void PassDataBetweenFormHandler(object sender, PassDataEventArgs e); // 添加一个PassDataBetweenFormHandler 类型的事件 public event PassDataBetweenFormHandler PassDataBetweenForm; public ScanCommon(string fileName, IntPtr Handle) { this.fileName = fileName; this.Handle = Handle; //扫描初始化(默认使用TWAIN方式进行连接) tw = new Twain(); tw.Init(Handle, out rc); //tw.Select(); } //启动扫描 public void StartScan() { if (rc != TwRC.Success) { MessageBox.Show("设备初始化失败,请检查硬件及驱动!"); } else { string path = "XXX路径" + "\\ScannerFile\\" + frmName; if (Scanning(path) == false) { MessageBox.Show("设备未找到或设备不支持TWAIN组件,无法自动创建扫描任务。") ; //回调主窗口 PassDataEventArgs args = new PassDataEventArgs("exit"); PassDataBetweenForm(this, args); GC.Collect(); } } }
在ScanCommon类中,主要的扫描方法均可以通过调用twain类实现,Scanning是调用驱动实现扫描的方法。Application.AddMessageFilter是添加扫描仪的事件监听,在监听事件中返回扫描仪的不同状态以实现取消和扫描的一些操作。
主要代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 | #region 扫描的一些方法 private bool Scanning( string filePath) { if (!msgfilter) { msgfilter = true ; Application.AddMessageFilter( this ); } ScanPath = filePath; return tw.Acquire( ref strScanErrorMessage, bContinuousScan); } /// <summary> /// 保存图片 /// </summary> /// <param name="dibhandp"></param> private void ImageSave(IntPtr dibhandp) { bmprect = new Rectangle(0, 0, 0, 0); if (dibhandp != IntPtr.Zero) dibhand = dibhandp; bmpptr = GlobalLock(dibhand); pixptr = GetPixelInfo(bmpptr); } public void EndingScan() { if (msgfilter) { tw.Finish(); RemoveMessageFilter( this ); msgfilter = false ; } } public static void RemoveMessageFilter(IMessageFilter value) { Application.RemoveMessageFilter(value); } #endregion |
在监听的TwainCommand.TransferReady状态中,是调用扫描仪扫描图片的。我开始的时候尝试修改twain类中TransferPictures的方法,但是结果证实不可行。
其实这是一个误区,我们只需要修改一下twain的启动扫描事件,可以根据是否连续扫描给扫描仪传不同的参数以达到此效果。
只需一行代码,就可实现一次扫描多张,且不需要更改扫描仪的任何设置。
如果设备支持连续送纸,启动扫描时扫描仪会直接连扫直到纸张全部扫完
1 | //此行代码是连续扫描<br> TwCapability cap = new TwCapability(TwCap.XferCount, -1); |
代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 | /// <summary> /// 启动扫描 /// </summary> /// <param name="strScanErrorMessage"></param> /// <returns></returns> public bool Acquire( ref string strScanErrorMessage, bool MultiScan) { try { TwRC rc; CloseSrc(); if (appid.Id == IntPtr.Zero) { Init(hwnd, out rc); if (appid.Id == IntPtr.Zero) strScanErrorMessage = "未找到扫描仪设备,请查看是否安装扫描仪驱动!" ; return false ; } rc = DSMident(appid, IntPtr.Zero, TwDG.Control, TwDAT.Identity, TwMSG.OpenDS, srcds); if (rc != TwRC.Success) { strScanErrorMessage = "未找到扫描仪设备" ; return false ; } if (MultiScan) { //如果是连续扫描 TwCapability cap = new TwCapability(TwCap.XferCount, -1); rc = DScap(appid, srcds, TwDG.Control, TwDAT.Capability, TwMSG.Set, cap); } else { //否则只扫描一张 TwCapability cap = new TwCapability(TwCap.XferCount, 1); rc = DScap(appid, srcds, TwDG.Control, TwDAT.Capability, TwMSG.Set, cap); } if (rc != TwRC.Success) { strScanErrorMessage = "未找到扫描仪设备" ; CloseSrc(); return false ; } TwUserInterface guif = new TwUserInterface(); guif.ShowUI = 1; guif.ModalUI = 1; guif.ParentHand = hwnd; rc = DSuserif(appid, srcds, TwDG.Control, TwDAT.UserInterface, TwMSG.EnableDS, guif); if (rc != TwRC.Success) { strScanErrorMessage = "扫描仪中没有纸" ; CloseSrc(); GC.Collect(); return false ; } } catch (Exception e) { strScanErrorMessage = e.Message; GC.Collect(); return false ; } GC.Collect(); return true ; } |
扫描结束后,回调主窗口返回数据,主窗口添加如下事件:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | private void scan_PassDataBetweenForm( object sender, PassDataEventArgs e) { if (e.EventStr == "exit" ) { this .Cursor = Cursors.WaitCursor; frm.dtRow = this .dtRow; //处理图片的一些方法.... this .Enabled = true ; this .Cursor = Cursors.Default; GC.Collect(); } } |
特别声明:本文由Healer007原创,署名小萝卜。转载请注明出处。谢谢!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· 周边上新:园子的第一款马克杯温暖上架
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器
· DeepSeek如何颠覆传统软件测试?测试工程师会被淘汰吗?
· 使用C#创建一个MCP客户端