Introduction
The development of windows imaging applications requires choosing an API to communicate with scanner s or cameras. The most used APIs are WIA and TWAIN.
The WIA (Windows Image Acquisition) platform enables imaging/graphics applications to interact with imaging hardware and standardizes the interaction between different applications and scanners. This allows those different applications to talk to and interact with those different scanners without requiring the application writers and scanner manufactures to customize their application or drivers for each application-device combination. (http://msdn.microsoft.com/en-us/library/ms630368(VS.85).aspx)
TWAIN is a standard software protocol and applications programming interface (API) that regulates communication between software applications and imaging devices such as scanners and digital cameras. (http://www.twain.org/)
Differences:
1. WIA uses a common dialog for all devices while TWAIN uses a dialog created by the device manufacturer. Practically speaking, this almost always means that the TWAIN dialog will provide more options and advanced control over the device.
2. TWAIN allows you to use custom capabilities that the device manufacturer has created even though they don't exist in the TWAIN specifications.
3. In general, when a device supports both Twain and WIA, TWAIN is better for scanners and WIA is better for acquiring images from cameras and video devices.
4. TWAIN has three transfer modes (Native, Memory, File) and WIA only has two (Memory, File).
5. Most TWAIN sources save the settings of the previous scan while WIA does not.
6. TWAIN supports options for each page when scanning in duplex mode but WIA uses the same settings for both sides.
Problem
Usually, older scanners (drivers) are build for TWAIN and does not supported by WIA platform, moreover newer devices which created under Microsoft standard does not supported by TWAIN API.
In order to build scanning application that will communicate with both types of devices I combined those APIs under a uniform interface which will provide the easy access to both type of devices.
ScannerAdapterBase
public abstract class ScannerAdapterBase{protected List<Image> m_ImagesList = null;protected ScannerDeviceData m_ScannerDeviceData = null;// Initializes the Adapterpublic abstract void InitAdapter(nessScanning control, IMessageFilter messageFilter, IntPtr handle);// Selects scanning device, and returns the indicator that the device selected// Returns the indicator that the device selectedpublic abstract bool SelectDevice();// Acquires images from scanning device and fills ImagesLispublic abstract void AcquireImages(bool showUI);…}
Factory Method
public static ScannerAdapterBase GetScannerAdapter(nessScanning control, IMessageFilter messageFilter, IntPtr handle){lock (locker){bool isTwainDeviceSelected = false;if (m_ScannerAdapterBase != null){return m_ScannerAdapterBase;}try{//Checks WIA Devicesm_ScannerAdapterBase = new WiaScannerAdapter();m_ScannerAdapterBase.InitAdapter(control, messageFilter, handle);isWiaDeviceSelected = m_ScannerAdapterBase.SelectDevice();if (isWiaDeviceSelected){return m_ScannerAdapterBase;}//Checks TWAIN Devicesm_ScannerAdapterBase = new TwainScannerAdapter();m_ScannerAdapterBase.InitAdapter(control, messageFilter, handle);isTwainDeviceSelected = m_ScannerAdapterBase.SelectDevice();if (isTwainDeviceSelected){return m_ScannerAdapterBase;}}catch (ScannerException ex){throw ex;}return null;}}
Wia Adapter AcquireImages method
public override void AcquireImages(bool showUI){CommonDialogClass wiaCommonDialog = new CommonDialogClass();//Select Deviceif (m_DeviceID == null){Device device = null;try{device = wiaCommonDialog.ShowSelectDevice(WiaDeviceType.ScannerDeviceType, false, false);if (device != null){m_DeviceID = device.DeviceID;FillDeviceData(device);}else{return;}}catch (COMException ex){if ((WiaScannerError)ex.ErrorCode == WiaScannerError.ScannerNotAvailable){return;}else{WiaScannerException se = BuildScannerException(device, ex);throw se;}}}//Create DeviceManagerDeviceManager manager = new DeviceManagerClass();Device WiaDev = null;foreach (DeviceInfo info in manager.DeviceInfos){if (info.DeviceID == m_DeviceID){WIA.Properties infoprop = null;infoprop = info.Properties;//connect to scannerWiaDev = info.Connect();break;}}//Get Scanning PropertiesWIA.Item scanningItem = null;WIA.Items items = null;if (showUI){items = wiaCommonDialog.ShowSelectItems(WiaDev, WiaImageIntent.TextIntent, WiaImageBias.MinimizeSize, false, true, false);}else{items = WiaDev.Items;}if (items != null && items.Count > 0){scanningItem = items[1] as WIA.Item;}WIA.ImageFile imgFile = null;WIA.Item item = null;//Prepare ImagesListif (m_ImagesList == null){m_ImagesList = new List<Image>;}//Start Scanwhile (HasMorePages(WiaDev)){item = scanningItem;try{//Scan ImageimgFile = (ImageFile)wiaCommonDialog.ShowTransfer(item, ImageFormat.Jpeg.Guid.ToString("B")/* wiaFormatJPEG*/, false);byte[] buffer = (byte[])imgFile.FileData.get_BinaryData();MemoryStream ms = new MemoryStream(buffer);m_ImagesList.Add(Image.FromStream(ms));imgFile = null;}catch (COMException ex){if ((WiaScannerError)ex.ErrorCode == WiaScannerError.PaperEmpty){break;}else{WiaScannerException se = BuildScannerException(WiaDev, ex);throw se;}}catch (Exception ex){WiaScannerException se = BuildScannerException(WiaDev, ex);throw se;}finally{item = null;}}}
Wia Adapter HasMorePages method
private bool HasMorePages(Device WiaDev){try{bool hasMorePages = false;//determine if there are any more pages waitingProperty documentHandlingSelect = null;Property documentHandlingStatus = null;foreach (Property prop in WiaDev.Properties){if (prop.PropertyID == WIA_PROPERTIES.WIA_DPS_DOCUMENT_HANDLING_SELECT)documentHandlingSelect = prop;if (prop.PropertyID == WIA_PROPERTIES.WIA_DPS_DOCUMENT_HANDLING_STATUS)documentHandlingStatus = prop;}if (documentHandlingSelect != null) //may not exist on flatbed scanner but required for feeder{//check for document feederif ((Convert.ToUInt32(documentHandlingSelect.get_Value()) & WIA_DPS_DOCUMENT_HANDLING_SELECT.FEEDER) != 0){hasMorePages = ((Convert.ToUInt32(documentHandlingStatus.get_Value()) & WIA_DPS_DOCUMENT_HANDLING_STATUS.FEED_READY) != 0);}}return hasMorePages;}catch (COMException ex){WiaScannerException se = BuildScannerException(WiaDev, ex);throw se;}}
TWAIN Adapter AcquireImages method
public ArrayList TransferPictures(){ArrayList pics = new ArrayList();if (srcds.Id == IntPtr.Zero){return pics;}TwRC rc;IntPtr hbitmap = IntPtr.Zero;TwPendingXfers pxfr = new TwPendingXfers();do{pxfr.Count = 0;hbitmap = IntPtr.Zero;TwImageInfo iinf = new TwImageInfo();rc = DSiinf(appid, srcds, TwDG.Image, TwDAT.ImageInfo, TwMSG.Get, iinf);if (rc != TwRC.Success){CloseSrc();return pics;}rc = DSixfer(appid, srcds, TwDG.Image, TwDAT.ImageNativeXfer, TwMSG.Get, ref hbitmap);if (rc != TwRC.XferDone){CloseSrc();return pics;}rc = DSpxfer(appid, srcds, TwDG.Control, TwDAT.PendingXfers, TwMSG.EndXfer, pxfr);if (rc != TwRC.Success){CloseSrc();return pics;}pics.Add(hbitmap);}while (pxfr.Count != 0);rc = DSpxfer(appid, srcds, TwDG.Control, TwDAT.PendingXfers, TwMSG.Reset, pxfr);return pics;}