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.
|