zoukankan      html  css  js  c++  java
  • 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();
                    }
                }
            }
    
                                      
    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 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的启动扫描事件,可以根据是否连续扫描给扫描仪传不同的参数以达到此效果。 

          只需一行代码,就可实现一次扫描多张,且不需要更改扫描仪的任何设置。

          如果设备支持连续送纸,启动扫描时扫描仪会直接连扫直到纸张全部扫完

      //此行代码是连续扫描
    TwCapability cap = new TwCapability(TwCap.XferCount, -1);

       代码如下:

            /// <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;
            }
    

      扫描结束后,回调主窗口返回数据,主窗口添加如下事件:

          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原创,署名小萝卜。转载请注明出处。谢谢!

  • 相关阅读:
    百度搜索技巧
    Redis汇总
    分享一个经验,代码打开mysql链接,执行存储过程时,提示:Table 'mysql.proc' doesn't exist
    WPF 重写微调自带的样式,ListView、DataGrid、TreeView等所有控件的默认样式
    WPF 图片抗锯齿,尤其是小图片更为严重
    通过鼠标事件,从鼠标点击的坐标寻找指定的控件
    重写TreeView,多层级节点下批量显示图片,图片支持缩略图和文件名列表切换,支持调用者动态匹配选中,支持外界拖入图片并添加到对应节点下
    重写TreeView,自定义图标,生成通行的下划线,取消默认获得焦点失去焦点的效果,并支持拖拽节点到外界
    四、C#入门—表达式与运算符
    三、C#入门—数据类型
  • 原文地址:https://www.cnblogs.com/healer007/p/6240730.html
Copyright © 2011-2022 走看看