C#使用Twain协议实现扫描仪连续扫描功能
作者:Healer007 发布时间:2023-02-15 18:14:38
C#调用Twain接口实现扫描仪连续扫描。在监听的TwainCommand.TransferReady状态中,是调用扫描仪扫描图片的。我开始的时候尝试修改twain类中TransferPictures的方法,但是结果证实不可行。其实这是一个误区,我们只需要修改一下twain的启动扫描事件,可以根据是否连续扫描给扫描仪传不同的参数以达到此效果。只需一行代码,就可实现一次扫描多张,且不需要更改扫描仪的任何设置。
如果用Twain协议实现一次扫描多张图片?相信有接触过Twain协议与扫描仪通信的朋友都遇到过这样的问题。按照网上的例子,在连续送纸的扫描仪中,调用一次却只能扫描一张图片,怎么破?
关于这个问题 我研究了好久,终于在困扰了我7天之后,我搞定了,下面分享一下我的解决经验。
新建一个ScanCommon类,在调用界面,写下调用扫描的方法:
ScanCommon scan = new RS_ScanCommon(fileName, this.Handle);
scan.PassDataBetweenForm += new RS_ScanCommon.PassDataBetweenFormHandler(scan_PassDataBetweenForm);
//是否连续扫描
scan.bContinuousScan = true;
scan.dtRow = dtRow;
this.Enabled = false;
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是添加扫描仪的事件监听,在监听事件中返回扫描仪的不同状态以实现取消和扫描的一些操作。
主要代码如下:
#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();
}
}
来源:https://www.cnblogs.com/healer007/p/6240730.html


猜你喜欢
- 1.在res上面右键->New->Android resource directory2.点击之后,出现下图Resource t
- 具体如下: XML文件:文件在MyDocument文件夹下 <?xml version="1.0" encodin
- 本文实例为大家分享了PhotoView实现图片多点触控效果展示的具体代码,供大家参考,具体内容如下效果:点击后能够自由缩放、平移;添加依赖:
- Springmvc+hibernate成为现在很多人用的框架整合,最近自己也在学习摸索,由于我们在开发项目中很多项目都用到列表分页功能,在此
- 本文实例为大家分享了Android百度地图之方向感应和模式更改,供大家参考,具体内容如下目标效果:菜单中设置几种模式,点击可查看不同的地图形
- 引言设计: 嗯? 这个图片点击跳转进详情再返回图片怎么变白闪一下呢?产品: 是啊是啊! 一定是个bug开发: 囧囧囧在开发过程中, 也许你也
- 一、快捷键添加代码块:++快速生成属性等:++导包:+++自动创建变量名:++查找源代码:++按条件查找替换:++快速查看当前类的所有方法:
- 哈希表(HashMap)hash查询的时间复杂度是O(1)按值传递Character,Short,Integer,Long, Float,D
- 本文实例为大家分享了Android弹出菜单效果的具体代码,供大家参考,具体内容如下功能描述:用户单击按钮弹出菜单。当用户选择一个菜单项,会触
- 实例如下:/** * 将一个list均分成n个list,主要通过偏移量来实现的 * @param source * @return */ p
- 前言aop面向切面编程,是编程中一个很重要的思想本篇文章主要介绍的是SpringBoot切面Aop的使用和案例什么是aopAOP(Aspec
- 什么是 Spring Boot 插件?Spring Boot 插件是一种扩展机制,它提供了一种简单的方式来扩展 Spring Boot 的功
- maven导入依赖<dependencies> <dependency> &
- 前言在上一篇文章中《Notification自定义界面》中我们实现了自定义的界面,那么我们该怎么为自定义的界面添加点击事件呢?像酷狗在通知栏
- ofType和javaType的区别JavaType和ofType都是用来指定对象类型的,但是JavaType是用来指定pojo中属性的类型
- 前言缓冲区 又称为缓存,它是内存空间的一部分。也就是说,在内存空间中预留了一定的存储空间,这些存储空间用来缓冲输入或输出的数据,这部分预留的
- 最近由于参加一个小小的创意比赛,用安卓做了一个小小的图片识别应用,主要是通过拍照识别图片中的菜品,还有对象位置查找的东西。之前没有做过安卓,
- 引言ShardingSphere的SQL解析,本篇文章源码基于4.0.1版本ShardingSphere的分片引擎从解析引擎到路由引擎到改写
- 本文实例为大家分享了javafx实现时钟效果的具体代码,供大家参考,具体内容如下核心为三个函数:第一个为 public void dials
- 对话框(Dialog)是Android系统在Activity或者其他组件运行过程中提供的一种提示机制。它可以帮助应用完成一些必要的提示功能,