In this post I'm going to cover a basic crash course for using the Microsoft Windows Image Acquisition library (WIA) in a C# WinForms application. It's mostly based around using the various built-in dialogues in order to easily add image acquisition and printing to your application, I don't go into deeper functionality such as command execution.
I started writing this post in September 2019 before burning out in a fairly large fashion. Is it normally my policy that I don't write a new development blog post until the previous is finished, even if not published, but after staring blankly at it for 9 months whenever I opened it, I had to shelve it and move on. It is now approaching 14 months and so I'm pushing it out as is.
Adding a reference to WIA
- Open the Add Reference dialogue
- Select COM from the left-hand sidebar
- Find Microsoft Windows Image Acquisition Library 2.0 from
the list and check it (you may find it easier just to type
imageinto the search box)
- Click OK to add the reference
Using COM Interop
If you aren't used to using COM references in .NET, it may be worth reading my previous article Resolving compile error "Interop type cannot be embedded. Use the applicable interface instead" to avoid some potential pitfalls.
A note on collections
WIA offers various collection interfaces, such as
Properties. All of these collections are
one-based just like Visual Basic of old, not the zero-based
collections of .NET.
A note on image formats
Although several functions allow you to specify an image format, it is not guaranteed that the result will use that format. For example, when scanning an image I always ask for an image in PNG format, but the result I get is always BMP on both the old Canon flatbed I used for most of this article and on a more recent Brother MFC-L2710DW.
Working with devices
Before you can do anything with WIA, you need a device. We can
DeviceManager interface to enumerate and access
DeviceManager interface has a
DeviceInfos property which
can be used to enumerate devices. Each device is returned via
DeviceInfo interface which allows us to query the device
type and enumerate its properties.
WIA supports 3 different types of devices - Scanners, Cameras and Video Cameras. I have tested WIA with a flatbed scanner, a DLSR camera, and a mobile phone. Although the latter two can both take pictures and record video, they appear in WIA as the Camera type. I do not have a dedicated video device I was able to test with.
In the months that this article has been sitting in draft form I also acquired a Brother laser printer that includes both a flatbed and an automated document feeder (ADF) scanner, I have briefly tested the flatbed aspect with WIA but not the ADF.
The WIA device type enumeration is not flag based. Therefore, isn't possible to mix and match device types when using WIA functions that take a type - you either have the choice of listing all devices, or devices belong to a single type.
Connecting to a device
DeviceInfo allows you to query the information
related to a specific device, to actually use it we first need
to obtain a
Device instance. This can be done via the
Connect method of a given
Using WIA dialogues
Common dialogues in Windows are a fantastic piece of
functionality - who wants to have to implement the same file or
folder pickers in every application? WIA also provides a number
of common dialogues via the
Selecting a device
ShowSelectDevice method displays a dialogue box for
choosing a device. By default it will show all devices, but you
can limit it to showing devices of a specific type.
There is one caveat with this method however - if no devices are
currently present, it will throw an exception. If you plan on
using this method you should add a handler for a hResult of
WIA_S_NO_DEVICE_AVAILABLE with value of
Alternatively, if you wanted to select a device of a specific
type, then you can use the optional
Displaying device properties
Although this is probably something you are unlikely to need to
call very often, it is possible to display the native
properties dialogue box for a given device via the
ShowDeviceProperties method. The dialogue displayed by this
method will vary by device.
Selecting an item
ShowSelectItems method displays a UI for selecting one or
more items from a device. In the case of a camera, it will
display a selection dialogue box that allows you choose one or
more photographs. For a scanner, it allows you to scan a
document or photo and for a camera it allows selection of a
previous taken photograph (as noted, I have no dedicated video
device to test with). It returns an
Items collection describing
the user's selection, or
null if cancelled.
SingleSelect parameter defaults to
true which only
allows the selection of a single item. Setting it to
allows multiple selection for the Get Pictures dialogue, but has
no effect for the Scan dialogue.
Acquiring an image
ShowAcquireImage will display one or more dialogues for
selecting an image. If successful, it will return an
object containing the acquired data, otherwise
Calling it without any parameters means it will allow an image
to be selected from any supported device, or you can use the
DeviceType parameter to constrain the acquisition to a
Regardless of if you allow for all device types or limit to a single type, if multiple devices exist it will first prompt for a device as described in Selecting a Device above. If only a single device is present it will automatically use that device without presenting a UI.
Once a device has been selected, the appropriate Select Item dialogue is displayed allowing an existing image to be selected (in the case of a camera) or a new image created (in the case of a scanner).
After selecting/creating an image, the image details are
returned wrapped in an
One other parameter which may be of interest is
you specify this, it will try and return the image result in
that format. In practice however, I haven't found this to work -
I always get a Windows Bitmap back regards of what I actually
See Converting WIA.ImageFile into a Bitmap below for how to
get a .NET
Bitmap from the
Transferring an image
As well as using
ShowAcquireImage to obtain an image via a
dialogue, you can also directly obtain an image. This is useful
when you have configured the properties and don't want the user
to be able to change them, for example when repeating a scan
with the same dimensions as the previous scan.
For this, you can use the
ShowTransfer method. This will still
display a dialogue, but one that only shows the progress of the
transfer and that allows it to be cancelled. As with
ShowAcquireImage, this method will return an
containing the results of the operation, and you can also
attempt to specify the image format you wish returned.
By using the
ShowPhotoPrintingWizard you can print one or more
image files, which is a handy way of adding print functionality
to your application with only a few lines of code.
Although you aren't able to control these programmatically, the Wizard allows the user to choose how images are laid out on the page and configure assorted options.
There are a number of caveats with this method that I have noticed:
- The Wizard is not modal, meaning a user can click back and continue working with your application leaving the Wizard open or open multiple copies of the Wizard
- File names must be fully qualified
- The Wizard will fail if any of the image files don't have a
recognised image extension. For example, if you created a
.tmpfile containing a bitmap and tried to print, it would fail (and with a very unhelpful "file not found" message)
Device and item properties
Item interfaces have a
collection that allows you to manipulate the item. Properties
are self-describing, so in addition to staples like ID, name and
value, you can also query the type of the property (both the
value type and also a sub type that describes how the properties
works, for example range or flags). For range based properties,
the minimum and maximum values are accessible, as well as the
step. For properties that are a list of values, you are able to
read these as well. You could use this information to build your
own UI elements rather than using the built in ones, or for
validating user input.
Properties collection has an indexer that accepts an
index, the ID of a property or the name. However, given that
both the index and ID are integers, if you want to pass an ID
you need to convert it to a string first. To save on confusion,
I ended up adding extension methods as helpers.
Assuming I wanted to configure the DPI and quality of a device prior to initiating a scan, I could call the extension as follows
Converting WIA.ImageFile into a Bitmap
ImageFile interface has an
ARGBData property that
Vector containing color data for an image. I tried
using this first to set the pixels of a new bitmap, but even
when manipulating the bitmap pixels directly it was a little
An alternative is to use the
FileData property. This returns a
series of bytes that represent the image in the output format
returned by the device. This means we can dump this into a
MemoryStream and call
Image.FromFile. However, as .NET likes
to keep the stream open that could lead to complications
and so I usually clone the resulting image. The following
extension method will take a given
ImageFile and return a
Bitmap from it.
Note that this extension method isn't suitable for images with
multiple frames (e.g. a multi-page TIFF file) as it will only
keep the first frame. I don't usually work with multi-page
images so I don't have a concrete recommendation for this
use-case. I think I'd lean towards saving the result to a
temporary file and then using
WIA is very useful for adding basic image printing support to your application, and perfect if you want to add the ability for your applications to capture images from various devices. It is capable of more than I've demonstrated here, but this article covers the basics and some common uses.
The source code for the demonstration as it was at the time of publication can be downloaded from the links on this page, any updates can be found on the GitHub repository.
Like what you're reading? Perhaps you like to buy us a coffee?