3 ----- TWAIN学习记录二

七、TWAIN最常用的Triplets操作

这里将对TWAIN中最常用的Triplets操作做一个简单的介绍,为了便于理解和记忆,我将结合前面讲的操作流程顺序去介绍这些常用的Triplets操作。

 

1.加载Source Manager并获得DSM_Entry入口函数 (状态1到2)

应用程序在调用DSM_Entry函数指针前必须加载Source Manager。这里没有使用Triplets操作。你可以使用LoadLibrary()函数,加载TWAIN_32.DLL文件。并使用GetProcAddress()函数,获得DSM_Entry函数指针

 

2.打开Source Manager (状态2到3)

Triplets 操作:DG_CONTROL / DAT_PARENT / MSG_OPENDSM

通过该操作,你可以打开Source Manager,并且还要在你的应用程序中,指定一个窗体作为Source的父窗口。Source Manager 将通过该窗体,把Source的消息传递给你的应用程序。

 

3.选择Source (状态3期间)

Triplets 操作:DG_CONTROL / DAT_IDENTITY / MSG_USERSELECT

你的应用程序发送该操作后,将显示Source Manager的用户界面,它是一个对话框。这个对话框中显示了系统中所有支持Twain的设备列表。系统默认设备将高亮显示在列表框中。你可以通过该列表框选择你想要的输入设备。

 

4.打开Source (状态3到4)

Triplets 操作:DG_CONTROL / DAT_IDENTITY / MSG_OPENDS

该操作可以打开你选择的Source(图像输入设备),同时,Source Manager会给该Source分配一个唯一的标识符。你要把打开的这个Source放在一个指定的结构中,以便于在后面和该Source进行通讯。

 

5.设置Source的性能参数 (状态4期间)

Triplets 操作:DG_CONTROL / DAT_CAPABILITY / MSG_GET

DG_CONTROL / DAT_CAPABILITY / MSG_SET

这里有两个Triplets操作,通过使用这两个操作可以去查询当前设备是否支持的某种功能,如果支持,还可以获得设备功能的当前值、默认值、以及可以重新设置的范围。你还可以根据查询的结果,按你的要求去重新设置该功能的当前值。

 

6.请求从Source获取数据 (状态4到5)

Triplets 操作:DG_CONTROL / DAT_USERINTERFACE / MSG_ENABLEDS

通过该操作,可以让Source显示它的用户界面,Source会去为数据传输作准备。

 

7.认数据准备传输 (状态5到6)

Triplets 操作:DG_CONTROL /DAT_EVENT / MSG_PROCESSEVENT

首先要说明一下,从状态5到状态6的这个过程,不是由你的应用程序通过Triplets操作来发起的。而是当Source准备好去传输数据时,它会发出一个事件信号来实现的。你的应用程序应该要去检查这个事件信号。

如何去检查这个事件信号?我们在加载Source Manager时,就为Source指定了一个父窗口,Source会把它事件信号封装成一个Windows的消息结构发送给它的父窗口。你可以在这个窗体的消息循环中去,使用 DG_CONTROL /DAT_EVENT / MSG_PROCESSEVENT操作,来判断Source是否有事件发生。MSG_XFERREADY就表示这个过程的状态位从5变为6了。

 

8.开始进行数据传输 (状态6到7)

Triplets 操作:DG_IMAGE / DAT_IMAGEINFO / MSG_GET

DG_IMAGE / DAT_IMAGENATIVEXFER / MSG_GET

在开始数据传输前,可以通过 DG_IMAGE / DAT_IMAGEINFO / MSG_GET 操作,去获得将要传输的图像的相关信息,比如位图大小、宽度、长度…。

通过 DG_IMAGE / DAT_IMAGENATIVEXFER / MSG_GET 操作,可以实现使用本地传输模式去传输数据。传输结束了,Source 将给它的父窗口一个 PM_XFERDONE 的消息。Source将在 DSM_Entry() 中返回为一个指向 DIB 位图的指针。

 

9.中止传输 (状态7到6到5)

Triplets 操作:DG_CONTROL / DAT_PENDINGXFERS / MSG_ENDXFER

在每次数据传输结束(成功、退出)后,可以发送该操作给Source,去表示应用程序已经接受完了所有的数据了。同时还可以根据它的返回值,去检查是否有其它的图像等待传送。

 

10.断开TWAIN会话 (状态5到4)

Triplets 操作:DG_CONTROL / DAT_USERINTERFACE / MSG_DISABLEDS

该操作让打开Source失效。

 

11.关闭Source (状态4到3)

Triplets 操作:DG_CONTROL / DAT_IDENTITY / MSG_CLOSEDS

该操作可以关闭指定的Source。

 

12.关闭Source Manager(状态3到2)

Triplets 操作: DG_CONTROL / DAT_PARENT/MSG_CLOSEDSM

关闭打开的Source Manager。

 

七、TWAIN的数据传输模式

TWAIN定义了三种模式用于Source 到Application的数据传输:本地模式、文件模式,和缓存模式。现在对每种模式进行一个简单的介绍。

注:对于音频数据的传输,只能选择本地模式或者文件模式来进行传输。

 

本地模式

所有的输入设备都支持这种本地数据传输模式,同时它也是TWAIN默认的数据传输模式,并且它还是最容易使用的数据传输模式。但是,它有一定的局限性,它传输的数据必须是DIB 图像数据,并且在传输时,会受到系统内存大小限制。

 

传输数据的格式: DIB (Device-Independent Bitmap)

使用该模式,在数据传输时Source分配一块单独的内存区域,并把图形数据写入这个内存区域内。然后它通过一个指向该内存地址的指针告诉Application,数据存放在什么地方。你的应用程序通过访问该内存区域去获得具体的图像数据。注意,Application在获得数据后要负责去释放这部分的内存。如果你的图像数据大于系统当前可用内存,会导致传输失败。

 

文件模式

该模式是让Application 创建一个文件,这个文件用于储存传输的数据,Source将对该文件进行读写操作。Source将把要传输的数据写到该文件中,你的应用程序通过访问该文件,就可以获得传输的数据。

 

在使用本地模式传输一个大的图像文件时,如果内存不够大,可以考虑使用文件传输模式来传输。文件传输模式与缓存传输模式相比,在使用方法上要简单些,但是该模式在传输速度上比缓存模式的传输速度要慢一些,并且在数据传输完毕后,你的应用程序还必须去管理这个数据文件。

 

缓存模式  

缓存模式在整个传输过程中,将使用一个或多个内存缓存区,内存缓存区的分配和释放工作由Application来控制。在传输过程中,传输数据被当作一个未知格式的位图。Application必须使用TW_IMAGEINFO 和 TW_IMAGEMEMXFER操作,去得到各个缓存区的信息并把它们正确组织为一个完整的位图。

 

如果使用本地模式 或 文件模式去传输数据,整个传输过程在只需要一个Triplets操作就可以完成。如果使用缓存模式 传输数据, 你的应用程序可能需要使用多个Triplets操作,不停地去获得缓存区的数据信息。但是,该传输模式具有很好的灵活性, 可以很好的去控制获得的数据,只不过在编程应用上要麻烦一些。

 

八、TWAIN的应用实现

好了,看了前面的对TWAIN的介绍,现在我们就动手开始进行实际的编程吧。在这里,只进行一个最简单的应用实现。我们的应用程序不去设置设备的性能参数,不选择其它数据传输模式,仅仅使用TWAIN的默认的本地传输模式方式,去获得图像数据。

在进行实际编程应用前,我们可以先安装TWAIN提供的工具包。它不仅提供了TWAIN应用的例程,还可以在你的计算机系统上安装一个虚拟的图像输入设备(TWAIN_32 Sample Source )。这对于没有扫描仪、数码相机的开发者,提供了一个很好的测试设备。TWAIN工具包的下载地址:http://www.twain.org/devfiles/twainkit.exe 。

由于TWAIN目前提供的是基于C的编程接口,所以我们这里采用VC作为开发工具。我们可以建一个自己的TWAIN类。把一些Triplets操作封装成这个类的成员函数。以便于程序调用。记住:在你的项目中要加入TWAIN提供的头文件。

前面已经介绍了,在进行TWAIN的操作前,如何加载TWAIN_32.dll文件,获得DSM_Entry()函数指针。下面仅简单介绍一下其他的成员函数。

 

1. 打开Source Manager

int CTwain::OpenSourceManager(void)

{

TW_UINT16 rc;

. . .

// lpDSM_Entry 是指向DSM_Entry的函数指针

    rc = (*lpDSM_Entry) (&AppID, NULL,

                        DG_CONTROL,DAT_PARENT,MSG_OPENDSM,                                 // hPWnd 是指定为Source的父窗口的句柄

                         (TW_MEMREF) & (*hPWnd)) ;

    switch (rc)    // 检查打开Source Manager是否成功

    {

    case TWRC_SUCCESS:   // 成功

        . . .

    case TWRC_CANCEL:

         . . .

    }

    . . .

}

 

2.打开Source

int CTwain::OpenSource(void)

{

    TW_UINT16 rc;

    rc = (*lpDSM_Entry) (&AppID,NULL,

                        DG_CONTROL,DAT_IDENTITY,MSG_OPENDS,

                       (TW_MEMREF) &SourceID); // SourceID 是要求打开Source

switch (rc)    // 检查打开Source Manager是否成功

    {

    case TWRC_SUCCESS: // 成功

     . . .

    }

     . . .

}

 

3.处理Source的事件

int CTwain::DealSourceMsg(MSG *pMSG)

{

    TW_UINT16 rc    = TWRC_NOTDSEVENT;

    TW_EVENT twEvent;

    twEvent.pEvent = (TW_MEMREF) pMSG;

    rc = (*lpDSM_Entry) (&AppID,&SourceID,

                        DG_CONTROL,DAT_EVENT,MSG_PROCESSEVENT,

                        (TW_MEMREF) &twEvent);

    switch (twEvent.TWMessage)

    {

    case MSG_XFERREADY: // Source准备好传输数据了 iStatus=6

        iStatus=6;

        GetBmpInfo();

        DoNativeTransfer();

    case MSG_CLOSEDSREQ: // 关闭 Source 用户界面的申请

    case MSG_CLOSEDSOK:

    case MSG_NULL:

    }  

. . .

}

 

4.使用本地模式传输数据

int CTwain::DoNativeTransfer(void)

{

    TW_UINT32 hBitMap = NULL; // 指向图像数据地址

    TW_UINT16 rc;

     HANDLE     hbm_acq = NULL;

     rc = (*lpDSM_Entry)(&AppID,&SourceID,

                        DG_IMAGE,DAT_IMAGENATIVEXFER,MSG_GET,

                        (TW_MEMREF)&hBitMap);

    switch (rc)

    {

    case TWRC_XFERDONE:      // 数据传输完成

        hbm_acq = (HBITMAP)hBitMap;

          // 把图像数据地址通过消息发送给应用程序

// 应用程序通过就可以通过 hbm_acq 来处理图像数据

        SendMessage(*hPWnd, PM_XFERDONE, (WPARAM)hbm_acq, 0);

        iStatus = 7;

break;

    case TWRC_CANCEL:

    case TWRC_FAILURE:

    }

     . . .

}

5.应用程序处理图像数据

LRESULT CTwainAppView::WindowProc(UINT message, WPARAM wParam, LPARAM lParam)

{

    if (message==PM_XFERDONE) // 收到 PM_XFERDONE 消息

{

       HBITMAP hBmp=FixUp(HANDLE(wParam)); // 图像转换处理

        Bitmap *pBm=0;                           // GDI+的Bitmap对象

       pBmp=pBm->FromHBITMAP(hBmp,hDibPal);

       Invalidate();

       . . .

     }

    return CView::WindowProc(message, wParam, lParam);

}

6.在应用程序的视图窗口上绘图

void CTwainAppView::OnDraw(CDC* pDC)

{

. . .

// 使用 GDI+ 在视图上 绘图

Graphics   myGraphics ( pDC->m_hDC ) ;

myGraphics.DrawImage ( pBmp , 0, 0,

pBmp->GetWidth(), pBmp->GetHeight() );

    . . .

}

我对twain也只是了解很少的一部分,还有很多功能没有实现,比如如何设置设备的性能参数、如何使用不同的数据传输模式、如何获得图像的布局,如何传输压缩的图像数据、如何更改Source Manager的用户界面等等。希望领导和同事多多指导交流。

posted @ 2011-12-09 10:20  lcryby  阅读(1203)  评论(0)    收藏  举报