使用 WIA 自动进纸器扫描仪扫描第二页失败

Posted

技术标签:

【中文标题】使用 WIA 自动进纸器扫描仪扫描第二页失败【英文标题】:Scanning with WIA automatic feeder scanner fails for second page 【发布时间】:2015-12-18 22:33:18 【问题描述】:

我正在尝试使用具有自动进纸器的扫描仪扫描多页。目前我的代码很简单:

WIA.CommonDialog dialog = new WIA.CommonDialog();
WIA.Device device = dialog.ShowSelectDevice(WIA.WiaDeviceType.ScannerDeviceType);
WIA.Items items = dialog.ShowSelectItems(device);
foreach (WIA.Item item in items)

    while (true)
    
        try
        
            WIA.ImageFile image = (WIA.ImageFile)dialog.ShowTransfer(item);
            if (image != null && image.FileData != null)
            
                dynamic binaryData = image.FileData.get_BinaryData();
                if (binaryData is byte[])
                    using (MemoryStream stream = new MemoryStream(binaryData))
                    using (Bitmap bitmap = (Bitmap)Bitmap.FromStream(stream))
                    
                        bitmap.Save(@"C:\Temp\scan.jpg", ImageFormat.Jpeg);
                    
            
        
        catch (COMException)
        
            break;
        
    

我尝试查询 WIA_DPS_DOCUMENT_HANDLING_STATUS 属性以查看馈送器中是否有任何可用页面,但始终返回 1,因此如果我得到 WIA_ERROR_PAPER_EMPTY,我会捕获 COM 异常,我知道文档进纸器是空的。

问题是这段代码只扫描第一页,当再次调用 dialog.ShowTransfer 方法时,我得到一个异常 E_FAIL HResult 并且我无法扫描更多页面。奇怪的是,当我在调试器中单步执行这段代码时,一切正常,所有页面都被扫描了。

我尝试通过执行Marshal.ReleaseComObject(image)image = null 来释放图像对象,但这并没有帮助。 this question 的建议也没有。是否有什么我做错了导致这些错误?

编辑:我无法找到一个好的解决方案。当进纸器准备扫描下一页时,扫描仪不断抛出E_FAIL,这需要几秒钟(它不是一个非常快的扫描仪)。所以,我添加了一个循环来继续尝试 10 秒,这是一个我不喜欢的解决方案,但它似乎有效。

编辑 2:这似乎是打印机的 WIA 驱动程序的问题。我用其他品牌的打印机试过了,完全没有这个问题。

【问题讨论】:

Vesan 您是否将其作为服务运行?还是使用不同的帐户?确保该进程有权访问“C:\Users\USER_PROFILE\AppData\Local\Temp\”文件夹。 @Aldracor 我将其作为常规 WPF 应用程序运行。它确实有权访问该文件夹。 我在同一个问题上苦苦挣扎,您是否找到更多快速扫描的解决方案 【参考方案1】:

我正在做同样的事情,并尝试使用您的代码和此示例中的代码:http://www.codeproject.com/Tips/792316/WIA-Scanner-in-Csharp-Windows-Forms

我在 hp scanjet 5590 上测试了您的代码,即使我在调试器中单步执行代码,它也只能获取一张图像。在第二次调用 dialog.ShowTransfer 引发 ArgumentException 并显示消息“值不在预期范围内”。我设法通过重置“图像”和“对话”对象以及设置显式传输格式 ID 来使其工作。您的代码还将图像写入同一个文件。如果应用于您的代码,这对我有用:

WIA.CommonDialog dialog = new WIA.CommonDialog();
        WIA.Device device = dialog.ShowSelectDevice(WIA.WiaDeviceType.ScannerDeviceType);
        WIA.Items items = dialog.ShowSelectItems(device);
        foreach (WIA.Item item in items)
        
            while (true)
            
                WIA.ImageFile image = null;
                try
                
                    dialog = new WIA.CommonDialog();
                    image = (WIA.ImageFile)dialog.ShowTransfer(item,"B96B3CAB-0728-11D3-9D7B-0000F81EF32E", false);
                    if (image != null && image.FileData != null)
                    
                        dynamic binaryData = image.FileData.get_BinaryData();
                        if (binaryData is byte[])
                            using (MemoryStream stream = new MemoryStream(binaryData))
                            using (Bitmap bitmap = (Bitmap) Bitmap.FromStream(stream))
                            
                                bitmap.Save(String.Format(@"C:\Temp\scan0.jpg", Path.GetRandomFileName()),
                                    ImageFormat.Jpeg);
                            
                    
                
                catch (COMException)
                
                    break;
                
                finally
                
                    if (image != null)
                        Marshal.FinalReleaseComObject(image);
                
            
        

那个 CodeProject 示例在我的硬件上也失败了,但同样的修复也有帮助。如果上面的代码仍然不适合您,请尝试一下,将原来的 Scan 方法替换为:

    public static List<Image> Scan(string scannerId)
    
        List<Image> images = new List<Image>();

        // 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 = null;
        WIA.CommonDialog dialog = new WIA.CommonDialog();
        WIA.Items items = dialog.ShowSelectItems(device);
        if (items == null)
            return images;

        item = items[1];

        bool hasMorePages = true;
        while (hasMorePages)
        
            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);
                try
                
                    Marshal.FinalReleaseComObject(image);
                
                finally
                
                    image = null;
                
                // add file to output list
                images.Add(Image.FromFile(fileName));
            
            finally
            
                //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()) & WIA_DPS_DOCUMENT_HANDLING_SELECT.FEEDER) != 0)
                    
                        hasMorePages = ((Convert.ToUInt32(documentHandlingStatus.get_Value()) & WIA_DPS_DOCUMENT_HANDLING_STATUS.FEED_READY) != 0);
                    
                
            
        
        return images;
    

也将 btn_scan_Click 方法替换为:

    private void btn_scan_Click(object sender, EventArgs e)
    

        try
        
            //get list of devices available
            List<string> devices = WIAScanner.GetDevices();
            List<Image> images = null;

            //check if device is not available
            if (devices.Count == 0)
            
                MessageBox.Show("You do not have any WIA devices.");
                this.Close();
            
            else
            
                if (devices.Count == 1)
                
                    images = WIAScanner.Scan(devices[0]);
                
                else
                
                    images = WIAScanner.Scan();
                
            
            //get images from scanner
            foreach (Image image in images)
            
                var path = String.Format(@"C:\Temp\scan0_1.jpg", DateTime.Now.ToString("yyyy-MM-dd HHmmss"), Path.GetRandomFileName());
                image.Save(path, ImageFormat.Jpeg);
            
        
        catch (Exception exc)
        
            MessageBox.Show(exc.Message);
        
    

【讨论】:

感谢您的建议。不幸的是,第一段代码对我不起作用(我开始认为这一定是扫描仪本身的问题)。第二个在扫描每一页之前显示选择对话框,这在我的情况下并不是很理想(原始的 CodeProject 代码根本不显示对话框,这也是不可接受的)。 我看不出有什么显着差异可能导致一个代码工作但另一个代码工作。通过将对话框移出循环而不释放项目 com 对象,可以很容易地停止 codeproject 示例以停止显示每个页面的对话框。我在原始答案中更新了该代码。【参考方案2】:

此代码适用于我

     try
     
        // Create a DeviceManager instance
        var deviceManager = new DeviceManager();

        List<Image> ret = new List<Image>();

        WIA.CommonDialog dialog = new WIA.CommonDialog();
        WIA.Device device = dialog.ShowSelectDevice(WIA.WiaDeviceType.ScannerDeviceType);
        WIA.Items items = dialog.ShowSelectItems(device);

        foreach (WIA.Item item in items)
        
           while (true)
           
              try
              
                 WIA.ImageFile image = (WIA.ImageFile) dialog.ShowTransfer(item);
                 if (image != null && image.FileData != null)
                 
                    var imageBytes = (byte[]) image.FileData.get_BinaryData();
                    var ms = new MemoryStream(imageBytes);
                    Image img = null;
                    img = Image.FromStream(ms);

                    ret.Add(img);
                 
              
              catch
              
                 break;
              
           
        
        return ret;
     
     catch (Exception)
     
        return null;
     

【讨论】:

该代码与我正在执行的代码有何不同?除了它不处理 MemoryStreamImage?

以上是关于使用 WIA 自动进纸器扫描仪扫描第二页失败的主要内容,如果未能解决你的问题,请参考以下文章

带有自动文档进纸器 (ADF) 的 C# WIA 在某些扫描仪上仅重新调整一页

通过进纸器进行 WIA 扫描

无法读取通过 ADF 扫描的第二页

使用 WIA 或 TWAIN 扫描页面

WIA 2.0 复式属性

WIA + 带有 adf = 1 页的网络扫描仪