如果用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(); } } }
View Code在ScanCommon类中,主要的扫描方法均可以通过调用twain类实现,Scanning是调用驱动实现扫描的方法。Application.AddMessageFilter是添加扫描仪的事件监听,在监听事件中返回扫描仪的不同状态以实现取消和扫描的一些操作。
主要代码如下:
#region 扫描的一些方法 private bool Scanning(string filePath) { if (!msgfilter) { msgfilter = true; Application.AddMessageFilter(this); } ScanPath = filePath; return tw.Acquire(ref strScanErrorMessage, bContinuousScan); } /// <summary> /// 保存图片 /// </summary> /// <param></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的启动扫描事件,可以根据是否连续扫描给扫描仪传不同的参数以达到此效果。
只需一行代码,就可实现一次扫描多张,且不需要更改扫描仪的任何设置。
如果设备支持连续送纸,启动扫描时扫描仪会直接连扫直到纸张全部扫完
//此行代码是连续扫描
TwCapability cap = new TwCapability(TwCap.XferCount, -1);
代码如下:
/// <summary> /// 启动扫描 /// </summary> /// <param></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; }
扫描结束后,回调主窗口返回数据,主窗口添加如下事件: