November 17, 2009
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….
Tags: 300 dpi, const, DPI, image acquisition, int, level api, scannnerItem, twain interface, VERTICAL, wia
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
Comment by Axel Arnold Bangert — January 22, 2011 @ 20:00
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
Comment by Axel Arnold Bangert — January 22, 2011 @ 21:52
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
Comment by Axel Arnold Bangert — January 22, 2011 @ 21:52
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
Comment by Axel Arnold Bangert — January 23, 2011 @ 10:33
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
Comment by Axel Arnold Bangert — January 23, 2011 @ 11:24
Grayscale
Axel Arnold Bangert – Herzogenrath 2011
Comment by Axel Arnold Bangert — January 23, 2011 @ 11:29
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
Comment by Axel Arnold Bangert — January 23, 2011 @ 12:00
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
Comment by Axel Arnold Bangert — January 23, 2011 @ 12:27
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
Comment by Axel Arnold Bangert — January 23, 2011 @ 15:04
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.
Comment by Nakov — January 23, 2011 @ 22:22