FAQ

Technical Support

If you have a question or technical issue that isn’t answered on this page, ask the entire TWAIN community at twain@twain.org.

(Note: In order to mail to this list, you must be subscribed to the list.  To subscribe, send an email to: join-twain@twain.org. To unsubscribe, send an email to: remove-twain@twain.org.)

 

FAQ

The following questions are the result of sorting through questions posted on the TWAIN Developers mailing list and discussions with TWAIN Working Group members. The intention is to clear-up any implementation issues before the TWAIN Working Group imposes TWAIN Compliance guidelines.

 

Question: What is TWAIN an acronym for?

Answer: An image capture API for Microsoft Windows and Apple Macintosh operating systems. The standard was first released in 1992, and is currently ratified at version 1.9 as of January 2000. TWAIN is typically used as an interface between image processing software and a scanner or digital camera.

The word TWAIN is from Kipling's "The Ballad of East and West" - "...and never the twain shall meet...", reflecting the difficulty, at the time, of connecting scanners and personal computers. It was up-cased to TWAIN to make it more distinctive. This led people to believe it was an acronym, and then to a contest to come up with an expansion. None were selected, but the entry "Technology Without An Interesting Name" continues to haunt the standard. "

(Borrowed with permission from The Free On-Line Dictionary of Computing).

 

Question: Where do I get updated scanner drivers for Windows 95/NT?

Answer: You need to contact your scanner vendor. The TWAIN working group doesn't maintain any scanner drivers. I have found a web site that provides drivers for a number of scanners vendors. TWG doesn't guarantee any responsibility for the content at the site. Scanner drivers.

 

Question: Is there a royality/license fee to implement TWAIN?

Answer: TWAIN is free to use in your application or source. The TWG asks that you make your application TWAIN compliant. Compliance requirements are covered in the TWAIN Specification.

 

Question: Who dictates container type during MSG_GET/MSG_GETCURRENT/MSG_GETDEFAULT?

Answer: Container types are dictated by the Data Source in all cases where a value is queried.

 

Question: What containers are allowed for each capability?

Answer: The allowable container types of each capability are clearly defined in Chapter 9 of the TWAIN Specification.

 

Question: Can the application ever specify a container type?

Answer: The only time it is appropriate for the calling Application to specify a container type is during the MSG_SET operation. At that time, the Application must also consider the allowable containers and types for the particular capability.

 

Question: What are TWAIN Types hold Strings?

Answer: There are 4 types of TWAIN strings defined for developer use:

TW_STR32

TW_STR64

TW_STR128

TW_STR256

 

Question: What types of TWAIN Containers can hold Strings?

Answer: The only containers that can possibly hold a string are the following:

TW_ENUMERATION

TW_ARRAY

TW_ONEVALUE

It is not possible or useful to use this type in a TW_RANGE, in fact there is no case where a capability has been defined in Chapter 9 of the TWAIN Specification where a TW_RANGE is allowed for a TW_STRXXX type of value.

 

Question: What TWAIN Capabilities use String Values?

Answer: As of version 1.7, only the following capabilities accept strings:

CAP_AUTHOR, TW_ONEVALUE, TW_STR128

CAP_CAPTION, TW_ONEVALUE, TW_STR255

CAP_TIMEDATE, TW_ONEVALUE, TW_STR32

ICAP_HALFTONES, TW_ONEVALUE/TW_ENUMERATION/TW_ARRAY, TW_STR32

 

Question: What would a TW_ONEVALUE holding a string look like?

Answer: If you were to redefine the TW_ONEVALUE container to hold a string, it would look like this structurally.

/* TWON_ONEVALUESTR32. Container for one value holding TW_STR32. */
typedef struct {
    TW_UINT16 ItemType;
    TW_STR32 Item;
} TW_ONEVALUESTR32, FAR * pTW_ONEVALUESTR32;

(Note: pay attention to 2 byte structure packing when defining custom container structures)

 

Question: How would I allocate a container with strings without redefining the structure?

Answer: The following function demonstrates how you would allocate and fill a string container using the TWAIN Structures already defined by TWAIN.

HGLOBAL AllocateAndFillOneValueStr32( const pTW_STR32 pInString )
{
                DWORD dwContainerSize = 0l;
                HGLOBAL hContainer = NULL;
                pTW_ONEVALUE pOneValue = NULL;
                pTW_STR32 pString = NULL;

                assert(pInString);

                // note: this calculation will yield a size approximately one pointer

               // larger than that required for this container (sizeof(TW_UINT32)). For

               // simplicity the size difference is negligible. The first TW_STR32 item shall

                // be located immediately after the pEnum->DefaultIndex member.

                dwContainerSize = sizeof(TW_ONEVALUE) + sizeof(TW_STR32);
                hContainer = GlobalAlloc( GPTR, dwContainerSize );
                if(hContainer)
                {
                                pOneValue = (pTW_ONEVALUE)GlobalLock(hContainer);
                                if(pOneValue)
                                {
                                                pOneValue->ItemType = TWTY_STR32;
                                                pString = (pTW_STR32)&pOneValue->Item;

                                                memcpy(pString, pInString, sizeof(TW_STR32));

                                                GlobalUnlock(hContainer);
                                                pOneValue = NULL;
                                                pString = NULL;
                                }
                }
                return hContainer;
}

 

Question: How could I put strings in a TW_ENUMERATION Container?

Answer: The following example demonstrates the creation of an enumeration to hold a certain number of TW_STR32 type strings.

HGLOBAL AllocateEnumerationStr32( TW_UINT32 unNumItems )
{
                DWORD dwContainerSize = 0l;
                HGLOBAL hContainer = NULL;
                pTW_ENUMERATION pEnum = NULL;

                // note: this calculation will yield a size approximately one pointer
                // larger than that required for this container (sizeof(pTW_UINT8)). For
                // simplicity the size difference is negligible. The first TW_STR32 item shall
                // be located immediately after the pEnum->DefaultIndex member.
                dwContainerSize = sizeof(TW_ENUMERATION) + ( sizeof(TW_STR32) * unNumItems);

                hContainer = GlobalAlloc( GPTR, dwContainerSize );
                if(hContainer)
                {
                                pEnum = (pTW_ENUMERATION) GlobalLock(hContainer);
                                if(pEnum)
                                {
                                                pEnum->ItemType = TWTY_STR32;
                                                pEnum->NumItems = unNumItems;

                                                GlobalUnlock(hContainer);
                                                pEnum = NULL;
                                }
                 }
                return hContainer;
}

 

Question: How do I index strings found in an TW_ENUMERATION?

Answer: The following function demonstrates the indexing of a string found in an enumeration container.

pTW_STR128 IndexStr128FromEnumeration( pTW_ENUMERATION pEnum, TW_UINT32 unIndex)
{
                BYTE *pBegin = (BYTE *)&pEnum->ItemList[0];
                assert(pEnum->NumItems > unIndex);
                assert(pEnum->ItemType == TWTY_STR128);

                pBegin += (unIndex * sizeof(TW_STR128));
                return (pTW_STR128)pBegin;
}

 

Question: How do I deal with "Current" and "Default" and "Preferred" Capability Values?

Answer: Often it is assumed that the "Current" and "Default" capabilities are going to be the same when a Data Source is opened. This assumption is not correct. This assumption would make it impossible for a Data Source to store and restore settings between sessions as a convenience for the user.

A better way to look at it, would be that "Default" Capability values indicate what value will be used if you issue a MSG_RESET operation.

The "Current" value may be set to a "Preferred" or to a previously stored value.

 

Question: How can I store Scan Parameters are in one session and restore them in another?

Answer:

1. User configures the Data Source User Interface with the following Parameters: 4x6 inch image in 24bit at 200 DPI X and Y Resolution

2. User selects "Scan" and Data Source Signals Application to transfer

3. Application Acquires the image successfully

4. Application Disables the Data Source

5. Application inquires during State 4 the Current values of Frame, Pixel Type, Bit Depth, and Resolution

6. Data Source reports to each inquiry the current values that were set by the user: 4x6 inch image in 24bit at 200 DPI X and Y resolution

7. Application Closes the Data Source

8. During Close procedure, the Data Source stores the current Frame, Pixel Type, Bit Depth and Resolution

9. Application Opens Data Source

10. During Open procedure, the Data Source restores current Frame, Pixel Type, Bit Depth and Resolution

11. Application inquires during State 4 the Current values of Frame, Pixel Type, Bit Depth, and Resolution

12. Data Source reports to each inquiry the current values that were restored from previous session: 4x6 inch image in 24bit at 200 DPI X and Y resolution in one session

 

Question: How can the Data Source represent the preferred Pixel Flavor without compromising TWAIN Defined Default value?

Answer:

1. Application opens Data Source for the first time

2. Application inquires during State 4 about the Default Pixel Flavor

3. Data Source reports that the Default Pixel Flavor is TWPF_CHOCOLATE (spec chapter 9)

4. tabApplication inquires during State 4 about the Current Pixel Flavor

5. tabData Source reports that the Current Pixel Flavor is TWPF_VANILLA (because this device returns data in that gender natively)

6. tabApplication issues Reset to Current Pixel Flavor

7. tabDuring reset operation, Data Source changes current value to TWPF_CHOCOLATE and prepares to invert data during transfer to accommodate the calling Application request

 

Question: Does this work in all conditions?

Answer: No. If a capability is constrained and the "Default" value is not in the constrained list, and the Data Source is supposed to respond to MSG_GET with a TW_ENUMERATION, then it cannot possibly report a valid Default Index. In this case it is safer for the Data Source to provide some valid index. When MSG_RESET is issued, the constraints will be lifted and the Default Index can once again be reported correctly.

 

Question: How does a Data Source respond to MSG_RESET?

Answer: It is known that this call resets the current value of the requested Capability to the default. It must also be stated that this call will also reset any Application imposed constraints upon the requested Capability.

 

Question: How does a Data Source respond to MSG_GETCURRENT, and MSG_GETDEFAULT?

Answer: It is intuitive to assume that this message should not be supported by Capabilities that have no Current or Default value. However the spec says otherwise in chapter 9 (a good example is ICAP_SUPPORTEDCAPS). In this case, it makes sense to simply respond to these messages in the same manner as MSG_GET.

It can also be assumed, that it is more intuitive for a Data Source to respond to this capability with a TW_ONEVALUE container in all cases that a TW_ONEVALUE container is allowed.

 

Question: How does a Data Source respond to a MSG_GET?

Answer: If an Application has constrained the current capability, then the Data Source response to this message should reflect those constraints. Otherwise, this should respond with all the values that the Data Source supports. Of course, the number of values that can be placed in the response are restricted by the allowed containers for the particular current capability outlined in chapter 9.

 

Question: Why does my application deadlock with some Data Sources?

Answer: It is possible that during execution of any triplet that the Data Source will fail unexpectedly. It is very important that Applications pay attention to the TWAIN State of the Data Source at the time of failure. A hanging or deadlock condition will occur if the Application fails to recover from error conditions with the proper state transitions. Most error handling is fairly obvious, however the following items have been mishandled in the past.

 

Question: How do I know if transition to State 5 has really happened?

Answer: A Data Source may fail a call to DG_CONTROL / DAT_USERINTERFACE / MSG_ENABLEDS unexpectedly. It is important to note that if an Application requests the User Interface be suppressed, and the Data Source returns a code of TWRC_CHECKSTATUS, this means only that User Interface suppression was not possible. The transition to State 5 still occurred. If the Application does not like this condition, then it may call MSG_DISABLEDS to close the Data Source without further user interaction. A return code of TWRC_FAILURE indicates that the transition to State 5 has not occurred.

 

Question: If there’s an error during image transfer, how do I get back to State 5?

Answer: It is important to be aware that when an error occurs during image transfer, a state transition to State 5 is not implicit. A call to DG_CONTROL / DAT_PENDINGXFERS / MSG_RESET or MSG_ENDXFER is required for a state transition back to State 5. If an Application calls MSG_DISABLEDS immediately after such a failure without first making the required calls to DAT_PENDINGXFERS, the resulting behavior of the Data Source will not be predictable. The Data Source should fail any call to MSG_DISABLEDS outside of State 5.

 

Question: How do I resolve conflict between changing ICAP_FRAMES, ICAP_SUPPORTEDSIZES, DAT_IMAGELAYOUT?

Answer: Since there are several ways to negotiate the scan area, it becomes confusing when deciding what should take precedence. It is logical to assume that the last method used to set the frame will dictate the current frame. However, it may still be confusing to decide how that is represented during a MSG_GET operation for any of the three methods. The following behavior is suggested.

Note: Frame Extents are only limited by ICAP_PHYSICALWIDTH and ICAP_PHYSICALHEIGHT. Setting ICAP_SUPPORTEDSIZES does NOT imply a new extent limitation. TWSS_XXXX sizes are simply predefined fixed Frame sizes.

  • If the frame is set in DAT_IMAGELAYOUT

- ICAP_FRAMES shall respond to MSG_GETCURRENT with the dimensions of the frame set in the DAT_IMAGELAYOUT call.

- ICAP_SUPPORTEDSIZES shall respond to MSG_GETCURRENT with TWSS_NONE

  • If the current frame is set from ICAP_FRAMES

- DAT_IMAGELAYOUT shall respond with the dimensions of the current frame set in ICAP_FRAMES

- ICAP_SUPPORTEDSIZES shall respond to MSG_GETCURRENT with TWSS_NONE

  • If the current fixed frame is set from ICAP_SUPPORTEDSIZES

- DAT_IMAGELAYOUT shall respond to MSG_GET with the dimensions of the fixed frame specified in ICAP_SUPPORTEDSIZES

- ICAP_FRAMES shall respond to MSG_GETCURRENT with the dimensions of the fixed frame specified in ICAP_SUPPORTEDSIZES

 

Question: What effect does ICAP_ROTATION, ICAP_ORIENTATION have on ICAP_FRAMES, DAT_IMAGELAYOUT, DAT_IMAGEINFO?

Answer: There is considerable confusion when trying to resolve the affect of Rotation and Orientation on the current Frames and Image Layout. After careful consideration of the specification it has been concluded that ICAP_ROTATION and ICAP_ORIENTATION shall be applied after considering ICAP_FRAMES and DAT_IMAGELAYOUT.

Obviously a change in orientation will have an effect on the output image dimensions, so these must be reflected in DAT_IMAGEINFO during state 6. The resulting image dimensions shall be reported by the Data Source after considering the affect of the rotation on the current frame.

For the sake of simplicity, the use of ICAP_ROTATION and ICAP_ORIENTATION should be mutually exclusive. However, it is really up to the Application to try and use one or the other. If an Application attempts to set both, then the reaction of the Data Source would be unpredictable. It may prioritize these items, or it might try to compound them.

 

Question: What are the actual allowed values for ICAP_CONTRAST, ICAP_BRIGHTNESS, and ICAP_SHADOW?

Answer: There is considerable confusion about what is the appropriate way to present these actual features for a particular device. Anyone that has attempted to support these capabilities knows that the recommended ranges do not accurately reflect the capabilities of real world devices. Data Source developers have tried many different methods of getting the correct response for their Data Source, and not all are consistent.

By providing a meaningful step size, or by providing a different container, a Data Source can provide the Application with enough information to accurately model the actual ability of the device. For an Application that wishes to present a custom User Interface for this type of capability, it is not really useful to the user if it provides 2000 steps from -1000 to +1000, especially if the device really only supports a small number of levels.

Since both Data Source Developers and Application Developers read the same specification, it can be assumed that it is not acceptable to provide values that do not fit within the documented ranges for these types of capabilities.

The following suggestion is an example of how to follow the spec, and provide the most accurate values for the particular Data Source.

 

Question: My scanner only supports 3 levels of brightness. How do I implement ICAP_BRIGHTNESS?

Answer: Specification requirement stated in Chapter 9:

"Source should normalize the values into the range. Make sure that a ‘0' value is available as the Current Value when the Source starts up. If the Source’s ± range is asymmetric about the ‘0’ value, set range maxima to ±1000 and scale homogeneously from the ‘0’ value in each direction. This will yield a positive range whose step size differs from the negative range’s step size."

(Note: it should be expanded in this statement that for a step size that differs in the negative and positive range, a TW_ENUMERATION container must be used. A TW_RANGE container is not suitable for representing a non-linear step size)

Actual device simply supports the options, normal, lighten, and darken.

These can fit into the constraints by mapping actual values to required values:

Normal = 0

lighten = -1000

darken = 1000

These values can be placed in a TW_RANGE container with a step size of 1000, or into a TW_ENUMERATION containing only the 3 values.

{ -1000, 0, 1000 }, the current and default values are 0.

 

Question: What do the TWAIN Defined Paper sizes refer to?

Answer: Please see the appropriate section in the TWAIN Specification.

 

Question: How do I handle ICAP_XRESOLUTION and ICAP_YRESOLUTION when ICAP_UNITS is set to TWUN_PIXELS?

Answer: In chapter 9 the TWAIN Specification states the following about the contents of ICAP_XRESOLUTION, and ICAP_YRESOLUTION:

"Measured in units of pixels per unit as defined by ICAP_UNITS (pixels per TWUN_PIXELS yields dimensionless data)."

The term "dimensionless" does nothing to indicate exactly how the Data Source shall respond in this condition. This behavior can be clarified by further stating that ICAP_XRESOLUTION shall report 1pixel/pixel when the units are TWUN_PIXELS. ICAP_YRESOLUTION shall report 1 pixel/pixel when the units are TWUN_PIXELS. Some Data Sources like to report the actual number of pixels that the device supports, but that response is more appropriate in ICAP_PHYSICALHEIGHT and ICAP_PHYSICALWIDTH.

 

Question: How does CAP_TIMEDATE know when and what to negotiate?

Answer: On page 9-14 of the TWAIN Specification the contents of CAP_TIMEDATE are described as follows:

"The date and time the image was acquired."

"The time and date when the image was originally acquired (when the Source entered State 7)"

The first problem with this definition is when to negotiate it. Since the Data Source can enter State 4 without ever having entered State 7, it should be stated that this capability must be negotiated during a State 7, before the call to the DG_CONTROL / DAT_PENDINGXFERS / MSG_ENDXFER triplet. (Note: That behavior requires the capability to be listed in the CAP_EXTENDEDCAPS capability by the Data Source.)

The strict definition in the TWAIN Specification, concerning the content of this capability, dedicates the use to tracking when an image was transferred from the Data Source to the Application. That is not really a useful value to provide, since the Application could generate that by itself with no assistance from the Data Source. In the current form, it also forbids the use of truly useful information that can be inquired from specialized scanners such as digital cameras. The expected content of this capability can be clarified with the following statement:

"CAP_TIMEDATE should return the closest available approximation of the time the physical phenomena represented by the image was recorded."

This statement opens the definition up to several possibilities, and makes it more ambiguous. In this case, ambiguity is good since specialized Data Sources can then provide truly useful information when it is available. Applications must also be aware of the specialized nature of this capability. If an Application truly wants the exact time of acquisition, it should generate that value itself during the image acquisition procedure.

 

Question: Will ICAP_PHYSICALWIDTH, and ICAP_PHYSICALHEIGHT change when the scanning area has changed?

Answer: Probably. On page 7-59 the specification states:

"Source: Reset all the fields of the structure pointed at by pImageLayout to the device’s power-on origin and extents. There is an implied resetting of ICAP_ORIENTATION, ICAP_PHYSICALWIDTH, and ICAP_PHYSICALHEIGHT to the device’s power-on default values."

This statement should be disregarded, since ICAP_PHYSICALHEIGHT and ICAP_PHYSICALWIDTH cannot be set or reset. These values are dependant on the maximum width and height that can possibly be set using the scanning area. These values are read only. It is reasonable to assume that these values will change when the scanning area has changed. Such a change could be triggered by enabling or disabling a document feeder.

 

Question: What happens when the Data Source has different ICAP_PHYSCALHEIGHT for Document Feeder and Flat Bed?

Answer: ·

  • Application negotiates CAP_FEEDERENABLED/MSG_GET, Data Source Response: FALSE
  • Application negotiates ICAP_PHYSICALHEIGHT, Data Source Response: 11 inches
  • Application negotiates CAP_FEEDERENABLED/MSG_SET, Value: TRUE, Data Source changes internal feeder enabled state to TRUE
  • Application negotiates ICAP_PHYSICALHEIGHT, Data Source Response: 14 inches

 

Question: I enable a Data Source and I cannot use TAB or Keyboard Shortcuts to Navigate TWAIN Dialog

Answer: The cause of this can be one of two things. Either the application is not forwarding all messages to TWAIN through the DAT_EVENT mechanism, or the Data Source is not properly processing the DAT_EVENT messages. (Windows: calling IsDialogMessage for each forwarded message with TWAIN Dialog handle)

 

Question: I enable the Data Source and the TWAIN Dialog Box Combo Boxes cannot be opened and Edit boxes produce multiple characters per keystroke?

Answer: his case is caused by processing TWAIN Dialog Messages twice. Either the Data Source has not returned the proper return code in response to DAT_EVENT calls (Windows: TWRC_DSEVENT when IsDialogMessage returns TRUE), or the Application is ignoring the return code.

 

Question: This is not a problem when Data Source operates through TWAIN Thunker?

Answer: Problems with the application handling of these messages are not often detected if the Data Source is operating through the TWAIN Thunking mechanism. This is because the Thunker process has a separate Window and Message pump that properly dispatch DAT_EVENT messages to the Data Source. Any mistake in application handling will pass without notice since all DAT_EVENT calls will return TWRC_NOTDSEVENT. (with the exception of important messages such as MSG_XFERREADY.)

 

Question: I do not think the problem is mine, it seems erratic, keyboard shortcuts and Tab key work for Message Boxes, but not TWAIN Dialog?

Answer: This is because Windows architecture is getting in the way. In Windows, a standard Message box is Modal, and operates from a local message pump until the user closes it. All messages are properly dispatched to the message box since it does not rely on the application message pump. The TWAIN Dialog is slightly different since it is implemented Modeless. There is no easy way to duplicate Modal behavior for the TWAIN Dialog.

 

Question: FloatToFix32 does not round negative numbers correctly.

Answer: The following changes are a possible fix to the problem:

/**********************************************************
* FloatToFix32
* Convert a floating point value into a FIX32
**********************************************************/

TW_FIX32 FloatToFix32( float floater )
{
                TW_FIX32 Fix32_value;
                TW_BOOL sign = (floater < 0)?TRUE:FALSE;
                TW_INT32 value = (TW_INT32) (floater * 65536.0 + (sign?(-0.5):0.5));
                Fix32_value.Whole = value >> 16;
                Fix32_value.Frac = value & 0x0000ffffL;
                return (Fix32_value);
}

 

Question: How can I get a copy of the EZTWAIN toolkit?

Answer: The EZTWAIN toolkit is available for download from the following location on the Web: http://www.dosadi.com/download.htm

 

Question: What certification program is available to certify my TWAIN implementation is compliant?

Answer: The TWAIN Working Group (TWG) has available Test Recommendations for Data Source implementers. Testing products and services are available from independent labs to test.

 


Home | What's New | About TWAIN | FAQ | Resources | Downloads | Contact Us | Mailing List | Site Map | Search

TWAIN license information and acknowledgements.
For questions or comments about TWAIN, contact the TWAIN Working Group
For comments about the site, contact the Webmaster

Page last updated: February 01, 2001