4.1 性能
应用程序与源进行性能协商的能力使人们能够控制TWAIN兼容的程序。在第四章“应用程序端的高级实现”中,你将看到对CAP_XFERCOUNT性能的协商。性能在并且总是在状态4期间进行协商,除非应用程序和源双方同意延迟协商。事实上,关于性能还有更多需要我们去了解。
4.1.1 性能值
TWAIN为每种性能定义了一个默认值和一组允许使用的值(见第10章)。应用程序不允许修改默认值,但允许将向用户提供的值限定为一个允许使用值的子集,以及选择性能的当前值。
4.1.1.1 默认值
一个源被打开时,每种性能的当前值都被设置为TWAIN定义的默认值。若TWAIN未定义,则源将选择一个值作为默认值。程序可以使用DG_CONTROL/ DAT_CAPABILITY / MSG_RESET操作将某性能重置为TWAIN定义的默认值。
虽然TWAIN为许多种性能定义了默认值,源也可能因为能够获得更高的效率而首选一个不同的值。例如,源通常在黑白图像中用位值0来代表白色,但是ICAP_FIXELFLAVOR的默认值为TWPF_CHOCOLATE,此值表示0代表黑色。即使TAWIN默认值为TWPF_CHOCOLATE,源也可能将TWPF_VANILLA作为首选值。当应用程序发出一个DG_CONTROL/DAT_CAPABILITY/MSG_GETDEFAULT操作时,源将返回它的首选值的信息。基于此信息源和应用程序将能够协商出一个更有效的传送方式。
注意这并不是在暗示TWAIN定义的默认值应被完全忽略。在处理特殊数据源性能的首选值和TWAIN默认值之间的冲突时,应考虑到此问题与在会话间保存和恢复图像属性类似。假定一个数据源想保存某些性能的当前值以在将来的某个会话中恢复是合理的,期望恢复值能够反映性能的当前设置也是合理的。若保存设置对图像属性确实有用,那么应声明数据源的首选值也采用同样方式进行处理。
加载数据源时,相关性能的当前值应被设置为从上一个会话恢复的值或数据源首选的值。此值将保持直至被应用程序显式更改或应用程序发出MSG_RESET操作。
并非所有性能都适用首选值,另外许多性能不适合在多个会话间保存和恢复。
以下是最好的例子:
例1:扫描参数在一个会话中保存并在另一个会话中恢复
1. 用户使用以下参数配置数据源用户接口:24位4*6英寸图像,水平竖直方向的DPI均为200。
2. 用户选择“扫描”然后数据源通知程序进行传送。
3. 应用程序成功获得图像。
4. 应用程序禁用数据源。
5. 应用程序状态4下询问帧,像素类型,位深度和分辨率的当前值。
6. 数据源报告用户设置的当前值:24位4*6英寸图像,水平竖直方向的DPI均为200。
7. 应用程序关闭数据源。
8. 在关闭期间,数据源保存当前帧,像素类型,位深度和分辨率。
9. 应用程序打开数据源。
10. 在打开期间,数据源恢复帧,像素类型,位深度和分辨率。
11. 应用程序在状态4下询问帧,像素类型,位深度和分辨率和当前值。
12. 数据源报告从上一个会话中恢复的数据:24位4*6英寸图像,水平竖直方向的DPI均为200。
例2:数据源使用首选Pixel Flavor代替TWAIN定义的默认值
1. 应用程序首次打开数据源。
2. 应用程序在状态4下询问默认Pixel Flavor。
3. 数据源报告Pixel Flavor默认为TWPF_CHOCOLATE。
4. 应用程序在状态4下询问当前Pixel Flavor。
5. 数据源报告Pixel Flavor当前为TWPF_VANILLA(因为设备本身采用这种方式返回数据)。
6. 应用程序要求重置Pixel Flavor。
7. 在重置期间,数据源将当前值变更为TWPF_CHOCOLATE并准备在传输过程中转换数据以适应应用程序要求。
此逻辑在一种情况下会失效。如果数据要对一个受限制的性能的MSG_GET返回TW_ENUMERATION, TAWIN定义的默认值有可能不在值的约束集合内。在这种情况下,应用程序将认为默认值未定义。一个常识是,出于安全性的考虑,数据源应在当前可用值集合中提供一些合理的默认值(TW_ENUMERATION中存储一个坏索引是灾难性的)。当默认值事实上正被使用时(通过MSG_RESET),此限制将无效并且当前默认值可再次存在并被定义。这是一个仅限于TW_ENUMERATION容器的问题,因为它包含默认值的索引。
4.1.1.2 当前值
应用程序可能要求设置性能的当前值。如果源的用户界面正在显示,当前值也许能从中看出(例如高亮)。如果应用程序设置了当前值,它用于采集和传输直至被用户或一个自动源进程更改。应用程序可在状态6下通过检查当前值判断是否有更改发生。
若仅需要确定性能的当前值,请使用MSG_CONTROL / DAT_CAPABILITY / MSG_GETCURRENT;若要确定当前值以及可用值,请用DG_CONTROL / DAT_CAPABILITY / MSG_GET。例如您可以对ICAP_PIXELTYPE使用MSG_GET,源将返回一个包含可用值TWPT_BW、TWPT_GRAY和TWPT_RGB的TW_ENUMERATION容器。
若要设置当前值,请使用DG_CONTROL / DAT_CAPABILITY / MSG_SET以及下列容器之一:
• TWON_ONEVALUE:将TW_ONEVALUE.Item置为要求的值。
• TWON_ARRAY:将TW_ARRAY.ItemList置为要求的值。
其中值必须为MSG_GET操作返回值的一个子集。
同样还可以通过TW_ENUMERATION和TW_RANGE容器来设置当前值。
4.1.1.3 可用值
为了限制在获取和传送过程中限制源可用的设置,应用程序可限定可用值,源不会使用这些值以外的值。这些限制将体现在源的用户界面上,因此不可用的值将不会提供给用户。
例如,如果ICAP_PIXELTYPE上的操作MSG_GET表明源支持TWPT_BW,TWPT_GRAY和TWPT_RGB图像,但应用程序只想要黑白图像,那么它可以要求限制可用值为TWPT_BW。
若要设置可用值,请使用DG_CONTROL / DAT_CAPABILITY / MSG_SET以及下列容器之一:
• TWON_ENUMERATION:将TW_ENUMERATION.ItemList域置为要求的值。通过将CurrentIndex指定为ItemList中某个值的索引,也可在此时设置当前值。
• TWON_RANGE:将TW_RANGE域设置为要求的值。此时同样可设置当前值。
注:TW_ONEVALUE和TW_ARRAY容器不可用于限制可用值。
4.1.2 性能协商
协商过程包括以下几个基本的部分:
• 应用程序确定源支持哪些性能。
• 应用程序按要求设置支持的性能。
• 应用程序校验设置是否已被源接受。
4.1.2.1 确定源支持哪些性能
步骤一
应用程序分配一个TW_CAPABILITY结构并如下填充:
Cap = 感兴趣的性能的名称,一般为CAP_name或ICAP_name
ConType = TWON_DONTCARE16
hContainer = 设置为NULL
步骤二
执行DG_CONTROL / DAT_CAPABILITY / MSG_GET并传递TW_CAPABILITY。
步骤三
源检查Cap域并判断是否支持此性能。若支持,则为应用程序生成信息,否则设置一个合适的返回值。
步骤四
应用程序检查操作的返回值(也许是状态码):
若为TWRC_SUCCESS,则源支持该性能并且:
• 源将一个容器(TWON_ARRAY,TWON_ENUMERATION,TWON_ONEVALUE,TWON_ONEVLUE或TWON_RANGE)标识符填充到ConType域。
• 源分配一个ConType指定类型的容器结构并使hContainer域引用此结构。然后用性能的当前值、默认值和可用值填充此结构。
根据容器的类型和内容(类型由其ItemType域指定),应用程序可读取其中的值。应用程序必须负责释放容器。
若TWRC_FAILURE或TWCC_CAPUNSUPPORTED,则源不支持该性能。
应用程序可对任何它想了解的性能重复此操作过程。若应用只想获取性能的当前值,可以使用MSG_GETCURRENT代替。在那种情况下,ConType只可能是TWON_ONEVALUE或TWON_ARRAY而不可能是TWON_RANGE或TWON_ENUMERATION。
注:性能CAP_SUPPORTEDCAPS返回源所支持的性能列表,但没有表示支持的性能是否能够协商。若源不支持性能CAP_SUPPORTEDCAPS,则返回TWRC_FAILURE或TWCC_CAPUNSUPPORTED。
4.1.2.2 按要求设置支持的性能
步骤一
应用程序分配一个TW_CAPABILITY结构并如下填充:
CAP = 感兴趣的性能名称,一般为CAP_name或ICAP_name
ConType = TWON_ARRAY,TWON_ENUMERATION,TWON_ONEVALUE或TWON_RANGE
hContainer = 应用程序应分配一个ConType所指示的结构并关联到此域。
步骤二
应用程序分配一个ConType指定的结构并填充它,根据MSG_GET操作返回的值,可指定所要求的当前值和可用值。应用程序不应尝试设置源的默认值,而只应该为该域施加合理的限制。
注:操作完成后,应用程序应负责在操作完成后释放此容器结构。
步骤三
使用DG_CONTROL/DAT_CAPABILITY/MSG_SET操作发送请求。
4.1.2.3 检查请求的返回值
步骤一
源支持某些性能不代表源支持设置此性能。应用程序必须检查MSG_GET的返回值以确定发生了什么:
返回TWRC_SUCCESS表示源按要求设置了性能。
返回TWRC_CHECKSTATUS表示源无法使用一个或多个您限定的值。例如,你要求值310但它只能接受100、200、300或400。您的请求不在它的有效范围内,因此它选择一个最接近的有效值。
此时使用DG_CONTROL / DAT_CAPABILITY / MSG_GET操作来获取当前值和可用值是判断源的选择对应用程序是否可接受的唯一途径。
返回TWRC_FAILURE或TWCC_BADVALUE表示:
• 源不允许您设置或限定值的请求。或
• 请求的值不在有效值范围内,源可能尝试设置为一个最接近的可用值。
此时应同样使用DG_CONTROL/DAT_CAPABILITY/MSG_GET来确定应用程序是否能继续工作。
4.1.3 常用的性能
TWAIN定义了超过150种的性能。虽然数量看起来很大,但如果认识到只有一部分是常用的,你就会觉得轻松点。以下是其中一些:
4.1.3.1 基础性能
Units(单位)
ICAP_UNITS性能用于确定源所使用的计量单位。默认为英寸,其它允许的值为厘米、像素等。此性能的值用于衡量其它一些性能或结构的值,包括:
ICAP_PHYSICALHEIGHT,
ICAP_PHYSICALWIDTH,
ICAP_XNATIVERESOLUTION,
ICAP_YNATIVERESOLUTION,
ICAP_XRESOLUTION,
ICAP_YRESOLUTION,
TW_FRAME,TW_IMAGEINFO.XResolution,
TW_IMAGE.YResolution
Sense of the Pixel(像素涵义)
ICAP_PIXELFLAVOR描述从源传送到应用程序后位数据应如何解释。默认值为TWPF_CHOCOLATE,它表示0为黑色(最深的颜色);另一个值为TWPF_VANILLA,它表示0为白色(最浅的颜色)。
3Resolution(分辨率)
图像分辨率在TW_IMAGEINFO结构中提供。若要查询或设置源的分辨率,请使用ICAP_XRESOLUTION,ICAP_YRESOLUTION。
同样还有CAP_XNATIVERESOLUTION,ICAP_YNATIVERESOLUTION。
4.1.3.2 图像类型性能
Types of Pixel(像素类型)
应用程序应协商ICAP_PIXELTYPE和ICAP_BITDEPTH,除非它能在所有位深度上处理所有像素类型。允许的像素类型包括TWPT_BW,TWPT_GRAY,TWPT_RGB、TWPT_PALETTE,TWPT_CMY,TWPT_CMYK,TWPT_YUV,TWPT_YUVK,TWPT-CIEXYZ和TWPT_INFRARED。
Depth of the Pixels(in bits) 像素位深度
对于TWPT_BW这样的像素类型,一个像素仅占一位。其它像素类型允许每个像素占多个位(4位或8位灰度图像或24位彩色图像)。请确保先设置ICAP_PIXELTYPE,然后再设置ICAP_BITDEPTH。
4.1.3.3 图形采集参数
Exposure(曝光)
许多性能对此有影响,包括ICAP_BRIGHTNESS,ICAP_CONTRAST,ICAP_SHADOW,ICAP_HIGHLIGHT,ICAP_GAMMA和ICAP_AUTOBRIGHT。
Scaling(缩放)
若要通知源在传输前缩放图像,请参考ICAP_XSCALING和ICAP_YSCALING。
Rotation(旋转)
若要通知源在传输前旋转图像,请参考ICAP_ROTATION和ICAP_ORIENTATION。
4.1.4 限制性能以及消息响应
在应用程序给性能支持的值施行了限制后,数据源在响应性能的相关查询时会存在不确定性。以下指南有助于厘清这种状况。
MSG_RESET
我们已经知道这将使性能的值重置为默认值,但还必须声明一点:这也会重置任何应用程序施加在性能上的限制。
MSG_GETCURRENT和MSG_GETDEFAULT
显然没有当前或默认值的性能将不会支持这些消息。但第10章描述了另一种可能性,在这种情况下,简单地采用与MSG_GET相同的方式响应这些消息是有意义的。
同样直观的是数据源将在所有允许的情况下使用TW_ONEVALUE来响应对性能的请求。
MSG_GET
如果应用程序对当前性能施加了限制,那么数据源将根据这些限制来响应此消息。否则将以将所有源支持的值作为响应。当然,响应中能够包含的值的数量要受到容器的限制。
MSG_SET
第7章有关此三联码的描述:
“当容器为TW_ONEVALUE或TW_ARRAY时设置当前值,当容器为TW_ENUMERATION或TW_RANGE时设置可用值以及当前值”
为进一步说明此操作,必须先声明一点:当应用程序施加一个限制时,源必须考虑所支持的值以及要求的限制。结果应为即支持又被限定使用的值的集合。
施加限制后会产生一种情况,即默认值不再在支持的值集合当中时。使用TW_ENUMERATION时,报告的的默认值索引应被数据源设置为限制集合中的某个值。这是一个确保索引有效的预防措施。在这种情况下,TW_ENUMERATION中的默认值不再有意义,应用程序可将其忽略,直至限制被MSG_RESET操作取消。
4.1.5 代码中的性能容器
性能信息在应用程序和源之间通过一种称为容器的结构进行传递:TW_ARRAY,TW_ENUMERATION,TW_ONEVALUE以及TW_RANGE。创建和读取容器所需的操作用下列代码段说明。容器可灵活地定义用于包含许多种数据之一。请参考工具包以了解容器可用的所有封装和拆包功能。
4.1.6 延迟协商-在状态4之后进行性能协商
应用程序可能在会话期间的任何时刻向源询问性能数据。但是,一个原则是应用程序只能在状态4下请求设置性能。此限制背后的基本原因与源启用时源用户界面的显示有关。许多源需要更改其用户界面的内容以响应应用程序的设置请求。这些更改可预防用户选择与应用程序要求不一致的选项。源用户界面不会在状态4下显示因而可以在用户不查觉的情况下改变。而用户界面在状态5至7时则会显示。
一些性能对用户界面没有影响并且应用程序可能希望在状态4之后进行设置。为了允许延迟协商,应用程序必须在状态4下请求特定的性能能够在稍后进行设置(状态5至6),源可以同意或拒绝此请求。此请求通过在CAP_EXTENDEDCAPS上使用DG_CONTROL/DAT_CAPABILITY操作来协商。
在CAP_EXTENDEDCAPS性能上的DG_CONTROL / DAT_CAPABILITY操作:
MSG_GET
指示源希望在状态5至6下进行协商的所有性能。
MSG_SET
指定应用程序希望在状态5至6下协商哪些性能。
MSG_GETCURRENT
指示源和应用程序均同意在状态5至6下协商的所有性能。
与其它性能一样,若源不支持CAP_EXTENDEDCAPS,它将返回返回码TWRC_FAILURE和状态码TWCC_CAPUNSUPPORTED。
若应用程序尝试在状态5或6下设置性能但源没有事先同意此安排,此操作将失败,其返回码为TWRC_FAILURE,状态码为TWCC_SEQERROR。
若应用程序不使用源用户界面,则应用程序将控制源的状态。若应用程序想设置性能的值,它可以使源返回状态4再进行此操作。因此使用自己的用户界面的应用程序无需使用CAP_EXTENDEDCAPS。
4.2 数据传送选项
之前已经讨论过,TWAIN为数据传送定义了三种模式:本地、文件和缓存模式。
源被要求支持本地和缓存传送模式。
4.2.1 本地传输模式
此模式的使用在第3章中已介绍。本地模式的一个潜在的局限是可能没有足够大的RAM块可用于保存图像。这种情况直到应用程序发送DG_IMAGE / DAT_IMAGENATIVEXFER / MSG_GET操作尝试进行传输时才会被发现。
当出现内存不足的情况下,源可能的响应方式有多种:
• 简单地使操作失败。
• 裁剪图像使其能够置入可用的内存。源应通知用户由于内存限制而进行了此操作。裁剪应保持图像和外观比例和起点(左上角)。
• 和用户进行沟通以允许变更图像尺寸或取消操作。
DG_IMAGE / DAT_IMAGENATIVEXFER / MSG_GET返回的返回码/状态码可指示发生了哪种动作:
TWRC_XFERDONE:
表示传输已完成并且会话状态为7。但这不能保证源没有裁剪图像。即使应用程序在传输前使用DG_IMAGE/DAT_IMAGEINFO/MSG_GET来确定图像尺寸,也不能认为返回的ImageWidth和ImageHeight适用于最终传输过来的图像。如果图像尺寸对应用程序很重要,则应在传输完成后却检查最终的图像尺寸,如下:
• 调用DG_CONTROL / DAT_PENDINGXFERS / MSG_ENDXFER操作使会话状态从7变更为6(或5)。
• 判断传输的真实的图像的尺寸: Windows —— 读取DIB头信息;Macintosh—— 检查图像的PicFrame。
TWRC_CANCEL:
获取操作被用户取消,会话状态为7。执行DG_CONTROL / DAT_PENDINGXFERS / MSG_ENDXFER操作以使会话状态从7变更为6(或5)。
TWRC_FAILURE:
检查状态码以确定失败的原因。会话状态为6。没有为DIB或PICT分配任何内存。图像依然处于挂起状态。如果是由内存不足引起,可以选择释放额外的内存或执行DG_CONTROL / DAT_PENDINGXFERS / MSG_ENDXFER以丢弃挂起的图像。
4.2.2 磁盘文件传输模式
从版本1.9开始,有两种可用的文件传输机制。Windows开发者可继续使用TWSX_FILE选项,Macintosh开发者则必须使用TWSX_FILE2,以在新版本的操作系统上正确地定位图像和音频文件。
判断源是否支持磁盘文件传输模式:
• 使用DG_CONTROL / DAT_CAPABILITY / MSG_GET操作。
• 将TW_CAPABILITY.Cap域设置为ICAP_XFERMECH。
• 源通过TW_CAPABILITY.hContainer返回它所支持的传输模式信息。磁盘文件模式用TWSX_FILE或TWSX_FILE2标识。源没有被强制要求支持磁盘文件传输模式,因此验证十分必要。
4.2.2.1 确定支持文件传输模式后,启动传输
在状态4下:
• 使用DG_CONTROL / DAT_CAPABILITY / MSG_SET操作,ICAP_XFERMECH设置为TWSX_FILE 或 TWSX_FILE2。
• 将 TW_CAPABILITY. Cap设置为ICAP_IMAGEFILEFORMAT,使用 DG_CONTROL / DAT_CAPABILITY / MSG_GET 确定源支持何种文件格式。源返回所支持的格式的标识符,这些标识符以 TWFF_ 为前缀,包括 TWFF_PICT, TWFF_BMP, TWFF_TIFF等。
在状态4、5、6下:
可使用DG_CONTROL/ DAT_SETUPFILEXFER 的 SG_GET, MSG_GETDEFAULT 和 MSG_SET 操作。此操作相关的数据结构是TW_SETUPFILEXFER 。
应用程序可使用MSG_GETDEFAULT操作来确定默认文件格式和文件名(TWAIN.TMP或TWAIN.AUD)。若要设置文件名和格式:
1. 分配一个TW_SETUPFILEXFER结构,填充适当的域:
a. FileName - 在Windows中请确保包含完整的路径。
b. Format - 以TWFF_开始的常量,如果设置为不支持的格式,则操作将返回TWRC_FAILURE / TWCC_BADVALUE,并且源将重围为输出数据到默认文件。
c. VrefNum - 在Macintosh中,设置为文件的卷标;在Windows中设置为TWON_DONTCARE16。
2. 调用DG_CONTROL / DAT_SETUPFILEXFER / MSG_SET。
4.2.2.2 传输到文件
在应用程序收到MSG_XFERREADY通知并发送DG_CONTROL / DAT_SETUPFILEXFER / MSG_GET后:使用DG_IMAGE / DAT_IMAGEFILEXFER / MSG_GET ,此操作没有与之关联的数据结构,在DSM_Entry调用中pData为NULL。
• 如果应用程序未指定文件名(在Set Up中),源将使用默认文件名或最后一次指定的文件信息。
• 如果应用程序指定的文件不存在,源将创建该文件。
• 如果文件存在但已包含数据,源将覆盖已有数据。所以若对多个文件传输使用相同的文件名,则必须在两次传输之间将文件数据复制到其它地方。
注:一旦开始,应用程序就无法取消文件传输操作。但是,源可能通过其用户界面向用户提供取消传输的功能。
在此操作后,确保检查返回码:
TWRC_XFERDONE:文件成功写入。应用程序应调用DG_CONTROL / DAT_PENDINGXFERS / MSG_ENDXFER使会话返回状态6(或5)。
TWRC_CANCEL:用户取消传输。文件内容未定义,调用DG_CONTROL / DAT_PENDINGXFERS / MSG_ENDXFER使会话返回状态6(或5)。
TWRC_FAILURE:源处于状态6;文件内容未定义;图像依然处于挂起状态。若要放弃图像,可使用DG_CONTROL / DAT_PENDINGXFERS / MSG_ENDXFER。
检查状态以确定失败的原因:
TWCC_BADDEST——指定了无效源。
TWCC_OPERATIONERROR——文件存在但无法存取或在写入时发生系统错误。
TWCC_SEQERROR——在无效状态下操作。
4.2.3 缓存传输模式
数据通常以非压缩格式传输,如果想知道源在缓存传输模式下是否能传输压缩数据,请对ICAP_COMPRESSION使用DG_CONTROL / DAT_CAPABILITY / MSG_GET操作,结果可能为TWCP_NONE ,也可能为TWCP_PACKBITS 、TWCP_JPEG等。
4.2.3.1 启动传输
在状态4下:
使用DG_CONTROL / DAT_CAPABILITY / MSG_SET,ICAP_XFERMECH 设置为TWSX_MEMORY。
在状态4、5、6下:
应用程序使用DG_CONTROL / DAT_SETUPMEMXFER / MSG_GET来确定源想要多大的缓存来传输。在状态6下源可能有更精确的信息。此操作相关数据结构为TW_SETUPMEMXFER,源将根据设备填充合适的值。
对用于非压缩传输的缓存:
• 应用程序负责分配和释放缓存传输所用的所有内存。
• 作为一个可选行为,创建一个所选尺寸大小的缓存。
• 在所有情况下,分配的内存应遵循MinBufSize和MaxBufSize的限制。否则源将操作失败(返回TWRC_FAILURE/TWCC_BADVALUE)。
• 使用多个缓冲区时,各个缓冲区大小必须相同。
• 建议光栅线应对齐到双字并以0填充。
4.2.3.2 执行缓存传输:
应用程序收到MSG_XFERREADY通知并发出DG_CONTROL / DAT_SETUPMEMXFER / MSG_GET后:
• 分配一个或多个相同尺寸的缓冲区,最好是TW_SETUPMEMXFER.Freferred域所声明的尺寸。如果不能,则确保缓冲区尺寸在MinBufSize和MaxBufSize之间。
• 分配一个 TW_IMAGEMEMXFER,第一个域设置为TWON_DONTCARE16,接下来六个域设置为 TWON_DONTCARE32。最后一个TW_MEMORY结构的Memory域如下填充:
Memory.Flags - 描述Memory.TheMem的类型,值为TWMF_POINTER 或 TWMF_HANDLE。
Memory.Length - 缓冲区尺寸,以字符为单位
Memory.TheMem - 指向上述分配的缓冲区的句柄或指针(是句柄还是指针由Flags域指定)。
每传输完一个缓冲区后,源将填充除Memory外的所有域。
缓存传输的流程如下:
步骤一:
缓存传输不提供嵌入的头信息,因此,应用程序必须确定图像属性。例如在状态6下收到MSG_XFERREADY后,发送DG_IMAGE / DAT_IMAGEINFO / MSG_GET 和DG_IMAGE / DAT_IMAGELAYOUT / MSG_GET来了解图像的位图特征、尺寸以及在当前页面上的位置。若需要其它额外的信息,请使用 DG_CONTROL / DAT_CAPABILITY / MSG_GET操作。
步骤二:
发送DG_IMAGE / DAT_IMAGEMEMXFER / MSG_GET。
步骤三:
检查返回码
• TWRC_SUCCESS - 检查TW_IMAGEMEMXFER结构中关于缓冲区的信息。如果想重用缓冲区,将数据拷贝到其它地方去。
若有必要,回到步骤二,重新获取一个缓冲区,重新初始化TW_IMAGEMEMXFER结构,再发送另一个DG_IMAGE / DAT_IMAGEMEMXFER / MSG_GET。
• TWRC_XFERDONE - 这表示源已经成功地传输完了最后一个缓冲区。
• TWRC_CANCEL - 用户取消了传输,应用程序必须发送 DG_CONTROL / DAT_PENDINGXFERS / MSG_ENDXFER以从状态7回到状态6(或5)。
• TWRC_FAILURE - 检查状态码以确定原因。如果失败在首个缓冲区的传输过程中,则会话仍处于状态6;若发生在随后的缓冲区传输过程中,则会话处于状态7。此时缓冲区内容无效且缓冲区传输仍处于挂起状态,若要取消,请使用DG_CONTROL / DAT_PENDINGXFERS / MSG_ENDXFER。
步骤四:
一旦返回了TWRC_XFERDONE,应用程序就必须发送 DG_CONTROL / DAT_PENDINGXFERS / MSG_ENDXFER来结束传输。
注:在使用缓存传输时,大多数源将图像数据分割成条。每个条是一个水平带,从图像左端开始横跨整个图像宽度,但只覆盖部分图像长度(高度)。如果在源返回的TW_IMAGEMEMXFER中,XOffset域为零,Columns域等于TW_IMAGEINFO.ImageWidth域,则可以断定源采用了这种分割方式。
还有一种只有少数源使用的片方式。请参见第八章有关TW_IMAGEMEMXFER的信息。
4.2.4 文件格式的缓存传输模式
此方式与缓冲传输模式非常类似,只是传输的数据遵循之前通过DG_IMAGE / DAT_SETUPFILEXFER / MSG_GET指定的图像文件格式。此方式不要求数据作为完整的图像线传输和任何填充,数据被认为是自包含和自描述的。
4.3 图像数据及其布局
从源传送到应用程序的图像有数个属性。其中一些描述图像尺寸,一些描述图像在原始页面中的位置,还有一些描述分辨率或像素位数等信息。TWAIN为应用程序提供了了解这些属性的途径。
用户通常可通过源用户界面选择和更改图像的属性。额外地,TWAIN也提供了支持在采集和传输前影响这些属性的的性能和操作。
4.3.1 获取将要传输的图像的信息
在传输开始前(状态6),源可向应用程序提供将要传输的真实图像的信息。注意一旦传输开始这样信息将丢失,因此应用程序应在必要时将其保存。这些信息可通过以下操作查询:
DG_IMAGE / DAT_IMAGELAYOUT / MSG_GET
DG_IMAGE / DAT_IMAGEINFO / MSG_GET
采集的图像区域始终是一个称为“框架”(Frame)的矩形。在一个页面上可能分配有多个框架。框架可由用户选择或应用程序指定。TW_IMAGELAYOUT结构指示图像在当前页面上相对于页面起点的位置,同时其FrameNumber域指示这是从页面上采集到的第几个框架。
TW_FRAME结构描述框架的Top、Bottom、Left和Right值。其单位由ICAP_UNITS指定。
图4-1 TW_FRAME结构
DG_IMAGE / DAT_IMAGEINFO / MSG_GET操作传达将被传输的图像的其它一些信息。
请注意TW_IMAGEINFO中ImageWidth、ImageLength和TW_IMAGELAYOUT中描述的框架之间的关联。
4.3.2 变更图像属性
通常用户会去选择所要求的属性,但应用程序可能希望在状态4进行初始化。例如,如果用户界面不会被显示,程序则可能希望选取框架。程序可使用DG_IMAGE / DAT_IMAGELAYOUT / MSG_SET操作来定义要获取的区域(框架)。但是并不存在相应的DG_IMAGE / DAT_IMAGEINFO / MSG_SET操作。
TW_IMAGEINFO 域 | 性能或相关数据结构 |
XResolution | ICAP_XRESOLUTION |
YResolution | ICAP_YRESOLUTION |
ImageWidth * | TW_IMAGELAYOUT.TW_FRAME.Right - TW_FRAME.Left |
ImageLength * | TW_IMAGELAYOUT.TW_FRAME.Bottom - TW_FRAME.Top |
SamplesPerPixel | ICAP_PIXELTYPE |
BitsPerSample | BitsPerPixel 除以SamplesPerPixel |
BitsPerPixel | ICAP_BITDEPTH |
Planar | ICAP_PLANARCHUNKY |
PixelType | ICAP_PIXELTYPE |
Compression | ICAP_COMPRESSION |
注:ImageWidth和ImageLength以像素为单位,而TW_FRAME使用ICAP_UNITS。
4.3.3 解决ICAP_FRAMES、ICAP_SUPPORTEDSIZES和DAT_IMAGELAYOUT之间的冲突
由于有几种方式可用于协商扫描区域,可能难以确定应优先使用哪种方式。一种合理的方案是用设置上一个框架的方式来设置当前框架。不过对于MSG_GET操作而言这三种方式依然难以确定。下列行为是推荐的:
注:框架区域只被ICAP_PHYSICALWIDTH和ICAP_PHYSICALHEIGHT限制,设置ICAP_SUPPORTEDSIZES不会增加新的限制。TWSS_xxxx是只预定义的固定框架尺寸。
若框架由DAT_IMAGELAYOUT设置:
ICAP_FRAMES应以DAT_IMAGELAYOUT调用中设置的框架尺寸来响应MSG_GETCURRENT。
ICAP_SUPPORTEDSIZES应用TWSS_NONE来响应MSG_GETCURRENT。
若当前框架由ICAP_FRAMES设置:
ICAP_FRAMES应以ICAP_FRAMES中设置的当前框架尺寸作为响应。
ICAP_SUPPORTEDSIZES应用TWSS_NONE来响应MSG_GETCURRENT。
若当前固定框架由ICAP_SUPPORTEDSIZES设置,则:
DAT_IMAGELAYOUT应以ICAP_SUPPORTEDSIZES中指定的固定框架尺寸来响应MSG_GET。
ICAP_FRAMES应以ICAP_SUPPORTEDSIZES中指定的固定框架尺寸来响应MSG_GETCURRENT。
4.3.4 ICAP_RETATION,ICAP_ORIENTATION对ICAP_FRAMES,DAT_IMAGELAYOUT、DAT_IMAGEINFO的影响
在尝试处理对当前框架和图像布局的旋转和取向的影响时存在更大的混乱。出于规范化的考虑,约定ICAP_ROTATION and ICAP_ORIENTATION应该在ICAP_FRAMES 和 DAT_IMAGELAYOUT之后应用。
显然取向的改变会影响到输出图形的尺寸,因此DAT_IMAGEINFO中必须予以考虑(状态6)。源报告的作为结果的图像尺寸应考虑当前框架的旋转。
ICAP_ORIENTATION 和 ICAP_ROTATION 是叠加的。最初的框架在从设备下载到源时被ICAP_ORIENTATION修改,体现所扫描的纸张的朝向。然后应用ICAP_ROTATION,得到最终报告给应用程序的框架信息(状态6至7)。结合这两个值的一个可能的理由是使用它们互相抵消。例如,某些内置文档自动传送机的扫描仪可通过将ICAP_ORIENTATION设置为TWOR_LANDSCAPE结合将ICAP_ROTATION设置为90度,来获得更好的性能。因为这将允许用户横向传送它们的图像(传送得更快),然后再通过旋转使采集到的图像重新变为竖向(用户观察的方式)。
4.4 传输多个图像
第3章讨论了单个图像的传输。传输多个图像只是简单地重复单个图像传输的处理过程。在TWAIN下传输多个图像有两类问题:
1. 当会话处于中间图像的边界时传输可处于什么状态?
2. 什么能力可用于支持文档传送机操作?这关系到扫描的高效性。
本段以对单个图像传输过程的回顾作为开始。然后再讨论单个图像传输完毕后应用程序可执行的操作,最后再展示文档传送机。
以下为对单图像传输的简要回顾:
1. 程序启动源,会话状态从4变为5。
2. 准备好图像后,源向程序发送MSG_XFERREADY。
3. 程序使用DG_IMAGE / DAT_IMAGEINFO / MSG_GET和DG_IMAGE / DAT_IMAGELAYOUT / MSG_GET获取将要传输的图像信息。
4. 程序使用DG_CONTROL / DAT_IMAGExxxxFER / MSG_GET操作初始化传输。
5. 传送成功后,源返回TWRC_XFERDONE。
6. 程序发送DG_CONTROL / DAT_PENDINGXFERSR / MSG_ENDXFER操作通知传输结束并获取挂起的传输数量。
如果单个图像传输的背后只是为了将其从源中清除的话,那么一个操作就可以了:
• 发送DG_CONTROL / DAT_PENDINGXFERSR / MSG_ENDXFER操作。正如普通图像传输那样,此操作告诉源程序已经获取完当前图像,并且源报告挂起的传输数量作为响应。
4.4.1 多图像传输的准备
图像传输完成后的DG_CONTROL / DAT_PENDINGXFERSR / MSG_ENDXFER操作有两个重要的功能:
1. 它返回挂起的传输数量(TW_PENDINGXFERS.Count)
2. 若挂起的传输数量大于0,它使会话状态变更为6(准备传输);否则变更为5(源启用)。前面说过当源知道可获取的图像数量时,它返回的数量值为一个正整数;若源不知道可用的图像数量,则返回的数量值为-1。后者在诸如使用了文档传送机的时候可能出现。需要注意的是不知道可用的图像数量也包括了没有可用图像的可能性。请参考DG_CONTROL / DAT_PENDINGXFERSR / MSG_ENDXFER以获取更多相关信息。
我们刚刚了解到MSG_ENDXFER发送后,会话状态可能处于5或6,也就是说会话依然处于活动状态。如果会话处于状态6,则程序可以采取两种行为以使会话状态最终变为5:
• 继续执行单个图像的传输处理过程直至没有更多图像可用。
• 发送一个DG_CONTROL / DAT_PENDINGXFERS / MSG_RESET 清空源中所有挂起的传输。
一旦会话状态返回5,程序就必须决定是停留在状态5还是变更为4。这里有两种可用的方案:
• 程序让源控制未来的状态变更。若源发送MSG_XFERREADY消息,程序重新开始进行多图像传输;如果源发送MSG_CLOSEDSREQ(例如用户激活了源显示的UI上的“关闭”触发器),程序应返回一个DG_CONTROL / DAT_USERINTERFACE / MSG_DISABLEDS使会话回到状态4。
• 程序直接控制会话状态。例如,程序可能希望在当前批次的图像传输完成后关闭,在这上,程序将在没有可用图像后立即发送DG_CONTROL / DAT_USERINTERFACE / MSG_DISABLEDS。
需要注意的是,在当前图像集传输完成后,并没有什么“正确”、“错误”或“首选”的方案可供程序遵照执行。如果程序希望明确地由用户来控制会话的结束,它可以等待源发送MSG_CLOSEDSREQ给它。另一方面,程序可能非常清楚会话的构成,例如,它可能希望扫描会话在遇到一张空白纸张时结束。在这种情况下,程序可能希望借助MSG_DISABLEDS来进行控制。
4.4.2 使用文档传送机(Document Feeder)
文档传送机这个名词即可指物理实体上的自动送稿机(例如用于扫描仪的),也可指逻辑上的图像库的传送功能。两种输入机制都适用于下列讨论的内容。此部分的主题是:
1. 对扫描来自文档传送机还是还是platen(滚筒)的页面进行控制。
2. 检测是否有纸张已准备扫描。
3. 控制预扫描。
注意:这些概念适用于没有传送机的扫描仪。
4.4.2.1 选择文档传送机
有时使用文档传送机将改变图像采集的方式。举例来说,当一张纸放置在台板上时,扫描仪需要在纸上移动它的光标,若使用文档传送器,则扫描仪可能使其光标固定而扫描移动的纸张。为应对这种差异,程序和源可明确地同意是否使用文档传送机。此行为的协商必须在状态4(源启用前)下进行。
CAP_FEEDERENABLED
判断源是否有可用的文档传送机,若是,则选择相关设置。
1. 使用DG_CONTROL / DAT_CAPABILITY / MSG_GET 操作来判断源是否支持此性能。TWRC_FAILURE / TWCC_CAPUNSUPPORTED 表示源不支持选择文档传送机。
2. 若支持,则在状态4下使用DG_CONTROL / DAT_CAPABILITY / MSG_SET操作。
3. 将TW_CAPABILITY.Cap设置为CAP_FEEDERENABLED。
4. 创建一个TW_ONEVALUE窗口并置为TRUE,将TW_CAPABILITY.hContainer指向此结构。
5. 执行MSG_SET操作并检查返回值。
若返回TWRC_SUCCESS,则传送机可用,并且您要求使用它的请求已被接受。程序现在可以设置文档传送机的其它性能了。
若返回TWRC_FAILURE 、TWCC_CAPUNSUPPORTED, TWCC_CAPBADOPERATION或TWCC_BADVALUE,则源不支持文档传送机或不允许使用。
注:如果程序想防止用户使用文档传送机,程序应使用MSG_SET将 CAP_FEEDERENABLED性能设置为FALSE。
4.4.2.2 检查是否有图像已准备好被获取
源设置中是否有图像已准备好被获取与是否有可用的文档传送机无关,这有三种可能:
1. 源无法辨别是否有可用图像。
2. 图像可用于获取,或
3. 无图像可用于获取。
要检测这些情况,请先判断源是否能辨别是否有图像可用于获取,然后再判断是否有可用图像。以下性能用于完成此工作:
CAP_PAPERDETECTABLE
判断源是否能辨别文档是否已加载。
1. 使用DG_CONTROL / DAT_CAPABILITY / MSG_GET操作。
2. 将TW_CAPABILITY.Cap 域设置为 CAP_PAPERDETECTABLE。
3. 源返回TWRC_SUCCESS及一个HContainer结构。若它能够检测可用于获取的文档,则值为TRUE。如果返回值为WRC_FAILURE 和 TWCC_CAPUNSUPPORTED 或 TWCC_BADVALUE,则源不能检测文档是否已加载。
注:CAP_PAPERDETECTABLE可独立于 CAP_FEEDERENABLED进行使用。同样,源并不一定需要一个自动传送机才能支持此性能。一个能够检测是否有纸张在台板上的扫描仪也将返回TRUE。
程序不能设置此性能,源只在必要时报告。
CAP_FEEDERLOADED
判断传送机中是否有文档加载。
1. 使用 DG_CONTROL / DAT_CAPABILITY / MSG_GET操作。
2. 将 TW_CAPABILITY.Cap 域设置为 CAP_FEEDERLOADED。
3. 有文档加载时源将返回TRUE。
注: 对CAP_FEEDERENABLED 和 CAP_PAPERDETECTABLE都一样,TRUE或FALSE并不表示可否使用此性能,FALSE只是表示没有可用文档或无法辨别。为了得到确定的答案,请务必先检查CAP_PAPERDETECTABLE 。
4.4.2.3 控制预扫描
使用低端扫描仪时,CPU通常都能实时或在不同纸张的扫描间隔期间处理输入的图像数据。但是,在使用高效扫描仪时,CPU可用于处理一张纸的图像数据的时间可能显著地少于扫描的时间。如果扫描仪能够扫描CPU将要获取的图像的头数据,则能够缓解此问题。此数据在CPU处理当前图像时缓存到扫描仪本地缓存或通过DMA保存到内存中。
不过预扫描并不总是适合的,因为是否需要继续扫描有时候是由当前扫描的图像决定的。例如扫描程序可能要求在遇到空白纸张时终止扫描。如果启用预扫描,空白纸张之后的一张或多张纸张都有可能被扫描并传送到扫描仪的输出区,从应用程序设计的观点来说这种行为是错误的。
我们已经阐述了控制预扫描功能的必要性。但是,一个简单的“启用预扫描”命令并不足以控制一些扫描仪提供的丰富功能。TWAIN的文档输送模型将每个图像的传输分为三个阶段:
1. 图像在输入区域中。此动作由用户完成(例如将一叠纸放到自动传送机中)。
2. 图像准备好被扫描。此行为导致下一个可用图像被输送到扫描区域的起点处。设置CAP_AUTOFEED性能以自动将图像输送到扫描区域的起点。
3. 图像被扫描。此行为导致图像被扫描。例如,DG_IMAGE / DAT_IMAGEMEMXFER / MSG_GET操作启动图像传输(通过内在缓存传输给程序)。通过设置 CAP_AUTOSCAN性能,TWAIN允许源将图像预取至源本地的存储器(即使程序尚未请求)。
CAP_AUTOFEED
启用源的自动传送文档进程。
1. 使用DG_CONTROL / DAT_CAPABILITY / MSG_SET操作。
2. 将 TW_CAPABILITY.Cap 域设置为 CAP_AUTOFEED 并将性能设置为TRUE。
3. 设置为TRUE时,源的行为是在页面的所有区域都已获取后弹出此页面,然后传送下一页面。有图像数据可获取(并且源处于启用状态)时此自动传送过程将一直持续。 CAP_FEEDERLOADED为TRUE表示纸张在文档传送机中。
注:要使用此性能,CAP_FEEDERENABLED 必须设置为TRUE,否则源将返回 TWRC_FAILURE / TWCC_CAPUNSUPPORTED。
CAP_AUTOSCAN
启用源的文档自动扫描进程。
• 使用DG_CONTROL / DAT_CAPABILITY / MSG_SET。
• 将TW_CAPABILITY.Cap域设置为CAP_AUTOSCAN并将性能设置为TRUE。
• 设置为TRUE时,源的行为是在页面的所有区域都已获取后弹出页面,并开始扫描下一页面。有图像数据可获取(并且源处于启用状态)时此自动扫描过程将一直持续。
注:将 CAP_AUTOSCAN 设置为TRUE将使 CAP_AUTOFEED 隐式被置为TRUE。
应用程序使用文档自动传送时:
• 将CAP_XFERCOUNT设置为-1以表示程序可接受多个图像。
• 预期源返回的TW_PENDINGXFERS.Count值为-1,表示源有更多的图像用于传输但数量未知。
• 使用文档自动传送不会导致多文档传输过程产生变化。
4.4.2.4 程序控制文档传送
除了文档自动传送以外,TWAIN也提供了由应用程序手动控制文档传送的选项。这只有在源同意状态5和6下协商(通过CAP_EXTENDEDCAPS)以下性能时才有可能。如果CAP_AUTOFEED 为TRUE,将影响到尖对以下性能的响应。
CAP_FEEDPAGE
• 如果程序将此性能设置为TRUE,源将弹出当前页面并输送下一页面(若存在)。
• 为了能正常工作,要求 CAP_FEEDERENABLED 和CAP_FEEDERLOADED为TRUE。
• 在 CAP_AUTOFEED为TRUE时也将是同样的动作。
• 弹出的页面对应程序正在获取或将要获取的图像,因此,若 CAP_AUTOSCAN 为TRUE并且有不确定数量的页面已被扫描,则弹出的页面可能是已经扫描到源的本地缓存中的页面。
CAP_CLEARPAGE
• 如果程序将此性能设置为TRUE,源将弹出当前页面并使传送区域为空(即无可获取图像)。
• 为了能像描述的那样工作,要求 CAP_FEEDERENABLED 为TRUE。
• 若 CAP_AUTOFEED 为TRUE,则下一页面将被推送至获取区域。
• 若CAP_AUTOSCAN为TRUE,设置此性能将返回TWRC_FAILURE及TWCC_BADVALUE。
CAP_REWINDPAGE
• 若设置此性能为TRUE,源将把当前页送回输入区域并把输出区域中的最后一个页面送回获取区域。
• 为了能正常工作,要求 CAP_FEEDERENABLED 为TRUE。
• 若 CAP_AUTOFEED 为TRUE,则将在页面的所有区域已获取后进行常规的传送。
• 回溯的页面对应程序正在获取的图像。因此,若CAP_AUTOSCAN为TRUE,并且不确定数量的页面已被扫描,则回溯的页面可能对应已扫描至源的本地缓存中的页面。
4.5 传送压缩数据
在使用缓存传输模式时,某些源可能支持以压缩格式传送数据。
为确定源是否支持传送压缩数据并设置其性能:
1. 使用 DG_CONTROL / DAT_CAPABILITY / MSG_GET操作。
2. 将TW_CAPABILITY.Cap 域设置为 ICAP_COMPRESSION。
3. 源通过TW_CAPABILITY.hContainer指向的一个容器指定所支持的压缩方式信息。可选的压缩方式的标识符均带前缀TWCP_(例如TWCP_PACKBITS),可在第8章的Constants部分和TWAIN.H文件中找到。
4. 若希望协商使用某种压缩方式,请使用 DG_CONTROL / DAT_CAPABILITY / MSG_SET操作。
TW_IMAGEMEMXFER结构用于DG_IMAGE / AT_IMAGEMEMXFER / MSG_GET操作。
传输压缩数据流时(边压缩边传输):
• BytesPerRow域应设置为0,Columns、Rows、XOffset和YOffset域应包含TWON_DONTCARE32 以表示这些域持有无效值(当前图形的尺寸可通过DG_IMAGE / DAT_IMAGEINFO / MSG_GET获取)。
• 缓冲区总是由源进行完整的填充。对于压缩数据则很可能有超过一条的不完整数据被写入缓存。
• 应用程序必须负责销毁缓存。
传输压缩数据块时(先压缩再传输):
• 此结构中的所有域包含有效值。BytesPerRow,Columns,Rows,XOffset和YOffset描述解压因子,Compression和BytesWritten描述压缩因子。
• 与压缩数据流的传输不同的是,此时由源分配传输缓冲。这允许源创建不同尺寸的缓冲区以完整地(未分割到一系列的缓冲区中)将压缩数据传输给程序。在这种情况下,程序应这样设置TW_MEMORY结构:Flags为TWMF_DSOWNS,Length为 TWON_DONTCARE32,TheMem为NULL。源应假定程序将保持之前的缓冲区而不会释放它,因此,源应为每次传输分配一个新的缓冲区。
• 应用程序必须负责销毁缓存。
• 最后,应用程序不应假定tiles会以任何特定的或逻辑的顺序进行传输。
4.5.1 JPEG压缩
TWAIN支持传输多种格式的压缩数据,JPEG压缩是其中一种。JPEG压缩算法为灰度和真彩图像提供了比例从10:1到25:1的压缩比例,代价则是图像质量的下降。此压缩由应用程序通过一系列“感知性的”过滤器分三个阶段完成:
4.5.1.1 颜色空间转换和分量二次取样(针对彩色图像)
由于平均拥有100百万个光线感知器(杆状细胞)和仅约6万个颜色感知器(视锥细胞),人眼对光的强度(亮度)的感知要比对光频率(色度,或“色彩”)敏感得多。通过将彩色图像转换到一个更有效的亮度/色度颜色空间并对色度分量进行二次取样能够轻易地将图像压缩许多。
此转换使用TW_JPEGCOMPRESSION。将TW_JPEGCOMPRESSION.ColorSpace指定为TWPT_YUV,RGB数据被转换为空间上更高效的YUV数据(以CCIR 601-1或YCbCr最广为人知)。
TW_JPEGCOMPRESSION.SubSampling指定最终的YUV数据流中亮度和色度样本的比例。典型的选择是每个色彩样本对两个亮度样本,这通过将TW_JPEGCOMPRESSION.SubSampling值设置为0x21102110来指定。一个更大的比例“每个色彩样本对4个亮度样本”由0x41104110表示。
4.5.1.2 应用离散余弦变换(DCT)和量子化
接下来原分量(经过或未经过颜色空间转换)通过DCT被算术地转换到一个空间频率表示法,然后使用量子矩阵进行过滤(每个频率都被划分到量子矩阵上相关的成员)。量子矩阵由TW_JPEGCOMPRESSION.QuantTable[]指定,可为最多四种不同的
源分量定义最多四个量子矩阵。TW_JPEGCOMPRESSION.QuantMap[]将特定的源分量映射到各个的量子矩阵。
注:JPEG互联网草案标准的K部分推荐为量子映射和量子矩阵提供默认值。TWAIN使用10918-1版本作为QuantTable、HuffmanDC和HuffmanAC和默认表。默认值通过将NULL选入TW_JPEGCOMPRESSION.QuantTable[]来指定。
4.5.1.3 哈夫曼编码
经过DCT和量子化的结果最后通过一个称为哈夫曼编码的无损压缩算法进行进一步压缩。应用程序开发者可提供哈夫曼表,不过一般都使用默认的表(将NULL选入TW_JPEGCOMPRESSION.HuffmanDC[]和TW_JPEGCOMPRESSION.HuffmanAC[])。
此算法选择支持使用重启标记代码,以允许随机读取JPEG数据流进行解压。更多描述请参考JPEG规范。
4.6 可选用户界面
是否使用源管理器提供的源选择对话框是可选的。
TWAIN包装了源管理器代码以作为应用程序和源的通信中介。源管理器提供的服务之一是找出匹配用户要求的可用源并将它们显示给用户进行选择。
我们推荐应用程序使用此接口,但没有强制要求,存在两种可选的替代方式:
1. 程序可开发并显示自定义的选择界面,这在响应用户从菜单中选择“Select Source...”时显示。
2. 如果程序专注于控制某个特定源,程序可直接选择此源。在这种情况下,从功能上说程序并不需要菜单项“Select Source..”,不过为保持与其它TWAIN兼容程序的一致性,应显示一个灰色的不可用菜单项。
显示自定义选择界面:
1. 使用DG_CONTROL / DAT_IDENTITY / MSG_GETFIRST操作使源管理器查找第一个可用源。源的名称包含在TW_IDENTITY.ProductName域中。保存此TW_IDENTITY结构。
2. 使用DG_CONTROL / DAT_IDENTITY / MSG_GETNEXT操作使源管理器获取下一个,重复此操作直到它返回一个表示没有其它可用源的TWRC_ENDOFLIST。同样应保存此TW_IDENTITY结构。
3. 将ProductName信息展示给用户进行选择。作出选择后,使用相关的TW_IDENTITY结构和DG_CONTROL / DAT_IDENTITY / MSG_OPENDS操作来使源管理器打开指定的源。
注:使用这种方式时,与MSG_USERSELECT 操作相对地,源管理器不会更新系统默认源信息以反映用户的选择。
直接选择源:
若程序想打开系统默认源,可使用DG_CONTROL / DAT_IDENTITY / MSG_GETDEFAULT操作来使源管理器查找默认源并用其信息填充TW_IDENTITY。
另外,如果想要使用的源不是默认源但知道其名称,可以使用DG_CONTROL / DAT_IDENTITY / MSG_GETFIRST和G_CONTROL / DAT_IDENTITY / MSG_GETNEXT操作来遍历所有源直至找到与指定名称匹配的源,然后使用相应的TW_IDENTITY结构来打开源。
注:使用这种方式时,源管理器同样不会更新系统默认源信息以反映用户的选择。
4.6.1 可选源用户界面
与源管理器的源选择对话框一样,程序可能要求不使用源的用户界面。例如某些文本识别插件只希望协商少数性能(如像素类型、分辨率、页面尺寸等)然后就直接获取和传输数据。
为了在不显示用户界面的情况下启用源:
• 使用 DG_CONTROL / DAT_USERINTERFACE / MSG_ENABLEDS。
• 将TW_USERINTERFACE.ShowUI域设置为FALSE。
• 收到并接受命令后,源将不显示用户界面但将开始采集数据。例如对于平板扫描仪,光标光将发光并开始移动;对于手持式扫描仪,将准备在“GO”按钮被按下时开始采集数据。其它设备可能有不同的响应,但都将立即开始采集或准备在用户触发后立即采集数据。
不显示源用户界面时性能协商非常重要:
• 因为源用户界面不显示,源无法向用户提供选择要采集信息的机会等。除非默认值是可接受的,否则所有有关图像采集的当前值和控制参数都必须在源启用前协商好(状态4)。
若TW_USERINTERFACE.ShowUI 被设置为FALSE:
• 源启用时,程序仍然要将所有事件传递给源(通过DG_CONTROL / DAT_EVENT / MSG_PROCESSEVENT)。
• 源应显示仅包含使设备在上下文中可用所必须的控制项的尽可能小的用户界面。通常这意味着不显示用户界面,但有些设备还是要求一个触发器来启动扫描。
• 在采集过程中源仍然显示进度条、错误和其它一些与设备操作有关消息。若源指定CAP_UICONTROLLABLE为TRUE,则程序可通过设置CAP_INDICATORS为FALSE来禁用它。
• 数据准备好被传输时,源仍然将向程序发送MSG_XFERREADY通知。
• 由于通常由用户触发,源也许会,也许不会向程序发送MSG_CLOSEDSREQ消息以要求关闭。因此,在源回到状态5后(紧随DG_CONTROL / DAT_PENDINGXFERS / MSG_ENDXFER操作并且TW_PENDINGXFERS.Count为0),程序可发送DG_CONTROL / DAT_USERINTERFACE / MSG_DISABLEDS操作。
总结:在ShowUI被设为FALSE后,一些源仍可能显示UI。程序可通过CAP_UICONTROLLABLE性能来查询ShowUI能否被设置。如果CAP_UICONTROLLABLE 为FALSE而 ShowUI也被设为FALSE,则启用源的操作将返回TWRC_CHECKSTATUS,但会显示UI。因此,想要禁用UI的程序应先查询CAP_UICONTROLLABLE。
4.6.2 模态和非模态用户界面
源管理器的用户界面是是模态的,但源可能提供模态或非模态的界面,下面是两者间的差别:
非模态:
当源使用非模态界面时,虽然源界面是显示的,但用户仍然可以通过单击程序窗口并激活它以操作程序。
用户被期望在想停止显示源用户界面时单击其关闭按钮。程序不应在任何传输动作后自动关闭一个非模态源,即使程序只想要单次传输。如果程序在用户请求前关闭了源,则用户很可能会迷惑于窗体为什么消失了。请等到用户表示希望关闭后再关闭源的界面,并在程序关闭源之前等待源发送MSG_CLOSEDSREQ请求。
模态:
使用模态用户界面的源不允许用户操作其它窗口。对Windows来说,如果界面是程序模态,则用户不能操作其它应用程序但仍然可能操作系统程序。如果界面是系统模态(这很少见),则用户无法在应用程序和系统级操作任何东西。系统模态对话框可能被用于显示高级错误消息,例如UAE。
若使用模态界面,则在一次会话期间源只能进行一次采集,不过每次采集可能包含多个框架。数据传输完毕后源将向程序发送关闭请求,相对地,源等待该请求。
源将在程序通过DG_CONTROL / DAT_USERINTERFACE / MSG_ENABLEDS启用它之后表明它将使用模态或非模态界面。此操作中使用的TW_USERINTERFACE结构包含一个ShowUI域,由程序设置用于声明源是否应显示用户界面。如果程序要求显示用户界面,则它也将通过此域来声明希望源采用模态(TRUE)还是非模态(FALSE)界面。
若源有请求,则可通过DG_CONTROL / DAT_USERINTERFACE / MSG_DISABLEDS 操作来去掉源用户界面。
4.7 灰度和图像信息
TWAIN中有一些操作元组允许应用程序开发者交流和影响图像(从源传输到程序)的灰度和颜色外观等信息。以下操作提供了此能力:
• CIE Color Descriptors
DG_IMAGE / DAT_CIECOLOR / MSG_GET
• Grayscale Changes
DG_IMAGE / DAT_GRAYRESPONSE / MSG_RESET
DG_IMAGE / DAT_GRAYRESPONSE / MSG_SET
• Palette Color Data
DG_IMAGE / DAT_PALETTE8 / MSG_GET
DG_IMAGE / DAT_PALETTE8 / MSG_GETDEFAUL
DG_IMAGE / DAT_PALETTE8 / MSG_RESET
DG_IMAGE / DAT_PALETTE8 / MSG_SET
• RGB Response Curve Data
DG_IMAGE / DAT_RGBRESPONSE / MSG_RESET
DG_IMAGE / DAT_RGBRESPONSE / MSG_RESET
4.7.1 CIE Color Descriptors(颜色描述子)
CIE XYZ是一种能够简化对数据的数学操作的颜色存储方式。(附录A讨论有关XYZ颜色空间和话题)。
若程序希望以此格式接收图像数据:
1. 确保源支持CIE XYZ格式。可通过对性能 ICAP_PIXELTYPE的DG_CONTROL / DAT_CAPABILITY / MSG_GET操作来检查。若支持则返回的支持类型中将包含TWPT_CIEXYZ。
2. 通过对性能 ICAP_PIXELTYPE的DG_CONTROL / DAT_CAPABILITY / MSG_SET操作来指定应使用CIE XYZ格式来传输数据,操作使用一个值为TWPT_CIEXYZ的TW_ONEVALUE容器。
为确定源将颜色数据转换为CIE XYZ格式时所使用的参数,请在图像传输后使用 DG_IMAGE / DAT_CIECOLOR / MSG_GET 操作。
4.7.2 灰度转换
(假定程序已经通过将ICAP_PIXELTYPE设置为TWPT_GRAY来通知源提供灰度数据并且源已接受)
程序可要求源在将数据传输至程序前对灰度数据进行曲线变换,相关操作为 DG_IMAGE / DAT_GRAYRESPONSE / MSG_SET,变换曲线信息由程序通过一个TW_GRAYRESPONSE结构指定。程序务必检查此请求的返回值,若返回TWRC_FAILURE并且状态码为TWCC_BADPROTOCOL,则表示程序不支持灰度的响应转换(与支持灰度数据无关)。
如果源允许程序设置灰度转换,则应有重置转换的途径。因此,源应有一种直接传输而不转换任何灰度数据的“恒等转换”。程序可通过DG_IMAGE / DAT_GRAYRESPONSE / MSG_RESET请求来重置转换。
4.7.3 调色板颜色数据
(假定程序已经通知源将ICAP_PIXELTYPE置为TWPT_PALETTE且源已接受)
DAT_PALETTE8操作允许程序请求源对调色板颜色数据的支持并启动调色板颜色的传输。此操作限定为8位数据,不论是灰度还是采色(8位或24位)。MSG_GET操作允许程序了解源在采集数据时使用的调色板。程序应总是在立即在图像传输后而不是之前执行此操作,因为源可能在采集过程中优化调色板。某些源可能允许程序通过MSG_SET来定义图像采集使用调色板。务必检查返回值以核实操作返回了TRRC_SUCCESS,这是确定你要求的调色板是否会真实的用于随后的调色板传输的唯一方法。
4.7.4 RGB响应曲线数据
(假定程序已经通过将ICAP_PIXELTYPE设置为TWPT_RGB来通知源提供RGB数据并且源已接受)
程序可要求源在将数据传输至程序前对数据作曲线变换,相关操作为DG_IMAGE / DAT_RGBRESPONSE / MSG_SET。变换曲线信息由程序通过一个TW_RGBRESPONSE结构指定。程序务必检查此请求的返回值,若返回TWRC_FAILURE并且状态码为TWCC_BADPROTOCOL,则表示程序不支持RGB的响应转换(与支持RGB数据无关)。
如果源允许程序设置RGB响应转换,则应有重置转换的途径。源应有一种直接传输而不转换任何RGB数据的“恒等转换”。程序可通过DG_IMAGE / DAT_RGBRESPONSE / MSG_RESET请求来重置转换。
4.8 对比度、亮度和阴影
一个难以明确的问题是什么才是最合适的表达一个特定设备的这些真实特性的方式。所有尝试支持这些性能的人都清楚推荐的范围并没有真实的反映现实世界中的设备。数据源开发者已经尝试了许多种不同的方法来获取正确的响应,不是所有的能够一致。
通过提供一个有意义的步进值或提供不同的容器,数据源可向程序提供足够的信息以准确地为设备的真实能力建模。对于一个希望展示关于这类性能的自定义用户界面的程序来说,提供从-1000到1000的2000个等级并没有太多作用,尤其是当设备实际上仅支持少数几个等级的时候。
由于数据源开发者和应用程序开发者都阅读相同的规范,因此可以想象为此类性能提供一个与指定范围不匹配的值是不会被接受的。
以下建议是一个如何遵循此规范的一个例子,它们为指定的数据源指定最准确的值。
例1: ICAP_BRIGHTNESS仅支持三个等级
第10章中声明的规范要求如下:
“源应将值校正到范围内,确保'0'是当前值的一个可用值。如果源的正负范围相对于0不对称,将范围数量设为正负1000并从0值在两个方向上进行等比分割。这将产生一个步进值不同的正范围与负范围。”
注:从这段关于正负范围步进值不一致的描述延伸一下,应使用 TW_ENUMERATION容器。 TW_RANGE无法表达非线性的步进值。
假设真实设备只支持普通、浅、深三种选项,则可以通过将真实值映射到请求值来适应此约束:
Normal = 0
Lighten = -1000
Darken = 1000
这些值可以放置在一个步进值为1000的TW_RANGE容器中,也可以放置在一个包含{-1000,0,1000}、当前值和默认值为0的TW_ENUMERATION容器中。