Playing with the Scanner with WIA and C#
Last week I needed to implement a piece of software for scanning small documents (bank payment orders). The problem was to scan documents with specific size (less than A4) in 300 DPI and with normal brightness and contrast. I found that in C# there are two general approaches to this problem:
- Using the TWAIN interface
- Using Windows Image Acquisition (WIA) API
Both interfaces are not natively supported in .NET Framework so some kind of wrappers was necessary to be developed. I choose WIA because it was simpler and higher level API with sufficient enough power.
To use WIA you need to download it from Microsoft (it is a COM server, distributed freely): http://www.microsoft.com/downloads/details.aspx?familyid=a332a77a-01b8-4de6-91c2-b7ea32537e29&displaylang=en.
The next step is to add it as COM object reference in Visual Studio (you need a single file called wiaaut.dll that you need to register with regsvr32). Once you add the reference to WIA COM object in Visual Studio, you get the namespace WIA. All you need to scan image is in this namespace. The most important classes are: Device, Item and CommonDialogClass.
I will not get into more details because developers need code and usually read the text only if the code is not working. Am I right? Did you tread this text?
using System; using System.IO; using System.Windows.Forms; using WIA; namespace PlayingWithTheScanner { public partial class MainForm : Form { public MainForm() { InitializeComponent(); } private void buttonScan_Click(object sender, EventArgs e) { CommonDialogClass commonDialogClass = new CommonDialogClass(); Device scannerDevice = commonDialogClass.ShowSelectDevice(WiaDeviceType.ScannerDeviceType, false, false); if (scannerDevice != null) { Item scannnerItem = scannerDevice.Items[1]; AdjustScannerSettings(scannnerItem, 300, 0, 0, 1010, 620, 0, 0); object scanResult = commonDialogClass.ShowTransfer(scannnerItem, WIA.FormatID.wiaFormatPNG, false); if (scanResult != null) { ImageFile image = (ImageFile) scanResult; string fileName = Path.GetTempPath() + DateTime.Now.ToString("dd-MM-yyyy-hh-mm-ss-fffffff") + ".png"; SaveImageToPNGFile(image, fileName); pictureBoxScannedImage.ImageLocation = fileName; } } } private static void AdjustScannerSettings(IItem scannnerItem, int scanResolutionDPI, int scanStartLeftPixel, int scanStartTopPixel, int scanWidthPixels, int scanHeightPixels, int brightnessPercents, int contrastPercents) { const string WIA_HORIZONTAL_SCAN_RESOLUTION_DPI = "6147"; const string WIA_VERTICAL_SCAN_RESOLUTION_DPI = "6148"; const string WIA_HORIZONTAL_SCAN_START_PIXEL = "6149"; const string WIA_VERTICAL_SCAN_START_PIXEL = "6150"; const string WIA_HORIZONTAL_SCAN_SIZE_PIXELS = "6151"; const string WIA_VERTICAL_SCAN_SIZE_PIXELS = "6152"; const string WIA_SCAN_BRIGHTNESS_PERCENTS = "6154"; const string WIA_SCAN_CONTRAST_PERCENTS = "6155"; SetWIAProperty(scannnerItem.Properties, WIA_HORIZONTAL_SCAN_RESOLUTION_DPI, scanResolutionDPI); SetWIAProperty(scannnerItem.Properties, WIA_VERTICAL_SCAN_RESOLUTION_DPI, scanResolutionDPI); SetWIAProperty(scannnerItem.Properties, WIA_HORIZONTAL_SCAN_START_PIXEL, scanStartLeftPixel); SetWIAProperty(scannnerItem.Properties, WIA_VERTICAL_SCAN_START_PIXEL, scanStartTopPixel); SetWIAProperty(scannnerItem.Properties, WIA_HORIZONTAL_SCAN_SIZE_PIXELS, scanWidthPixels); SetWIAProperty(scannnerItem.Properties, WIA_VERTICAL_SCAN_SIZE_PIXELS, scanHeightPixels); SetWIAProperty(scannnerItem.Properties, WIA_SCAN_BRIGHTNESS_PERCENTS, brightnessPercents); SetWIAProperty(scannnerItem.Properties, WIA_SCAN_CONTRAST_PERCENTS, contrastPercents); } private static void SetWIAProperty(IProperties properties, object propName, object propValue) { Property prop = properties.get_Item(ref propName); prop.set_Value(ref propValue); } private static void SaveImageToPNGFile(ImageFile image, string fileName) { ImageProcess imgProcess = new ImageProcess(); object convertFilter = "Convert"; string convertFilterID = imgProcess.FilterInfos.get_Item(ref convertFilter).FilterID; imgProcess.Filters.Add(convertFilterID, 0); SetWIAProperty(imgProcess.Filters[imgProcess.Filters.Count].Properties, "FormatID", WIA.FormatID.wiaFormatPNG); image = imgProcess.Apply(image); image.SaveFile(fileName); } } }
The above example scans a small area of the page in 300 DPI (color mode), saves the result in PNG format and displays it in a picture box. Download the entire example’s source code: playingwiththescanner.zip.
The interface of WIA is really ugly and is not C# friendly, but that’s the life. Enjoy….
28 Responses to “Playing with the Scanner with WIA and C#”
Hi Leute,
der Code ist gut, aber unbedingt bei den Eigenschaften für WIA -> Interop-Typen einbetten auf “False” setzen, sonst werden die Klassen-Konstruktoren nicht gefunden und nichts funktioniert bzw.man bekommt Compilefehler en masse.
Axel Arnold Bangert – Herzogenrath 2011
Hi folks,
what I am missing and searching is the grayscale option, for the default option of all scanner settings is WiaImageIntent.ColorIntent.
Though it is implemented in -> showAcquireImage(WiaDeviceType.ScannerDeviceType,WiaImageIntent.GrayscaleIntent, WiaImageBias.MinimizeSize, WIA.FormatID.wiaFormatJPEG, false, true, false) -> but I don’t want to see the Scanner GUI.
So there must be something like -> ?????const string WIA_SCAN_GrayscaleIntent = ??????;
Does someone know something about that?
Axel Arnold Bangert – Herzogenrath 2011
Hi folks,
what I am missing and searching is the grayscale option, for the default option of all scanner settings is WiaImageIntent.ColorIntent.
Though it is implemented in -> showAcquireImage(WiaDeviceType.ScannerDeviceType,WiaImageIntent.GrayscaleIntent, WiaImageBias.MinimizeSize, WIA.FormatID.wiaFormatJPEG, false, true, false) -> but I don’t want to see the Scanner GUI.
So there must be something like -> ?????const string WIA_SCAN_GrayscaleIntent = ??????;
Does someone know something about that?
Axel Arnold Bangert – Herzogenrath 2011
Hi,
I have just found it here http://msdn.microsoft.com/en-us/library/ms630196%28v=VS.85%29.aspx
WIA_IPS_CUR_INTENT — WIA_INTENT_IMAGE_TYPE_GRAYSCALE
Axel Arnold Bangert – Herzogenrath 2011
Hi,
it works fine for grayscale like that:AdjustScannerSettings(scannnerItem, 150, 0, 0, 1275, 1755, 2, 0, 0);…private static void AdjustScannerSettings(IItem scannnerItem, int scanResolutionDPI,int scanStartLeftPixel, int scanStartTopPixel,int scanWidthPixels,
int scanHeightPixels, int scanColorIntent, int brightnessPercents, int contrastPercents)…const string WIA_IPS_CUR_INTENT = “6146”;SetWIAProperty(scannnerItem.Properties, WIA_IPS_CUR_INTENT, scanColorIntent);…
Axel Arnold Bangert – Herzogenrath 2011
Grayscale
Axel Arnold Bangert – Herzogenrath 2011
Hi
wiothout the right PropertyID nothing works. To get the right PropertyID you can
catch it like that:
for (int i = 1 ; i < scannnerItem.Properties.Count; i++)
{
Property prop = scannnerItem.Properties.get_Item(i);
MessageBox.Show(prop.Name.ToString() + " = " + prop.PropertyID.ToString());
}
Without the right PropertyID you cannot set the constant – for example:
const string WIA_IPS_CUR_INTENT = “6146″
Best regards
Axel Arnold Bangert – Herzogenrath
Item Name = 4098
Full Item Name = 4099
Item Flags = 4101
Color Profile Name = 4120
Brightness = 6154
Contrast = 6155
Private Highlight Level = 71692
Private Midtone Level = 71694
Private Shadow Level = 71693
Private Gamma = 71695
Private Saturation = 71699
Private Hue X = 71696
Private Hue Y = 71697
Private Sharpen Level = 71698
Threshold = 6159
Horizontal Resolution = 6147
Vertical Resolution = 6148
Private Default Resolution = 71687
Private Quality Resolution = 71688
Horizontal Start Position = 6149
Vertical Start Position = 6150
Horizontal Extent = 6151
Vertical Extent = 6152
Pixels Per Line = 4112
Bytes Per Line = 4113
Number of Lines = 4114
Item Size = 4116
Minimum Buffer Size = 4118
Current Intent = 6146
Data Type = 4103
Bits Per Pixel = 4104
Bits Per Channel = 4110
Channels Per Pixel = 4109
Planar = 4111
Compression = 4107
Media Type = 4108
Format = 4106
Preferred Format = 4105
Filename extension = 4123
Access Rights = 4102
Photometric Interpretation = 6153
Private Source Depth = 71686
Private Preview = 71683
Private Exposure Method = 71689
Private Smoothing = 71722
Private Color Enhanced = 71723
Private TMA Method = 71685
Private Defaults = 71701
Axel Arnold Bangert – Herzogenrath 2011
const DeviceID = 2
const Manufacturer = 3
const Description = 4
const Type = 5
const Port = 6
const Name = 7
const Server = 8
const RemoteDevID = 9
const UIClassID = 10
const FirmwareVersion = 1026
const ConnectStatus = 1027
const DeviceTime = 1028
const PicturesTaken = 2050
const PicturesRemaining = 2051
const ExposureMode = 2052
const ExposureCompensation = 2053
const ExposureTime = 2054
const FNumber = 2055
const FlashMode = 2056
const FocusMode = 2057
const FocusManualDist = 2058
const ZoomPosition = 2059
const PanPosition = 2060
const TiltPostion = 2061
const TimerMode = 2062
const TimerValue = 2063
const PowerMode = 2064
const BatteryStatus = 2065
const Dimension = 2070
const HorizontalBedSize = 3074
const VerticalBedSize = 3075
const HorizontalSheetFeedSize = 3076
const VerticalSheetFeedSize = 3077
const SheetFeederRegistration = 3078
const HorizontalBedRegistration = 3079
const VerticalBedRegistraion = 3080
const PlatenColor = 3081
const PadColor = 3082
const FilterSelect = 3083
const DitherSelect = 3084
const DitherPatternData = 3085
const DocumentHandlingCapabilities = 3086
const DocumentHandlingStatus = 3087
const DocumentHandlingSelect = 3088
const DocumentHandlingCapacity = 3089
const HorizontalOpticalResolution = 3090
const VerticalOpticalResolution = 3091
const EndorserCharacters = 3092
const EndorserString = 3093
const ScanAheadPages = 3094
const MaxScanTime = 3095
const Pages = 3096
const PageSize = 3097
const PageWidth = 3098
const PageHeight = 3099
const Preview = 3100
const TransparencyAdapter = 3101
const TransparecnyAdapterSelect = 3102
const ItemName = 4098
const FullItemName = 4099
const ItemTimeStamp = 4100
const ItemFlags = 4101
const AccessRights = 4102
const DataType = 4103
const BitsPerPixel = 4104
const PreferredFormat = 4105
const Format = 4106
const Compression = 4107
const MediaType = 4108
const ChannelsPerPixel = 4109
const BitsPerChannel = 4110
const Planar = 4111
const PixelsPerLine = 4112
const BytesPerLine = 4113
const NumberOfLines = 4114
const GammaCurves = 4115
const ItemSize = 4116
const ColorProfiles = 4117
const BufferSize = 4118
const RegionType = 4119
const ColorProfileName = 4120
const ApplicationAppliesColorMapping = 4121
const StreamCompatibilityID = 4122
const ThumbData = 5122
const ThumbWidth = 5123
const ThumbHeight = 5124
const AudioAvailable = 5125
const AudioFormat = 5126
const AudioData = 5127
const PicturesPerRow = 5128
const SequenceNumber = 5129
const TimeDelay = 5130
const CurrentIntent = 6146
const HorizontalResolution = 6147
const VerticalResolution = 6148
const HorizontalStartPostion = 6149
const VerticalStartPosition = 6150
const HorizontalExtent = 6151
const VerticalExtent = 6152
const PhotometricInterpretation = 6153
const Brightness = 6154
const Contrast = 6155
const Orientation = 6156
const Rotation = 6157
const Mirror = 6158
const Threshold = 6159
const Invert= 6160
const LampWarmUpTime = 6161
In fact WIA is less flexible than TWAIN. Not all options are controllable and generally scanning is slower than with TWAIN. It works for simple tasks but is not good enough in more complex scenarios.
Hi every one,
This example is working fine but in preview of document the document is not displaying full.
How to change the settings to preview full image of a document in this ………
Please help me ………
WIA has missing features and works slower. For more complex applications use the TWAIN API.
Hello good example you gave.
I need your help, I get the following error.
CommonDialogClass commonDialogClass = new CommonDialogClass ();
Interop type ‘WIA.CommonDialogClass’ can not be embedded. Use the applicable interface instead.
please if anyone knows thanks in advance resolve.
Great post, thats what I needed.
@weimar:
Just double click on reference on Solution Explorer and Select WIA, then in properties Window, select [Embed Interop Type] property and make it false.
Sorry my Keyboard is not working properly, thats y typo. Great post and its really useful for me since Iam a beginner.
I have uploaded SOlution but found below error.
Could not load file or assembly ‘Interop.WIA, Version=1.0.0.0, Culture=neutral, PublicKeyToken=a5a1b2327382927a’ or one of its dependencies. The system cannot find the file specified.
Please Advice me as soon as possible
Maybe the version of .NET Framework. This codee is very old. You need the assembly Interop.WIA.dll, version 1.0. Try to find is somewhere in Internet.
In Windows 7 and Windows 8, WIA is part of Windows and no additional download is required. You can just add a reference to the COM server %WinDir%\System32\wiaaut.dll from Visual Studio. Visual Studio will make automatically Interop assembly. You can choose “Windows Image Acquisition Library v2.0” from the “COM” section in the “Reference Manager” in Visual Studio (right click on the project –> Add Reference…)
How to implement the same in asp.net web application?any idea plz share…..
Thanks in advance….
There are third-party non-standard browser plugins that provide scanner access capabilities through JavaScript, e.g. http://www.codeproject.com/Articles/524884/Control-Scanners-Webcams-in-JavaScript. You may use JS code to scan the document and upload it to the ASP.NET application.
If we are using third party tool i.e TWAIN,we have to buy it.Is there any way by which we can make it for free.If then plz share
Thanks in advance…..
I’ll try to put this to good use imemeiatdly.
good website found here.
In Windows 7 to Windows 10 WIA is part of Windows and no additional download is required. Now in this article you have showed the relation of WIA and C#. You may take a look of https://procpedia.com/wia-error-codes which help to learn more about WIA errors codes which we face and their solution as well.
Has anybody been able to do a duplex scan using a document feeder using WIA 2.0. Am able to scan but onnly front page is acquired.
In order to scan both sides, a property may have to be set. This setting is made on the device, not on the item. This could look like this, for example:
if (duplex)
{
SetProp(device, WIA_PROPERTIES.WIA_DPS_DOCUMENT_HANDLING_SELECT, WIA_PROPERTIES.WIA_ADF_DUPLEX);
}
The following applies:
private class WIA_PROPERTIES
{
public const uint WIA_ADF_DUPLEX = 0x005;
public const and WIA_DPS_DOCUMENT_HANDLING_SELECT = 3088;
}
And the method that sets the property:
private void SetProp(WIA.Device device, uint target, object value)
{
if (device == null)
return;
if (target == null)
return;
foreach (WIA.Property prop in device.Properties)
{
if (prop.PropertyID == target)
prop.set_Value(value);
}
}
Translated with http://www.DeepL.com/Translator
How I can preview simultaneously before final scan?
I used this code but not getting output properly, just getting some dots in middle of the page expect that everything is white any help pls.