May 14 2008
scan an image using the WIA Library
in .net, 2 ways of probably many more, to invoke imaging devices like scanner etc and get the scanned objects/documents are discussed below.
One is using TWAIN. TWAIN is an API used by software applications to talk to imaging devices. I believe it is an old API, but still quite famous. my multimedia courses always made reference to the TWAIN standards, and the section always ended with a reference citing, TWAIN to be very complicated and restricted to work with.
The word TWAIN is from Rudyard 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.
The word TWAIN is not an official acronym; however, it is widely known as “Technology Without Any Impressive Name.” - Wikipedia
however, the second and the latest API is the WIA Library. (Windows Image Acquisition Library) this is a later API than TWAIN, and said to be more standards-conformant, though I have no idea yet. I haven’t worked with TWAIN to see the difficulties.
the WIA library is probably in-built in VISTA and Windows 2003 Operating systems, but I couldn’t spot it in XP.
getting onto the code, in order to scan and process a document using c#,
- add a reference to the WIALib.dll (Microsoft Windows Image Acquisition 1.01 Type Library)
- include the following using directives.
using System.Runtime.InteropServices; using WIALib;
I ended up with the following snippet which scans and processes the scanned document:
private void ScanDocuments() { // WIA manager COM object. // Allows the user to select an imaging device like scanner/camera etc. WiaClass wiaManager = null; // WIA devices collection COM object. // The collection of imaging devices. CollectionClass wiaDevicesCollection = null; // WIA root device COM object. // Represents the selected imaging device. ItemClass wiaRootDeviceItem = null; // WIA collection COM object. // Collection of WIA Image items. CollectionClass wiaImageItems = null; // WIA image COM object. // Represents the first of our selected image. ItemClass wiaFirstScannedItem = null; try { // create COM instance of WIA manager wiaManager = new WiaClass(); // call Wia.Devices to get all devices wiaDevicesCollection = (CollectionClass)wiaManager.Devices; // No Devices found. if (null == wiaDevicesCollection || 0 == wiaDevicesCollection.Count) { throw new Exception("No WIA devices found!"); } // = Nothing for COM. object useDialogFlag = System.Reflection.Missing.Value; // User will select a root device here. wiaRootDeviceItem = (ItemClass)wiaManager.Create(ref useDialogFlag); // No device selected. Just return. if (null == wiaRootDeviceItem) { return; } // Get the list of images. wiaImageItems = (CollectionClass)wiaRootDeviceItem.GetItemsFromUI(WiaFlag.SingleImage, WiaIntent.ImageTypeColor); // If there is a problem, return. if (null == wiaImageItems) { return; } // We'll grab the first picture only. bool useFirstImageOnly = true; // Iterate through the images and select the first one. foreach (object wiaImageObject in wiaImageItems) { if ((useFirstImageOnly)) { wiaFirstScannedItem = (ItemClass)Marshal.CreateWrapperOfType(wiaImageObject, typeof(ItemClass)); // Get a temporary file name. string tempFileName = System.IO.Path.GetTempFileName(); // Copy the scanned object to the temporary file, in a synchronous manner. wiaFirstScannedItem.Transfer(tempFileName, false); // Work with the tempFile. useFirstImageOnly = false; // If you want to get hold of all the scanned items, // remove the 'useFirstImageOnly' flag. } // Release the enumerated COM object image. Marshal.ReleaseComObject(wiaImageObject); } } catch (Exception ex) { throw new Exception("Acquire from WIA Imaging failed: " + ex.Message); } finally { // Release the COM objects used. if (null != wiaFirstScannedItem) { Marshal.ReleaseComObject(wiaFirstScannedItem); } if (null != wiaImageItems) { Marshal.ReleaseComObject(wiaImageItems); } if (null != wiaRootDeviceItem) { Marshal.ReleaseComObject(wiaRootDeviceItem); } if (null != wiaDevicesCollection) { Marshal.ReleaseComObject(wiaDevicesCollection); } if (null != wiaManager) { Marshal.ReleaseComObject(wiaManager); } } }
couple of things I noticed:
- when I use the method to invoke the graphic device (scanner, digital camera etc), the imaging device GUI is launched. as good as if you invoked the scanner/digital camera device using Start >> etc..
- once you scan N number of objects, the above code snippet selects just the first one.
as you can see from the comments, you can easily process all the scanned documents., instead of just the first one.
I was browsing through the TWAIN standards and looking for .NET snippets to scan documents, and wanted a cleaner solution to scan a document. the WIA code seemed a little compact.
there’s a solution to every problem; given enough time and money..