TWAIN学习笔记

合集下载
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

2008-10-06
TWAIN学习笔记(壹)
∙TWAIN,定义了一套标准的软件协议(software protocol)和应用程序编程接口 (application programming interface(API))。

使用它实现软件应用程序和图象获取设备(扫描仪)之间的通讯。

我们见到的情况是:从FILE 菜单下选取ACQUIRE就弹出了扫描软件。

四层:
Application,Protocol,Acquisition,Device
∙用户层,用户的应用程序,界面之类的东西
∙协议层,把用户的请求转换成TWAIN明白的内容
∙请求层,向下请求内容,可以是硬件也可以是数据库
∙硬件层,数据的来源
TWAIN之间通讯通过两个入口,DSM_Entry,DS_Entry
Application:
所有的应用不能直连到数据层,只能通过SourceManager,通过DSM_Entry()方法。

DSM_Entry()方法有下面的参数:
∙标识符构造,identifier structure
∙目标(SourceManager或者Source)
∙三个描述
o数据组(Data Group : DG_)
o Data Argument Type(DAT_)
o Message(MSG_)
∙用于传数据的指针域
Win下,C代码类似于:
C代码
1.TW_UINT16 FAR PASCAL DSM_Entry(
2. pTW_IDENTITY pOrigin, // source of message
3. pTW_IDENTITY pDest, // destination of message
4. TW_UINT32 DG, // data group ID: DG_xxxx
5. TW_UINT16 DAT, // data argument type: DAT_xxxx
6. TW_UINT16 MSG, // message ID: MSG_xxxx
7. TW_MEMREF pData // pointer to data
8.);
Source Manager:
SM提供应用层和数据层之间的通讯,支持用户选取数据源,应用层读取数据源。

如果用DSM_Entry()的时候,调用的是SM,那直接就操作它本身。

如果调用的是S,那再调用DS_Entry()。

Win下面,C代码类似于:
C代码
1.TW_UINT16 FAR PASCAL DS_Entry(
2. pTW_IDENTITY pOrigin, // source of message
3. TW_UINT32 DG, // data group ID: DG_xxxx
4. TW_UINT16 DAT, // data argument type: DAT_xxxx
5. TW_UINT16 MSG, // message ID: MSG_xxxx
6. TW_MEMREF pData // pointer to data
7.)
Source:
返回值前缀TWRC_,如果出问题,设置一个前缀为TWCC_的状态码,但是不会自动返回。

SM和S在Win下都是DLL形式实现。

从Source返回给Application,需要4步:
∙通知应用层,已经准备好了有东西要返回了。

MSG_XFERREADY用于Source 通知App
∙禁用Source的用户接口,MSG_CLOSEDSREQ
∙通知应用层,按下了OK按钮,应用更改,用于Source被DG_CONTROL /DAT_USERINTERFACE / MSG_ENABLEDSUIONLY.打开的情况,MSG_CLOSEDSOK ∙设备发生动作,只有在应用层给数据层这个优先权,单独传回来。

MSG_DEVICEEVENT
DSM_Entry()和DS_Entry()用于通讯,一个操作和一个应用或者SM关联。

通常,但不绝对,用传进来的最后一个参数(pData)来描述。

从app到SM,设为NULL,从app到S(通过SM),设为目标id,从SM到S,设为DS_Entry。

传进来的三个参数DG,DAT,MSG表示的意思如下:
DG_XXXX:
∙DG_CONTROL 用于TWAIN操作动作,例如打开SM
∙DG_IMAGE 用于操作图形图像操作
∙DG_AUDIO 用于操作声频数据
DAT_XXX:
传进来的参数,可以引用一个结构体或者变量,例如DAT_IDENTITY,还有类似
于TW_XXX的声明。

MSG_XXX:
用于确定动作,都是类似于MSG_GET,MSG_SET的有前缀MSG_开始的。

三个例子:
打开SM模块:DG_CONTROL/DAT_PARENT/MSG_OPENDSM
打开对话框,让用户可以选择Source:
DG_CONTROL/DAT_IDENTITY/MSG_USERSELECT
导一个图像到文件上:DG_IMAGE/DAT_IMAGEFILEXFER/MSG_GET
协议层被分为7个阶段:
[1,2,3]在且只在SM阶段,[4,5,6,7]在且只在S阶段。

举例说:
1.Pre-Session ---->
2.SM Loaded ---->
3.SM
Opened ----> 4.Source Open ---->
SM not loaded App:Get Entry point User:Select Source Capability Negotiation
5.Source Enable ---->
6.Transfer
Ready ----> 7.Transferring
Source:Show User App:Inquire Image Source: Transfer Data
Interface or Audio Information
看英文资料精疲力竭……还阳中……
TWAIN学习笔记(贰)
TWAIN
能力分成三组:
∙CAP_XXX:适用于一般的数据源
∙ICAP_XXX:适用于图形图像源
∙ACAP_XXX:适用于声音数据源
能力容器分成四类:
∙TW_ONEVALUE:单值
∙TW_ARRAY:多值
∙TW_RANGE:范围值
∙TW_ENUMERATION:枚举值
<上面数据类型很烦,自己看说明去吧>
有三种方法将Source传递到应用程序。

native, disk file, buffered memory。

音频文件只支持native和disk file。

Native:所有的Source都必须支持的模式,但是有限制性(例如限制于DIB或者PICT格式,受可用内存的限制),Win下,DIB格式(Device-Independent Bitmap),Source给文件分配一个内存块,将指针返回给应用,应用负责转换数据之后释放这块内存。

Disk File:推荐Source支持这种模式,应用程序创建一个Source支持格式的文件,易于读写,尤其是可以避免遇到内存问题。

稍微比之后讨论的Buffered 模式慢,但比他好操作,并且之后应用程序要操作清理这个文件。

Buffered Memory:所有的Source必须支持该模式。

MD,被关闭了,没保存。

通过一个或多个缓存来实现传输,应用层来分配内存的使用和释放。

数据以一无格式位图(unformatted bitmap)传输,应用需要在传输过程中
(TW_IMAGEINFO&TW_IMAGEMEMXFER)用信息标识各个缓存和正确识别位图。

于Native和Disk File的一个动作结束传输相比,这种模式可能要多次循环。

应用层实现:
TWAIN的实现层次:
∙最小实现:使用TWAIN默认的,只在Native本机模式,请求单独一个图片。

∙基本实现:
∙最大实现:
安装SM(Source Manager)软件:
TWAIN Working Group(TWG)给Win提供四个包:
∙TWAIN_32.DLL:32位程序用
∙TWAIN.DLL:16位程序用
∙TWUNKER_32.EXE:让16位应用程序链接32位的数据源
∙TWUNKER_16.EXE:让32位应用程序链接16位源,注意,16位源不能再NT上面正确运行
SM四个文件Win文件夹下,比如C:\Winnt,C:\Windows.
微软提供了一个VER.DLL包,用于安装SM。

VER.DLL,VER.LIB,VER.H包括在安装包Toolkit里面。

VER.DLL是可以自由使用和发布的。

TWAIN要开始,要做三个准备:
∙添加应用的用户接口用来选择数据源和请求菜单选择:必须有选择源(Select Source...和Acquire...)
∙将TWAIN.H引用到程序中:包括所有必须的定义
∙更改应用的事件循环:可以开很多个源,但是每次只能持有一个。

o传递事件给Source
o通知应用,源准备好了或者关闭接口
o硬件事件发生的时候通知应用。

三个目标的实现如下:
——————靠——————
下面全都是具体实现,不想弄了。

——————靠——————
算了,复制粘贴一下。

谁帮个忙。

第一个目标,传递事件(从应用到源):
只要源激活了,为了确保源能接受和执行事件,应用必须将所有事件,在源激活期间,统统传过去。

如:DG_CONTROL/DAT_EVENT/MSG_PROCESSEVENT
TW_EVENT结构如下:
C代码
1.typedef struct {
2. TW_MEMREF pEvent; /* Windows pMSG or MAC pEvent */
3. TW_UINT16 TWMessage; /* TW message from Source to */
4. /* the application
*/
5.} TW_EVENT, FAR *pTW_EVENT;
pEvent在Win下,指向message structure。

源从SM接收到信息,决定是否属于它,
∙如果是:源执行事件,然后设置返回码为TWRC_DSEVENT,以示它是Source 事件,并且设置TW_Event结构的TWMessage到MSG_NULL,∙如果不是:设置返回码为TWRC_NOTDSEVENT,设置TWMessage到MSG_NULL,应用从DSM_Entry接收到信息,然后在循环里面装作没事情一样执行。

第二和第三个目标,(从源到事件)
当源准备好了,通知应用,通过TW_EVENT.TWMessage,有下面四个选项:
∙MSG_XFERREADY:标示数据已经准备好了
∙MSG_CLOSEDSREQ:关闭Source的用户接口
∙MSG_CLOSEDSOK:同上,不过只用在DG_CONTROL / DAT_USERINTERFACE / MSG_ENABLEDSUIONLY
∙MSG_DEVICEEVENT:报告设备事件发生
Win下,修改循环的例子代码:
C代码
1.TW_EVENT twEvent;
2.TW_INT16 rc;
3.while (GetMessage ( (LPMSG) &msg, NULL, 0, 0) ) {
4. rc = TWRC_NOTDSEVENT;
5. if Source is enabled {
6. twEvent.pEvent = (TW_MEMREF)&msg;
7. twEvent.TWMessage = MSG_NULL;
8. rc = (*pDSM_Entry) (pAppId,
9. pSourceId,
10. DG_CONTROL,
11. DAT_EVENT,
12. MSG_PROCESSEVENT,
13. (TW_MEMREF)&twEvent);
14. // check for message from Source
15. switch (twEvent.TWMessage) {
16. case MSG_XFERREADY:
17. SetupAndTransferImage(NULL);
18. break;
19. case MSG_CLOSEDSREQ:
20. DisableAndCloseSource(NULL);
21. break;
22. case MSG_CLOSEDSOK:
23. DisableAndCloseSource(NULL);
24. GetCustomDsData();
25. break;
26. case MSG_NULL:
27. // no message returned from the
source
28. break;
29. }
30. }
31. // Source didn’t process it, so we will
32. if (rc == TWRC_NOTDSEVENT) {
33. TranslateMessage( (LPMSG) &msg);
34. DispatchMessage( (LPMSG) &msg);
35. }
36.}
DSM_Entry()方法:
Win下代码如下:
C代码
1.TW_UINT16 FAR PASCAL DSM_Entry(
2. pTW_IDENTITY pOrigin, // source of message
3. pTW_IDENTITY pDest, // destination of message
4. TW_UINT32 DG, // data group ID: DG_xxxx
5. TW_UINT16 DAT, // data argument type: DAT_xxxx
6. TW_UINT16 MSG, // message ID: MSG_xxxx
7. TW_MEMREF pData // pointer to data
8.);
∙pOrigin:TW_IDENTITY,从应用和源链接上之后不能改变。

∙pDest:如果操作最后目标是SM,设置为NULL,否则指向源
∙DG_XXX:DG_CONTROL,DG_IMAGE,DG_AUDIO目前是被定义掉了的,可以自定义数据组。

∙DAT_XXX:描述pData对象的唯一标示(结构或者变量)
∙MSG_XXX:动作的描述
∙pData:操作用到的TW_XXX结构或者变量,类型有DAT_XXX描述。

There are nine operation triplets that can be sent from the application
to be consumed by the
Source Manager.
有九个手术双胞胎,可发出的申请将消费源管理器。

从应用到SM,(我们公司的人事很有味道),DG统统属于DG_CONTROL,DAT
有三个:DAT_IDENTITY,DAT_PARENT,DAT_STATUS。

下面的列表是DAT下面的MSG
组合:
DG_CONTROL/DAT_IDENTITY
MSG_CLOSEDS: 准备关闭源
MSG_GETDEFAULT : 获取默认源的标识信息
MSG_GETFIRST : 获取第一个活动源的标识信息
MSG_GETNEXT : 获取下一个活动源的标识信息
MSG_OPENDS : 装载且初始化源
MSG_USERSELECT : 弹出“选择源”的对话框
DG_CONTROL / DAT_PARENT
MSG_CLOSEDSM : 准备关闭SM
MSG_OPENDSM : 初始化SM
DG_CONTROL / DAT_STATUS
MSG_GET : 返回SM当前状态码
从应用到源:
参数通过DSM_Entry调用,第一个集是DG_CONTROL,定义了DG能在所有的TWAIN
设备上运用的。

第二个集,定义为DG_IMAGE。

DG_CONTROL / DAT_CAPABILITY (能力值,扫描仪这类东西能干啥)MSG_GET 获取能力值,包括当前的和默认的
MSG_GETCURRENT 获取能力值当前值
MSG_GETDEFAULT 获取源的默认首选能力值
MSG_RESET : 将当前源能力值转成TWAIN定义的默认值
MSG_SET : 设定能力值DG_CONTROL / DAT_DEVICEEVENT
MSG_GET : DG_CONTROL / DAT_NULL / MSG_DEVICEEVENT
DG_CONTROL / DAT_EVENT
MSG_PROCESSEVENT : 从应用传递事件到源
DG_CONTROL / DAT_FILESYSTEM
MSG_AUTOMATICCAPTUREDIRECTORY : 选择目录自动接收图像
MSG_CHANGEDIRECTORY : 更改当前domain,host,dir,设备MSG_COPY : 拷贝文件
MSG_CREATEDIRECTORY : 建立一个目录文件夹
MSG_DELETE : 删除一个目录文件夹
MSG_FORMATMEDIA : 格式化存储设备(?那么牛)
MSG_GETCLOSE 关闭MSG_GETFILEFIRST打开的上下文MSG_GETFIRSTFILE 获取目录里第一个文件
MSG_GETINFO 获取当前文件上下文的信息
MSG_RENAME 重命名一文件
DG_CONTROL/DAT_PASSTHRU/MSG_PASSTHRU
MSG_PASSTHRU 用特殊命令。

(无聊厂家提供的特殊功能)DG_CONTROL / DAT_PENDINGXFERS
MSG_ENDXFER 应用接收或者请求结束数据传输
MSG_GET 返回源准备提供的传输
MSG_RESET 重置
MSG_STOPFEEDER 强行停止ADF
DG_CONTROL / DAT_SETUPFILEXFER
MSG_GET 返回文件的信息,文件将被源写入请求的数据
MSG_GETDEFAULT 返回默认的文件传输信息
MSG_RESET 重置当前文件信息
MSG_SET 为下一个文件传输设置信息
DG_CONTROL / DAT_SETUPFILEXFER2
MSG_GET 跟上面一样
MSG_GETDEFAULT 跟上面一样
MSG_RESET 跟上面一样
MSG_SET 跟上面一样
DG_CONTROL / DAT_SETUPMEMXFER
MSG_GET 返回源的最优,最小和最大的缓冲值
上回说到从应用到源的三胞胎的第一组设置,现在说第二组DG_IMAGE DG_CONTROL / DAT_STATUS
MSG_GET
从源返回当前状态码 DG_CONTROL / DAT_USERINTERFACE
MSG_DISABLEDS
关闭源的用户接口 MSG_ENABLEDS
激活源的用户接口 DG_CONTROL / DAT_XFERGROUP
MSG_GET 给下面传输返回DG ,目前支持DG_IMAGE 或
自定DG
DG_IMAGE / DAT_CIECOLOR
MSG_GET
给当前的传输返回CIE XYZ 信息 DG_IMAGE / DAT_GRAYRESPONSE
MSG_RESET
灰度默认值 MSG_SET
设置灰度值 DG_IMAGE / DAT_IMAGEFILEXFER
MSG_GET
用Disk File 模式初始化图形图像请求 DG_IMAGE / DAT_IMAGEINFO
MSG_GET
返回准备传输的图形图像的信息 DG_IMAGE / DAT_IMAGELAYOUT
MSG_GET
给“原始”图像描述物理布局/位置 MSG_GETDEFAULT
获取图的默认布局信息 MSG_RESET
将下个图传输布局信息设成默认值 MSG_SET
设置下个图传输的布局信息 DG_IMAGE / DAT_IMAGEMEMXFER
MSG_GET
以缓存模式初始化图请求 DG_IMAGE / DAT_IMAGENATIVEXFER MSG_GET
以本地模式初始化图请求 DG_IMAGE / DAT_JPEGCOMPRESSION
MSG_GET
获取当前传输的JPEG 压缩参数 MSG_GETDEFAULT
获取默认的JPEG 压缩参数 MSG_RESET
使用源的默认JPEG 压缩值 MSG_SET
使用指定的JPEG 压缩值 DG_IMAGE / DAT_PALETTE8
MSG_GET
获取当前传输信息 MSG_GETDEFAULT
获取源默认的调色板信息 MSG_RESET
使用源默认的调色板 MSG_SET 使用指定的调色板
以上说的是三胞胎(triplet ,这个变态的翻译好记点,别学我),
DG_XXX,DAT_XXX,MSG_XXX 由上面的决定,剩下的几个补充如下:

pOrigin :源,应用程序的TW_IDENTITY 结构的副本
∙ pDest :如果操作对象是SM ,值一定是NULL ,如果是源,该参数引用源的TW_IDENTITY 结构的一副本,返回给应用
∙ pData :由之前的DAT_XXX 来定义是什么类型。

通常,对应的用TW_XXX 来命名数据结构。

如:DAT_IDENTITY 对应的就是TW_XXX 。

TWAIN.H 里面定义了全部的结构。

应用负责所有的分配和释放以及检查。

{最短的一章,下面那个一个整体,实在对不起啊兄弟,委屈你太监了。

} DIB (自百度百科)
C 代码
1. DIB ,全称Device Independent Bitmap ,设备无关位图文件,这是一种文件格式,其目的是为了保证用某个应用程序创建的位图图形可以被其它应用程序装载或显示一样。

2.
3. DIB(Device-indepentent bitmap)的与设备无关性主要体现在以下两个方面:
4. DIB 的颜色模式与设备无关。

例如,一个256色的DIB 即可以在真彩色显示模式下使用,也可以在16色模式下使用。

5. 256色以下(包括256色)的DIB 拥有自己的颜色表,像素的颜色独立于系统调色板。

DG_IMAGE / DAT_RGBRESPONSE
MSG_RESET
使用默认的RGB 值 MSG_SET
设定RGB 值 DG_AUDIO / DAT_AUDIOFILEXFER
MSG_GET :
文件(File )模式传音频数据 DG_AUDIO / DAT_AUDIOINFO
MSG_GET :
获取当前传输的信息(av 的上半集) DG_AUDIO / DAT_AUDIONATIVEXFER
MSG_GET
本地模式(Native )传输音频(audio )数据
6.由于DIB不依赖于具体设备,因此可以用来永久性地保存图象。

DIB
一般是以*.BMP文件的形式保存在磁盘中的,有时也会保存在*.DIB文件中。

运行在不同输出设备下的应用程序可以通过DIB来交换图象。

7. DIB还可以用一种RLE算法来压缩图像数据,但一般来说DIB是不压
缩的。

8.DIB的结构
9.与Borland C++下的框架类库OWL不同,MFC未提供现成的类来封装
DIB。

尽管Microsoft列出了一些理由,但没有DIB类确实给MFC用户带来很多不便。

用户要想使用DIB,首先应该了解DIB的结构。

10. 在内存中,一个完整的DIB由两部分组成:一个BITMAPINFO结构和
一个存储像素阵列的数组。

BITMAPINFO描述了位图的大小,颜色模式和调色板等各种属性,其定义为
11. typedef struct tagBITMAPINFO {
12. BITMAPINFOHEADER bmiHeader;
13. RGBQUAD bmiColors[1]; //颜色表
14. } BITMAPINFO;
15. RGBQUAD结构用来描述颜色,其定义为
16. typedef struct tagRGBQUAD {
17. BYTE rgbBlue; //蓝色的强度
18. BYTE rgbGreen; //绿色的强度
19. BYTE rgbRed; //红色的强度
20. BYTE rgbReserved; //保留字节,为0
21. } RGBQUAD;
22. 注意,RGBQUAD结构中的颜色顺序是BGR,而不是平常的RGB。

23. BITMAPINFOHEADER结构包含了DIB的各种信息,其定义为
24. typedef struct tagBITMAPINFOHEADER{
25. DWORD biSize; //该结构的大小
26. LONG biWidth; //位图的宽度(以像素为单位)
27. LONG biHeight; //位图的高度(以像素为单位)
28. WORD biPlanes; //必须为1
29. WORD biBitCount //每个像素的位数(1、4、8、16、24
或32)
30. DWORD biCompression; //压缩方式,一般为0或
BI_RGB (未压缩)
31. DWORD biSizeImage; //以字节为单位的图象大小(仅
用于压缩位图)
32. LONG biXPelsPerMeter; //以目标设备每米的像素数
来说明位图的水平分辨率
33. LONG biYPelsPerMeter; //以目标设备每米的像素数
来说明位图的垂直分辨率
34. DWORD biClrUsed; /*颜色表的颜色数,若为0则位图
使用由biBitCount指定的最大颜色数*/
35. DWORD biClrImportant; //重要颜色的数目,若该值为
0则所有颜色都重要
36. } BITMAPINFOHEADER;
37. 与DDB不同,DIB的字节数组是从图象的最下面一行开始的逐行向上
存储的,也即等于把图象倒过来然后在逐行扫描。

另外,字节数组中每个扫描行的字节数必需是4的倍数,如果不足要用0补齐
38. DIB可以存储在*.BMP或*.DIB文件中。

DIB文件是以
BITMAPFILEHEADER结构开头的,该结构的定义为
39. typedef struct tagBITMAPFILEHEADER {
40. WORD bfType; //文件类型,必须为"BM"
41. DWORD bfSize; //文件的大小
42. WORD bfReserved1; //为0
43. WORD bfReserved2; //为0
44. DWORD bfOffBits; //存储的像素阵列相对于文件头的
偏移量
45. } BITMAPFILEHEADER;
46. 紧随该结构的是一个BITMAPINFOHEADER结构,然后是RGBQUAD结构
组成的颜色表(如果有的话),文件最后存储的是DIB的像素阵列。

47.DIB的颜色信息储存在自己的颜色表中,程序一般要根据颜色表为DIB创
建逻辑调色板。

在输出一幅DIB之前,程序应该将其逻辑调色板选入到相关的设备上下文中并实现到系统调色板中,然后再调用相关的GDI函数(如::SetDIBitsToDevice或::StretchDIBits)输出DIB。

在输出过程中,GDI函数会把DIB转换成DDB,这项工作主要包括以下两步:
48. 将DIB的颜色格式转换成与输出设备相同的颜色格式。

例如,在真彩
色的显示模式下要显示一个256色的DIB,则应该将其转换成24位的颜色格式。

49. 将DIB像素的逻辑颜色索引转换成系统调色板索引。

50.编写DIB类
51. 由于MFC未提供DIB类,用户在使用DIB时将面临繁重的Windows API
编程任务。

幸运的是,Visual C++提供了一个较高层次的API,简化了DIB 的使用。

这些API函数实际上是由MFC的DibLook例程提供的,它们位于DibLook目录下的dibapi.cpp、myfile.cpp和dibapi.h文件中,主要包括:
52. ReadDIBFile //把DIB文件读入内存
53. SaveDIB //把DIB保存到文件中
54. CreateDIBPalette //从DIB中创建一个逻辑调色板
55. PaintDIB //显示DIB
56. DIBWidth //返回DIB的宽度
57. DIBHeight //返回DIB的高度
58.DIB区块
59.DIB区块
60.DIB能拥有几种色彩组织中的一种,DDB必须是单色的或是与真实输出设
备相同的格式。

DIB是一个档案或记忆体块;DDB是GDI点阵图物件并由点阵图代号表示。

DIB能被显示或转换为DDB并转换回DIB,但是这里包含了装置无关位元和设备相关位元之间的转换程序。

61.现在您将遇到一个函式,它打破了这些规则。

该函式在32位元Windows
版本中发表,称为CreateDIBSection,语法为:
62.hBitmap = CreateDIBSection (
63. hdc, // device context hand
le
64. pInfo, // pointer to DIB info
rmation
65. fClrUse, // color use flag
66. ppBits, // pointer to point
er variable
67. hSection, // file-mapping obje
ct handle
68. dwOffset) ; // offset to bits in
file-mapping object
69.CreateDIBSection是Windows API中最重要的函式之一(至少在使用点
阵图时),然而您会发现它很深奥并难以理解。

70.让我们从它的名称开始,我们知道DIB是什么,但「DIB section」到底
是什么呢?当您第一次检查CreateDIBSection时,可能会寻找该函式与DIB区块工作的方式。

这是正确的,CreateDIBSection所做的就是建立了DIB的一部分(点阵图图素位元的记忆体块)。

71.现在我们看一下传回值,它是GDI点阵图物件的代号,这个传回值可能是
该函式呼叫最会拐人的部分。

传回值似乎暗示著CreateDIBSection在功能上与CreateDIBitmap相同。

事实上,它只是相似但完全不同。

实际上,从CreateDIBSection传回的点阵图代号与我们在本章和上一章遇到的所有点阵图建立函式传回的点阵图代号在本质上不同。

72.一旦理解了CreateDIBSection的真实特性,您可能觉得奇怪为什么不把
传回值定义得有所区别。

您也可能得出结论:CreateDIBSection应该称之为CreateDIBitmap,并且如同我前面所指出的CreateDIBitmap应该称之为CreateDDBitmap。

73.首先让我们检查一下如何简化CreateDIBSection,并正确地使用它。


先,把最後两个参数hSection和dwOffset,分别设定为NULL和0,我将在本章最後讨论这些参数的用法。

第二,仅在fColorUse参数设定为
DIB_ PAL_COLORS时,才使用hdc参数,如果fColorUse为DIB_RGB_COLORS (或0),hdc将被忽略(这与CreateDIBitmap不同,hdc参数用於取得与DDB相容的设备的色彩格式)。

74.因此,CreateDIBSection最简单的形式仅需要第二和第四个参数。

第二
个参数是指向BITMAPINFO结构的指标,我们以前曾使用过。

我希望指向第四个参数的指标定义的指标不会使您困惑,它实际上很简单。

75.假设要建立每图素24位元的384×256位元DIB,24位元格式不需要色彩
对照表,因此它是最简单的,所以我们可以为BITMAPINFO参数使用
BITMAPINFOHEADER结构。

76.您需要定义三个变数:BITMAPINFOHEADER结构、BYTE指标和点阵图代
号:
77.BITMAPINFOHEADER bmih ;
78.BYTE * pBits ;
79.HBITMAP hBitmap ;
80.现在初始化BITMAPINFOHEADER结构的栏位
81.bmih->biSize = sizeof (BITMAPINFOHEADER) ;
82.bmih->biWidth = 384 ;
83.bmih->biHeight = 256 ;
84.bmih->biPlanes = 1 ;
85.bmih->biBitCount = 24 ;
86.bmih->biCompression = BI_RGB ;
87.bmih->biSizeImage = 0 ;
88.bmih->biXPelsPerMeter = 0 ;
89.bmih->biYPelsPerMeter = 0 ;
90.bmih->biClrUsed = 0 ;
91.bmih->biClrImportant = 0 ;
92.在基本准备後,我们呼叫该函式:
93.hBitmap = CreateDIBSection (NULL, (BITMAPINFO *) &bmih, 0, &pBi
ts, NULL, 0) ;
94.注意,我们为第二个参数赋予BITMAPINFOHEADER结构的位址。

这是常见
的,但一个BYIE指标pBits的位址,就不常见了。

这样,第四个参数是函式需要的指向指标的指标。

95.这是函式呼叫所做的:CreateDIBSection检查BITMAPINFOHEADER结构并
配置足够的记忆体块来载入DIB图素位元。

(在这个例子里,记忆体块的大小为384×256×3位元组。

)它在您提供的pBits参数中储存了指向此记忆体块的指标。

函式传回点阵图代号,正如我说的,它与
CreateDIBitmap和其他点阵图建立函式传回的代号不一样。

96.然而,我们还没有做完,点阵图图素是未初始化的。

如果正在读取DIB
档案,可以简单地把pBits参数传递给ReadFile函式并读取它们。

或者可以使用一些程式码「人工」设定。

DIB(自百度百科)END
应用控制TWAIN流程:
之前看到过那个图吧,7步那个,没看到算你倒霉。

首先要正确的打开流程,不一定要从第一步走到第七步,可能走到三之后,四到七不停重复,又或者六七重复。

挺灵活的。

下面那章包括那么多项的简单样例。

• Load the Source Manager and Get the DSM_Entry (State 1 to 2)
∙• Open the Source Manager (State 2 to 3)
∙• Select the Source (during State 3)
∙• Open the Source (State 3 to 4)
∙• Negotiate Capabilities with the Source (during State 4)
∙• Request the Acquisition of Data from the Source (State 4 to 5) ∙• Recognize that the Data Transfer is Ready (State 5 to 6)
∙• Start and Perform the Tr ansfer (State 6 to 7)
∙• Conclude the Transfer (State 7 to 6 to 5)
∙• Disconnect the TWAIN Session (State 5 to 1 in sequence)
1到2:
用LoadLibrary()装载TWAIN_32.DLL
用GetProcAddress()调用DSM_Entry
C代码
1.DSMENTRYPROC pDSM_Entry;
2.HANDLE hDSMLib;
3.char szSMDir;
4.OFSTRUCT of;
5.// check for the existence of the TWAIN_32.DLL file in the
6.// Windows directory
7.// 检查Win目录下面有没有TWAIN_32.DLL
8.GetWindowsDirectory (szSMDir, sizeof(szSMDir));
9./*** Could have been networked drive with trailing ‘\’ ***/
10./***网络路径***/
11.if (szSMDir [(lstrlen (szSMDir) - 1)] != ‘\\’){
12. lstrcat( szSMDir, "\\" );
13.}
14.if ((OpenFile(szSMDir, &of, OF_EXIST) != -1){
15. // load the DLL
16. if (hDSMDLL = LoadLibrary(“TWAIN_32.DLL”)) != NULL){
17. // check if library was loaded
18. if (hDSMDLL >= (HANDLE)VALID_HANDLE){
19. if (lpDSM_Entry = (DSMENTRYPROC)GetProcAddress(hDSM
DLL,MAKEINTRESOURCE (1))) != NULL){
20. if (lpDSM_Entry ){
21. FreeLibrary(hDSMDLL);
22. }
23. }
24. }
25. }
26.}
强烈建议使用动态装载TWAIN_32.DLL,写死的话,如果Win没有装TWAIN_32的话,到时候都不知道是啥了。

得到DSM_Entry之后,检查pDSM_Entry(),如果是NULL的话,说明SM没在用户机器上面安装。

要是还去用*pDSM_Entry()的话,会出一个UAE(Unrecoverable Application Error).
2到3
SM装载完之后,应用现在要打开SM了,注意,要开始SM了。

操作码:DG_CONTROL / DAT_PARENT / MSG_OPENDSM。

pOrigin:应用必须分配一个TW_IDENTITY结构,并且给除Id外的坑种萝卜,当结构准备好之后,pOrigin指向该结构。

在MSG_OPENDSM操作中,SM用唯一Id赋值给TW_IDENTITY。

这个是应用到SM 的唯一标识。

之后应用保存,之后,应用调用DSM_Entry()的时候,每次都用pOrigin指向的这个。

这个TW_IDENTITY在TWAIN.H里面定义好了。

贴一贴:
C代码
1./* DAT_IDENTITY Identifies the program/library/code */
2./* resource. */
3.typedef struct {
4. TW_UINT32 Id; /* Unique number for identification*/
5. TW_VERSION Version;
6. TW_UINT16 ProtocolMajor;
7. TW_UINT16 ProtocolMinor;
8. TW_UINT32 SupportedGroups;/*Bit field OR combination */
9. /*of DG_con
stants found in */
10. /*the TWAIN
.H file */
11. TW_STR32 Manufacturer;
12. TW_STR32 ProductFamily;
13. TW_STR32 ProductName;
14.} TW_IDENTITY, FAR *pTW_IDENTITY;
∙pDest:色即是空(Set to NULL indicating the operation is intended for the Source Manager.)
∙pData:指向hWnd(the window handle),作为源的"parent"。

变量类型是TW_INT32的,在16位系统下,the handle is stored in the low word of the 32 bit integer and the upper word is set to zero. If running under the WIN32 environment, this is a 32 bit window handle。

SM
为应用保存拷贝一份。

初始化TW_IDENTITY:
C代码
1.TW_IDENTITY AppID; // App’s identity structure
2. AppID.Id = 0; // Initialize to 0 (Source Manager
3. // will assign real value)
4. AppID.Version.MajorNum = 3; //Your app's version number
5. AppID.Version.MinorNum = 5;
6. nguage = TWLG_ENGLISH_USA;
7. AppID.Version.Country = TWCY_USA;
8. lstrcpy (, "Your App's Version String");
9. AppID.ProtocolMajor = TWON_PROTOCOLMAJOR;
10. AppID.ProtocolMinor = TWON_PROTOCOLMINOR;
11. AppID.SupportedGroups = DG_IMAGE | DG_CONTROL;
12. lstrcpy (AppID.Manufacturer, "App's Manufacturer");
13. lstrcpy (AppID.ProductFamily, "App's Product Family");
14. lstrcpy (AppID.ProductName, "Specific App Product Name"); Win下,用DSM_Entry()打开SM:
C代码
1.TW_UINT16 rc;
2.rc = (*pDSM_Entry) (&AppID,
3. NULL,
4. DG_CONTROL,
5. DAT_PARENT,
6. MSG_OPENDSM,
7. (TW_MEMREF) &hWnd);
当AppID是应用设置的TW_IDENTITY结构的id,hWnd是应用的主窗口句柄(main window handle)。

第3步:选择源
开始SM了,SM帮助你找到你的起源。

操作码:DG_CONTROL / DAT_IDENTITY / MSG_USERSELECT
∙pOrigin:在应用初始化TW_IDENTITY结构的初始化SupportedGroups的时候就指定了
∙pDest:四大皆空(Set to NULL.)
∙pData:先过DSM_Entry,然后必须分配这个结构,当它被分配之后,应用必须做下面的
o id设0
o产品名(ProductName)设null String("\0"),要是想臭美一下,将源的名替代掉null,系统默认的可以用DG_CONTROL /
DAT_IDENTITY / MSG_GETDEFAULT,MSG_GETFIRST and MSG_GETNEXT
获取
最土的办法通过SM选S是弹出S选择框。

然后点选源,走下面几步:∙应用发送DG_CONTROL / DAT_IDENTITY / MSG_USERSELECT,弹出对话框,列出所有的已经安装在系统上的能给你数据的源。

∙用户选择一个源或者按下退出(Cancel)。

如果没有设备,你就只能选退出,因为OK是灰的啊,你按不到~
∙应用检查DSM_Entry返回码,英明的判断用户的动作:
o TWRC_SUCCESS:被pData指向的,在TW_IDENTITY里面的源,终于上位
o TWRC_CANCEL:没选,别开源。

o TWRC_FAILURE:用DG_CONTROL/DAT_STATUS/MSG_GET获取失败原因,经常是因为内存问题,白菜,去加根啦。

当然你也可以不让人选。

第3到第4步:开源啦~不收费的哦
SM帮你开源
操作码: DG_CONTROL / DAT_IDENTITY / MSG_OPENDS
∙pOrigin:应用的TW_IDENTITY
∙pDest:NULL
∙pData:指向TW_IDENTITY
在MSG_OPENDS操作过程中,SM确定S,并且在TW_IDENTITY.Id设定。

也有可能不选择源就直接点Acquire了,这个时候,默认的源就是最后安装的那个或者最后一次使用的那个。

第4步:确认源的能力
如果是单张图的话,当前只用确定一个能力CAP_XFERCOUNT,其他都是可选。

操作码:
DG_CONTROL/DAT_CAPABILITY/MSG_GET
DG_CONTROL/DAT_CAPABILITY/MSG_SET
∙pOrigin:TW_IDENTITY
∙pDest:指向源,SM接收到DSM_Entry,判断是传给源还是自己消化,如果是源就通过DS_Entry往下调
∙pData:TW_CAPABILITY
TW_CAPABILITY的结构如下:
C代码
1.typedef struct {
2. TW_UINT16 Cap; /* ID of capability to get or set */
3. TW_UINT16 ConType; /* TWON_ONEVALUE, TWON_RANGE, */
4. /* TWON_ENUMERATION or
TWON_ARRAY */
5. TW_HANDLE hContainer; /* Handle to container of type */
6. /* ConType */
7.} TW_CAPABILITY, FAR *pTW_CAPABILITY;
应用程序分配container,在MSG_SET操作的时候,用hContainer指向,源在MSG_GET的时候返回这个指向。

不管怎么样,最后,应用一定要释放掉这东西。

一个操作一个目的
MSG_GET:谁都不是完打印机,都有自己不会的,用这个来确定你会TWAIN定义里面的几种,在TWAIN.H里面有所有的定义。

如果能取到,返回当前的,默认的,
可用的(Current, Default, Available)值,这些都能在MSG_SET里面修改原来默认支持的功能。

要是出错了,返回码是TWRC_FAILURE,状态码会是下面几个:
∙TWCC_CAPUNSUPPORTED:没能力啊
∙TWCC_CAPBADOPERATION:有心无力啊(Operation not supported by capability)
∙TWCC_CAPSEQERROR:该功能依赖另一个功能
应用程序应该兼容TWCC_BADCAP,早期1.7版本可能会返回。

MSG_SET
由应用来更改当前或者可用值。

要做异常判断啊。

TWCC_BADVALUE可能是:
∙应用设定能力值超过了源能力
∙源不允许设定该能力
∙源不允许使用应用设定的能力类型
查询和设置只在第4步做这个操作。

记得一定要做异常判断哦。

明确设置应用能传几张图:
代码是CAP_XFERCOUNT,所有的源都必须支持这个能力。

必须明确告诉应用在TWAIN中能拿到几张。

值范围如下:
∙1:1张
∙>1:指定的多张
∙-1:任意张,是默认值
∙0:无意义值,在应用中也不要设这个值,源接到这个之后就返回TWRC_FAILURE和TWCC_BADVALUE
下面是一个例子,说明怎么设定限制:
C代码
1.TW_CAPABILITY twCapability;
2.TW_INT16 count;
3.TW_STATUS twStatus;
4.TW_UINT16 rc;
5.#ifdef _MSWIN_
6. pTW_ONEVALUE pval;
7.#endif
8.#ifdef _MAC_
9. TW_HANDLE h;
10. pTW_INT16 pInt16;
11.#endif
12.//-----Setup for MSG_SET for CAP_XFERCOUNT
13.twCapability.Cap = CAP_XFERCOUNT;
14.twCapability.ConType = TWON_ONEVALUE;
15.#ifdef _MSWIN_
16. twCapability.hContainer = GlobalAlloc(GHND,
17.
sizeof(TW_ONEVALUE));
18. pval = (pTW_ONEVALUE) GlobalLock(twCapability.hContainer);
19. pval->ItemType = TWTY_INT16;
20. pval->Item = 1; //This app will only accept 1 image
21. GlobalUnlock(twCapability.hContainer);
22.#endif
23.#ifdef _MAC_
24. twCapability.hContainer = (TW_HANDLE)h
25. = NewHandle(sizeof(T
W_ONEVALUE));
26. ((TW_ONEVALUE*)(*h))->ItemType = TWTY_INT16;
27. count = 1; //This app will only accept 1 image
28. pInt16 = ((TW_ONEVALUE*)(*h))->Item;
29. *pInt16 = count;
30.#endif
31.//-----Set the CAP_XFERCOUNT
32.rc = (*pDSM_Entry) (&AppID,
33. &SourceID,
34. DG_CONTROL,
35. DAT_CAPABILITY,
36. MSG_SET,
37. (TW_MEMREF)&twCapability);
38.#ifdef _MSWIN_
39. GlobalFree((HANDLE)twContainer.hContainer);
40.#endif
41.#ifdef _MAC_
42. DisposHandle((HANDLE)twContainer.hContainer);
43.#endif
44.//-----Check Return Codes
45.//SUCCESS
46. if (rc == TWRC_SUCCESS)
47. //the value was set
48. //APPROXIMATION MADE
49. else if (rc == TWRC_CHECKSTATUS){
50. //The value could not be matched exactly
51. //MSG_GET to get the new current value
52. twCapability.Cap = CAP_XFERCOUNT;
53. //Source will specify
54. twCapability.ConType = TWON_DONTCARE16;
55. //Source allocates and fills container
56. twCapability.hContainer = NULL;
57. rc = (*pDSM_Entry) (&AppID,
58. &SourceID,
59. DG_CONTROL,
60. DAT_CAPABILITY,
61. MSG_GET,
62. (TW_MEMREF)&twCapabili
ty);
63. //remember current value
64.#ifdef _MSWIN_
65. pval = (pTW_ONEVALUE) GlobalLock(twCapability.hContainer);
66. count = pval->Item;
67. //free hContainer allocated by Source
68. GlobalFree((HANDLE)twCapability.hContainer);
69.#endif
70.#ifdef _MAC_
71. pInt16 = ((TW_ONEVALUE*)(*h))->Item;
72. count = *pInt16;
73. //free hContainer allocated by Source
74. DisposeHandle((HANDLE)twCapability.hContainer);
75.#endif
76.}
77.//MSG_SET FAILED
78.else if (rc == TWRC_FAILURE){
79. //check Condition Code
80. rc = (*pDSM_Entry) (&AppID,
81. &SourceID,
82. DG_CONTROL,
83. DAT_STATUS,
84. MSG_GET,
85. (TW_MEMREF)&twStatus);
86. switch (twStatus.ConditionCode){
87. TWCC_BADCAP:
88. TWCC_CAPUNSUPPORTED:
89. TWCC_CAPBADOPERATION:
90. TWCC_CAPSEQERROR:
91. //Source does not support setting this cap
92. //All Sources must support CAP_XFERCOUNT
93. break;
94. TWCC_BADDEST:
95. //The Source specified by pSourceID is not open
96. break;
97. TWCC_BADVALUE:
98. //The value set was out of range for this Source
99. //Use MSG_GET to determine what setting was made
100. //See the TWRC_CHECKSTATUS case handled earlier 101. break;
102. TWCC_SEQERROR:
103. //Operation invoked in invalid state
104. break;
105. }
106.}
关于另外的能力
∙Image Type:虽然没说,但是应用应该知道源的ICAP_PIXELTYPE和ICAP_BITDEPTH。

∙Transfer Mode:默认的传输方式是Native。

也就是说源会接受一次性把扫到的传回来给应用。

如果可用内存不够大的话,就失败了。

第4到第5步:从源获取数据
源设备被打开了,也知道他能干什么了,应用激活源,然后用他的接口,请求,然后获取数据。

操作码:DG_CONTROL / DAT_USERINTERFACE / MSG_ENABLEDS
∙pOrigin:指向应用的TW_IDENTITY结构
∙pDest:指向源的TW_IDENTITY结构
∙pData:指向类型是TW_USERINTERFACE的一个结构
TW_USERINTERFACE定义如下:
C代码
1.typedef struct {
2. TW_BOOL ShowUI;
3. TW_BOOL ModalUI;
4. TW_HANDLE hParent;
5.} TW_USERINTERFACE, FAR *pTW_USERINTERFACE;
如果要源显示用户接口就将ShowUI设为TRUE,要么设成FALSE
如果应用要源以modal形式运行,ModalUI设成TRUE,要么就FALSE以Modeless。

也就是说,FALSE的时候,是阻塞的,等源的GUI跑完了,才能继续使用应用。

Win下,应用把句柄给Window,作为Source‘s parent。

再解释一下流程就是说:用户选择应用的Acquire菜单,应用激活源,应用通常请求源显示,以帮助用户获得数据。

源被告之,获取操作码之后就显示了,以模态非模态显示就看你的ModalUI设置了。

源必须检查ShowUI,如果不支持就返回错误码,也就是说忽略ShowUI=FALSE,然后继续。

第5步到第6步:
源来控制从第5步到第6步。

没操作码从应用传过来了。

源自娱自乐。

记住,源激活之后,应用就一直转发他的时间循环给源,
操作码:DG_CONTROL /DAT_EVENT / MSG_PROCESSEVENT
TW_EVENT结构如下:
C代码
1.typedef struct {
2. TW_MEMREF pEvent; /*Windows pMSG or MAC pEvent */
3. TW_UINT16 TWMessage;/*TW message from the Source to the app
lication*/
4.} TW_EVENT, FAR *pTW_EVENT;
源当他准备好传输数据的时候,设置TWMessage。

应用对每个DG_CONTROL
/DAT_EVENT / MSG_PROCESSEVENT都要检查TWMessage,如果MSG_XFERREADY,就到了第6步,源将会等待应用请求真的传输数据了。

第6步到第7步:
源说他I DO了,等着应用上了。

应用就大厅图的细节,初始化传输,之后就到第7步。

但是如果初始化失败,还留在第六步就。

初始化操作码:DG_IMAGE / DAT_IMAGENATIVEXFER / MSG_GET
两个操作可以使用的:
操作码:DG_IMAGE / DAT_IMAGEINFO / MSG_GET
∙pOrigin:应用的TW_IDENTITY结构
∙pDest:源的TW_IDENTITY结构
∙pData:指向TW_IMAGEINFO型的一个结构
TW_IMAGEINFO定义如下:
C代码
1.typedef struct {
2. TW_FIX32 XResolution;
3. TW_FIX32 YResolution;
4. TW_INT32 ImageWidth;
5. TW_INT32 ImageLength;
6. TW_INT16 SamplesPerPixel;
7. TW_INT16 BitsPerSample[8];
8. TW_INT16 BitsPerPixel;
9. TW_BOOL Planar;
10. TW_INT16 PixelType;
11. TW_UINT32 Compression;
12.} TW_IMAGEINFO, FAR *pTW_IMAGEINFO;
源填充这个结构,应用不管以什么方法传输(本地,文件,缓存)都从这拿到数据。

操作码:DG_IMAGE / DAT_IMAGENATIVEXFER / MSG_GET
∙pOrigin:指向应用的TW_IDENTITY结构
∙pDest:指向源的TW_IDENTITY结构。

相关文档
最新文档