Newsletter sign-up
View all newsletters

Enterprise Java Newsletter
Stay up to date on the latest tutorials and Java community news posted on JavaWorld

Sponsored Links

Optimize with a SATA RAID Storage Solution
Range of capacities as low as $1250 per TB. Ideal if you currently rely on servers/disks/JBODs

Bridge the gap between Java and Twain

Integrate imaging devices in Java using Twain and JNI

  • Print
  • Feedback

Page 3 of 6

Classic EZTwain 1.x DLL

Now that we can decode the native image from Twain to a supported Java format like JPEG, wrapping the Twain C API becomes a priority. At first, I started to write my own Twain wrapper library. After several failures and a bruised ego, I searched for an alternative. I strained my brain until I found the EZTwain DLL library. Dosadi has given away their 1.x version to the Twain community at large. After some minor modifications, we can use the EZTwain DLL with our JNI headers. Because the DLL as-is hangs during the Twain calls, source code changes were required.

Specifically I modified the TWAIN_UnloadSourceManager() method. I had to ensure all the pointers were set to null, otherwise the DLL would not properly unload the source manager. After I changed the source code, the Java application responded without errors. The native Win32 environment didn't need these changes, as the DLL unloaded properly

Java and Win32 hardware: The ugly truth

Though the low-level plumbing is set up, communication between Java and Win32 will still present problems. Java has difficulty integrating with hardware devices because of the Win32 message pump. Java has no real way to connect to the event handlers in the Win32 world. Instead, you must create a proxy window, so it, not the Java application, can receive the Win32 SDK messages.

That approach negates the need to pass the HWND parameter to EZTwain DLL; instead we can use a null HWND as a parameter within the DLL. When the EZTwain 1.x DLL detects a null, it creates a proxy window, hides it, and uses it for pumping message handlers. The Java client is relieved of the HWND responsibility, simplifying the bridge between the two layers.

Note: That technique proves useful for synchronous hardware devices like Twain or utility libraries that lack a real GUI. With Twain, you pass it a command, the vendor-supplied dialog appears, the acquisition occurs, and then Twain eventually returns a DIB. However, be aware that, with TAPI (Telephony Application Programmers Interface) and other asynchronous technologies, passing a null HWND will not suffice. Further processing of call-back methods may be required. Asynchronous hardware devices need both the application and the DLL to participate in two-way communication via the Win32 message handlers. As Java clients cannot take part, more complex solutions are required: perhaps a TCP/IP socket server.

The JNI C interface

Now we need to map the previous flow of events to an actual interface in the JNI layer. We must write the exact number of JNI methods required to realize the use-case—no more and no less. Strictly adhering to RUP keeps us focused. The sequence diagram depicts the user actor going through the use-case and exercising our API. I detail the methods below:

isTwainAvailble()

The JNI method jboolean Java_org_scavino_twain_JTwain_isTwainAvailble() allows an application to test for Twain's existence. This method accomplishes Step 1 in the use-case's primary flow. isTwainAvailble() does not confirm whether your particular Twain device is enabled or even attached to the machine. It merely tests for the existence of the twain.dll in your path and verifies that you have at least one Twain device installed. This result is cached after the Twain library has been prodded. A more elaborate exception-handling mechanism could replace the simple boolean return type. Again, the current goal is simplicity, and a future iteration could have exception handling in the interface.

  • Print
  • Feedback

Resources