|
Technical answers from the trenches |
|
TWAIN Support in ObjectPAL, Part 2: TWAIN Support Overview
| ||||
by Paul Cronk |
Posted: 1 July 2001 |
|||
  |
Applies to: Paradox 10 |
|||
  |
Audience: Developers |
|||
Note: This is Part 2 of 4. You can also:
TWAIN Support OverviewIn Paradox 9, interactive TWAIN support was added in SP1. This gave the ability to acquire images from scanners and cameras into tables and forms. However, it was not until Paradox 10 did the support become available to the developer. The TWAIN type in ObjectPAL gives the developer the ability to acquire images from scanners and cameras, and placing those images into files, graphic types, and tables. The TWAIN type also contains functions to enumerate through the list of data sources on the computer. With the addition of the TWAIN type developers can add the ability to acquire and manage scanned images. A TWAIN variable type is used to acquire images from TWAIN-compliant devices. Communication between Paradox (or more precisely the TWAIN variable) and the source manager is established by opening a session with the source manager. The source manager is installed when the first TWAIN-compliant device is installed onto the workstation. The latest version of the twain_32.dll, which contains the source manager, is placed into the operating system directory by the installation program of a TWAIN-complaint device. For Windows ME, and Windows 2000, Microsoft came out with WIATWAIN, an acronym for Windows Imaging Acquisition TWAIN. This means that all Windows ME and 2000 machines come with the source manager installed as part of the operating system. WIATWAIN is a windows driver and interface for data sources. Regardless of the operating system, Paradox still behaves the same way. TWAIN support is treated like a plug-in for Paradox. The file 'pxtwn32.dll' contains the interface that Paradox uses to communicate with the source manager. If this DLL is not present (or not plugged-in), then all the functionality related to TWAIN support is effectively disabled. Note that you cannot use the Paradox SP1 version of pxtwn32.dll in the absence of its existence in Paradox 10. The only similarity between the two files is the filename. The version shipped with Paradox 9 SP1 does not provide an interface to ObjectPAL. After a connection has been established with the source manager, the application can enumerate the available data sources, acquire images, get the default source for the machine, and set the data source for the session. Images acquired via a TWAIN variable can be transferred to three different formats. ObjectPAL can acquire to a file, a graphic type, or a graphic field that has been placed in edit-mode. There is also an option to display the user-interface for the data source before acquiring. Checking for TWAIN SupportTo check for TWAIN support, the application would typically call isTwainAvailable() on the startup of the application, and store the result for later reference. ;# FormData1::var var loTwain Logical endvar ;# FormData1::init method init(var eventInfo Event) loTwain = isTwainAvailable() endMethod Whenever the application is about to display user-interface items regarding acquisition, the variable loTwain is referenced. If this value returns FALSE, then the user-interface items are disabled, hidden, or removed. This allows applications to take advantage of workstations that have TWAIN-compliant devices attached and still function with those workstations with no TWAIN-compliant devices. Each developer/application will have their own methods of handling application settings. This example is not to point out the best method, but recommend to store the return value of isTwainAvailable() for later reference is a good idea. Opening a SessionAs stated previously, communication between the source manager and the TWAIN variable type is handled by a session. Typically, this is known as 'opening a TWAIN session'. The session is the only means to talk to the source manager. To establish a session, the function open() is called. While not efficient, this does provide another means to verify that TWAIN support is available. If the return code from open() is false, then the TWAIN session could not be established. Lastly, developers can code an isAssigned() call to determine if the session was established. Normally, conditional code would be wrapped around the open() call. Like most session style objects, the close() function will terminate the session. Like the TCursor object, when the variable goes out of scope, the variable is unassigned, and the session is terminated. A simple example is described below. ;# btnExample::pushbutton method pushbutton(var eventInfo Event) var twSes Twain endvar ;// open a session to the source manager, and report ;// an error if one is returned. if not twSes.open() then errorShow() return endif if not twSes.isAssigned() then ;// acquire, select source, etc. endif ;// close the session. twSes.close() endMethod Default SourcesThe term default source refers to the system-wide TWAIN-compliant data source that is used by default for acquiring images. The only supported way of changing the system default data source is through the Select Source dialog. If the source for a TWAIN session is not explicity set, the session inherits the system's default data source for the acquisition. The following example describes how to get the default source for the machine. This information is useful, if you are coding your Select Source dialog. When coding your own Select Source dialog, the application is responsible for saving, and retrieving the selected data source. The application is also responsible for ensuring the data source still exists on the system. ;# btnExample::pushbutton method pushbutton(var eventInfo Event) var twSes Twain strSource String endvar if not twSes.open() then errorShow() return endif strSource = twSes.getDefaultSource() msgInfo ( "Default Source", strSource ) twSes.close() endMethod Showing the Select Source DialogThe Select Source dialog is used to select a data source to acquire from. The data source that is selected from the Select Source dialog becomes the default data source for the machine. ;# btnExample::pushbutton method pushbutton(var eventInfo Event) var twSes Twain strOldSource String strNewSource String endvar if not twSes.open() then errorShow() return endif strOldSource = twSes.getDefaultSource() twSes.ShowSelectSourceDlg() strNewSource = twSes.getDefaultSource() if strOldSource = strNewSource then msgInfo ( "Twain", "The data source has not changed." ) else msgInfo ( "Twain", "The data source has changed" ) endif twSes.close() endMethod Enumerating Data SourcesA TWAIN session can enumerate all the data sources on a machine. This is as simple as opening a TWAIN session and calling enumSourceNames(). This information returns the source names of the data sources located on the machine. The index of each data source is stored in the key of the returned dynArray entry. The index should only be used as a means to retrieve the data source name, and should not be stored for later use. ;# btnExample::pushbutton method pushbutton(var eventInfo Event) var twSes Twain strOldSource String dynSourceNames DynArray[] String endvar if not twSes.open() then errorShow() return endif twSes.enumSourceNames( dynSourceNames ) dynSourceNames.view() twSes.close() endMethod Setting the source for a sessionTo set a data source for the TWAIN session, the caller would use setSource(). If the source is not found in the source list, then the setSource() returns FALSE. The following example will select the first source name in the source name list. ;# BtnExample::pushbutton Method pushbutton(var eventInfo Event) var twSes Twain strOldSource String dynSourceNames DynArray[] String endvar if not twSes.open() then errorShow() return endif twSes.enumSourceNames ( dynSourceNames ) ;// if there was at least one source name, then set it. if dynSourceNames.size() >= 1 then twSes.setSource ( dynSourceNames[ 1 ] ) else msgInfo ( "Twain", "There are no sources available." ) endif twSes.close() ;// ... endMethod Getting the source for the sessionThe source for the current session can be set by calling setSource(). Likewise, to retrieve the selected source use getSource(). The difference between getSource(), and getDefaultSource(), is that in the latter we are retrieving the default source for the system, and getSource() retrieves the source for the session. In the event that the source has explicitly been set by the developer, calling getSource() without setting the session source will return the same result as getDefaultSource(). For this example, we'll assume we always want to acquire from the camera, regardless of what they have selected.
;# BtnExample::pushbutton
Method pushbutton(var eventInfo Event)
var
twSes Twain
strSourceName String
dynSourceNames DynArray[] String
endvar
if not twSes.open() then
errorShow()
return
endif
strSourceName = twSes.getSource()
if strSourceName <> "QV QuickCam 2.33 32bit" then
if not twSes.setSource ( "QV QuickCam 2.33 32bit" ) then
msgInfo ( "Twain", "The camera isn't installed." )
return
endif
endif
twSes.close()
endMethod
Getting the number of sourcesEarlier, an example set the source based on results from the enumSourceNames() method of the Twain type. The code relies on the size() function of the DynArray type to return the number of sources available in the array. By using getSourceCount(), the number of TWAIN-compliant data sources is retrieved. Since at least one TWAIN-compliant device is required for TWAIN support to be available, this function should never return 0. Thus, we can safeguard our code by getting the source code after opening the TWAIN session. The example below clearly illustrates how we can produce more efficient code: ;# BtnExample::pushbutton Method pushbutton(var eventInfo Event) var twSes Twain strOldSource String dynSourceNames DynArray[] String endvar if not twSes.open() then errorShow() return endif if twSes.getSourceCount() = 0 then errorShow() return endif twSes.enumSourceNames ( dynSourceNames ) twSes.setSource ( dynSourceNames[ 1 ] ) twSes.close() endMethod Acquiring ImagesWith the Twain type, developers can acquire images into three different formats. For each format, the user-interface can be shown or not shown. Paradox does not support multiple image handling. Certain cameras can buffer images in the camera memory, and send them in succession. Paradox does not support ADF (automatic document feeders), such as scanners. The reason is quite simple. It makes little sense to scan 40 images into the same graphic field in a table. A graphic type can only hold one graphic, and a file can only have one filename. Paradox does not support 32bit images well, regardless if they are scanned in, or imported from files. With other topics such as graphics handling, 24bit scanned images can be saved to disk in .gif, .jpg formats to keep the file size down. Paradox 10 SP1 does not support acquiring to the graphic object type. An error stating that an unassigned variable was referenced that resulted from attempting to acquire to the graphic object. In fact, upon further investigation, it appears that it is calling the 'acquire to file' TWAIN function. Acquiring to a file To acquire to a file, only the filename is required. Like other ObjectPAL functions, if the filename is not preceded with an absolute path, the working directory is assumed. ;# BtnExample::pushbutton Method pushbutton(var eventInfo Event) var twSes Twain strFileName String endvar if not twSes.open() then errorShow() return endif strFileName = "acquired.bmp" ;// acquire to the filename, acquired.bmp. ;// show the user interface. if not twSes.acquire ( strFileName, true ) then errorShow() endif twSes.close() endMethod Acquiring to a graphic object Acquiring to a graphic object is straight-forward. The first parameter of the acquire() method is the uiObject that refers to the graphic object. The graphic object can be in run or design mode. ;# BtnExample::pushbutton Method pushbutton(var eventInfo Event) var twSes Twain uiGraphic UIObject endvar if not twSes.open() then errorShow() return endif ;// acquire to the field, fldGraphic. ;// show the user interface. uiGraphic = fldGraphic if not twSes.acquire (uiGraphic, true ) then errorShow() endif twSes.close() endMethod Acquiring to a graphic field object Acquiring to a graphic field is a little more complex than a graphic object. The form must be in edit mode. The uiObject refers to the graphic field. If these two conditions are not met, then the acquire method will log an error to the error stack. ;# BtnExample::pushbutton Method pushbutton(var eventInfo Event) var twSes Twain uiGraphic UIObject endvar if not twSes.open() then errorShow() return endif ;// place the form in edit mode. ;// acquire to the graphic field object, fldGraphic. ;// show the user interface. fldGraphic.edit() uiGraphic = fldGraphic if not twSes.acquire (uiGraphic, true ) then errorShow() endif twSes.close() ;// end Edit mode which will post the record. fldGraphic.endEdit() endMethod Acquiring to a graphic type This example does not work in Paradox 10 SP1. Acquiring to a graphic type returns an error stating usage of an unassigned variable. However, for completeness, the example, plus an explanation is listed here. Its intended functionality is the ability to acquire an image from a data source and place the image into the graphic object. Then the graphic object can be written to disk, stored into a table, or displayed on screen.;# BtnExample::pushbutton Method pushbutton(var eventInfo Event) var twSes Twain gAcquired Graphic uiGraphic UIObject endvar if not twSes.open() then errorShow() return endif ;// acquire to the graphic type, fldGraphic. ;// show the user interface. if not twSes.acquire (gAcquired, true ) then errorShow() endif qAcquired.writeToFile ( "c:\\temp\\acquired.bmp" ) twSes.close() endMethod Next Part: Part 3: Function Reference Previous: Part 1: Definitions, Requirements, and Introduction |
|||
|
||||||||
|
Copyright © 2000-2004, techtricks.com; All Rights Reserved. Acknowledgements, Disclaimers, Terms and Conditions. |
||||||||
|
Article last updated on 05 June 2003
|
||
|
|
||
|
[- End -]
|