使用C#无需对话框扫描器

15

我正在构建一个用于远程控制扫描仪设备的.Net 4.0应用程序。我尝试了TWAIN和WIA库,但是遇到了同样的问题——在没有扫描仪选择扫描设置对话框的情况下进行图像扫描。

我发现了一篇有用的文章WIA scripting in .Net,并对其进行了修改:

private Image Scan(string deviceName)
{
    WiaClass wiaManager = null;       // WIA manager COM object
    CollectionClass wiaDevs = null;   // WIA devices collection COM object
    ItemClass wiaRoot = null;         // WIA root device COM object
    CollectionClass wiaPics = null;   // WIA collection COM object
    ItemClass wiaItem = null;         // WIA image COM object

    try
    {
        // create COM instance of WIA manager
        wiaManager = new WiaClass();

        // call Wia.Devices to get all devices
        wiaDevs = wiaManager.Devices as CollectionClass;
        if ((wiaDevs == null) || (wiaDevs.Count == 0))
        {
            throw new Exception("No WIA devices found!");
        }

        object device = null;
        foreach (IWiaDeviceInfo currentDevice in wiaManager.Devices)
        {
            if (currentDevice.Name == deviceName)
            {
                device = currentDevice;
                break;
            }
        }

        if (device == null)
        {
            throw new Exception
            (
                "Device with name \"" + 
                deviceName + 
                "\" could not be found."
            );
        }

        // select device
        wiaRoot = (ItemClass)wiaManager.Create(ref device); 

        // something went wrong
        if (wiaRoot == null)
        {
            throw new Exception
            (
                "Could not initialize device \"" + 
                deviceName + "\"."
            );
        }

        wiaPics = wiaRoot.GetItemsFromUI
        (
            WiaFlag.SingleImage,
            WiaIntent.ImageTypeColor
        ) as CollectionClass;

        if (wiaPics == null || wiaPics.Count == 0)
        {
            throw new Exception("Could not scan image.");
        }

        Image image = null;

        // enumerate all the pictures the user selected
        foreach (object wiaObj in wiaPics)
        {
            if (image == null)
            {
                wiaItem = (ItemClass)Marshal.CreateWrapperOfType
                (
                    wiaObj, typeof(ItemClass)
                );

                // create temporary file for image
                string tempFile = Path.GetTempFileName();

                // transfer picture to our temporary file
                wiaItem.Transfer(tempFile, false);

                // create Image instance from file
                image = Image.FromFile(tempFile);
            }

            // release enumerated COM object
            Marshal.ReleaseComObject(wiaObj);
        }

        if (image == null)
        {
            throw new Exception("Error reading scanned image.");
        }

        return image;
    }
    finally
    {
        // release WIA image COM object
        if (wiaItem != null)
            Marshal.ReleaseComObject(wiaItem);

        // release WIA collection COM object
        if (wiaPics != null)
            Marshal.ReleaseComObject(wiaPics);

        // release WIA root device COM object
        if (wiaRoot != null)
            Marshal.ReleaseComObject(wiaRoot);

        // release WIA devices collection COM object
        if (wiaDevs != null)
            Marshal.ReleaseComObject(wiaDevs);

        // release WIA manager COM object
        if (wiaManager != null)
            Marshal.ReleaseComObject(wiaManager);
    }
}

通过这个方法,我成功从配置中选择了设备(Scan方法的输入参数),并获取了扫描后得到的图像。

但是,扫描选项对话框(使用DEVICENAME进行扫描)会出现问题。由于这是一个远程控制应用程序,对话框不会显示给用户,因此我需要使用默认设置跳过它,或者在必要时使用配置中的设置。

扫描选项对话框: scanning options dialog


3
你认为,如果要避免出现任何用户界面,调用GetItemsFromUI可能是问题的根源吗? - Damien_The_Unbeliever
顺便提一下,这是使用“Microsoft Windows Image Acquisition 1.01 Type Library”完成的,但如果其他库可以解决此问题,则欢迎使用。 - Miljenko Barbir
@Damien_The_Unbeliever:哈哈,那肯定是问题所在,但有什么替代方案呢? - Miljenko Barbir
你不能直接使用 wiaRoot.Children 吗? - Gabe
@Gabe:wiaRoot.Children 可以用来做什么? - Miljenko Barbir
3个回答

23
最终,我没有使用问题中编写的代码来扫描对话框。我发现了一个有用的示例,使用Windows Image Acquisition 2.0进行扫描,它也有一个阻塞对话框,但这很容易修改,只需几分钟就可以创建一个简单的类,其中包含一个Scan(string scannerId)函数,它只会选择设备并进行扫描,如下所示:
using System;
using System.Collections.Generic;
using System.IO;
using System.Drawing;

namespace WIATest
{
    class WIAScanner
    {
        const string wiaFormatBMP = "{B96B3CAB-0728-11D3-9D7B-0000F81EF32E}";

        class WIA_DPS_DOCUMENT_HANDLING_SELECT
        {
            public const uint FEEDER = 0x00000001;
            public const uint FLATBED = 0x00000002;
        }

        class WIA_DPS_DOCUMENT_HANDLING_STATUS
        {
            public const uint FEED_READY = 0x00000001;
        }

        class WIA_PROPERTIES
        {
            public const uint WIA_RESERVED_FOR_NEW_PROPS = 1024;
            public const uint WIA_DIP_FIRST = 2;
            public const uint WIA_DPA_FIRST = WIA_DIP_FIRST + WIA_RESERVED_FOR_NEW_PROPS;
            public const uint WIA_DPC_FIRST = WIA_DPA_FIRST + WIA_RESERVED_FOR_NEW_PROPS;
            //
            // Scanner only device properties (DPS)
            //
            public const uint WIA_DPS_FIRST = WIA_DPC_FIRST + WIA_RESERVED_FOR_NEW_PROPS;
            public const uint WIA_DPS_DOCUMENT_HANDLING_STATUS = WIA_DPS_FIRST + 13;
            public const uint WIA_DPS_DOCUMENT_HANDLING_SELECT = WIA_DPS_FIRST + 14;
        }

        /// <summary>
        /// Use scanner to scan an image (with user selecting the scanner from a dialog).
        /// </summary>
        /// <returns>Scanned images.</returns>
        public static List<Image> Scan()
        {
            WIA.ICommonDialog dialog = new WIA.CommonDialog();
            WIA.Device device = dialog.ShowSelectDevice(WIA.WiaDeviceType.UnspecifiedDeviceType, true, false);

            if (device != null)
            {
                return Scan(device.DeviceID);
            }
            else
            {
                throw new Exception("You must select a device for scanning.");
            }
        }

        /// <summary>
        /// Use scanner to scan an image (scanner is selected by its unique id).
        /// </summary>
        /// <param name="scannerName"></param>
        /// <returns>Scanned images.</returns>
        public static List<Image> Scan(string scannerId)
        {
            List<Image> images = new List<Image>();

            bool hasMorePages = true;
            while (hasMorePages)
            {
                // select the correct scanner using the provided scannerId parameter
                WIA.DeviceManager manager = new WIA.DeviceManager();
                WIA.Device device = null;

                foreach (WIA.DeviceInfo info in manager.DeviceInfos)
                {
                    if (info.DeviceID == scannerId)
                    {
                        // connect to scanner
                        device = info.Connect();
                        break;
                    }
                }

                // device was not found
                if (device == null)
                {
                    // enumerate available devices
                    string availableDevices = "";
                    foreach (WIA.DeviceInfo info in manager.DeviceInfos)
                    {
                        availableDevices += info.DeviceID + "n";
                    }

                    // show error with available devices
                    throw new Exception("The device with provided ID could not be found. Available Devices:n" + availableDevices);
                }

                WIA.Item item = device.Items[1] as WIA.Item;

                try
                {
                    // scan image
                    WIA.ICommonDialog wiaCommonDialog = new WIA.CommonDialog();
                    WIA.ImageFile image = (WIA.ImageFile)wiaCommonDialog.ShowTransfer(item, wiaFormatBMP, false);

                    // save to temp file
                    string fileName = Path.GetTempFileName();
                    File.Delete(fileName);
                    image.SaveFile(fileName);
                    image = null;

                    // add file to output list
                    images.Add(Image.FromFile(fileName));
                }
                catch (Exception exc)
                {
                    throw exc;
                }
                finally
                {
                    item = null;

                    //determine if there are any more pages waiting
                    WIA.Property documentHandlingSelect = null;
                    WIA.Property documentHandlingStatus = null;

                    foreach (WIA.Property prop in device.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;
                    }

                    // assume there are no more pages
                    hasMorePages = false;

                    // may not exist on flatbed scanner but required for feeder
                    if (documentHandlingSelect != null)
                    {
                        // check for document feeder
                        if ((Convert.ToUInt32(documentHandlingSelect.get_Value()) &amp;amp;amp;amp; WIA_DPS_DOCUMENT_HANDLING_SELECT.FEEDER) != 0)
                        {
                            hasMorePages = ((Convert.ToUInt32(documentHandlingStatus.get_Value()) &amp;amp;amp;amp; WIA_DPS_DOCUMENT_HANDLING_STATUS.FEED_READY) != 0);
                        }
                    }
                }
            }

            return images;
        }

        /// <summary>
        /// Gets the list of available WIA devices.
        /// </summary>
        /// <returns></returns>
        public static List<string> GetDevices()
        {
            List<string> devices = new List<string>();
            WIA.DeviceManager manager = new WIA.DeviceManager();

            foreach (WIA.DeviceInfo info in manager.DeviceInfos)
            {
                devices.Add(info.DeviceID);
            }

            return devices;
        }

    }
}

7

首先,非常感谢Miljenko Barbir提供的解决方案,它非常有效。

我想补充一点,如果你想要零对话框,你可以使用(来自Milijenko的演示代码)。

WIA.ImageFile image = item.Transfer(wiaFormatBMP);

代替
WIA.ImageFile image = (WIA.ImageFile)wiaCommonDialog.ShowTransfer(item, wiaFormatBMP, false);

这基本上也会移除进度条,因此您可以在没有任何对话框的情况下进行扫描。

这真的帮助了我修改 http://adfwia.codeplex.com/ 上的代码,使其能够在没有任何 UI 的情况下进行扫描。非常感谢。 - Vishnoo Rath
@Greg,非常感谢。这节省了我的时间。 - SaddamBinSyed

0
// show scanner view 
guif.ShowUI = 0;
guif.ModalUI = 0;

你可以看到在这段代码中,我已经实现了。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接