Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Scanning with WIA automatic feeder scanner fails for second page

Tags:

c#

.net

wia

I'm trying to scan multiple pages using a scanner which has an automatic feeder. My code is very simple at the moment:

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;
        }
    }
}

I tried querying the WIA_DPS_DOCUMENT_HANDLING_STATUS property to see if there are any pages available in the feeder, but that always returns 1, so instead I'm catching a COM exception an if I get the WIA_ERROR_PAPER_EMPTY, I know that the document feeder is empty.

The trouble is that this code only scans the first page, when the dialog.ShowTransfer method is called again, I get an exception with and E_FAIL HResult and I can't scan any more pages. Strangely enough, when I step through this code in the debugger, everything works fine and all pages are scanned.

I tried freeing up the image object by doing Marshal.ReleaseComObject(image) and image = null, but that didn't help. Neither did the suggestions from this question. Is there anything I'm doing wrong that's causing these errors?

EDIT: I wasn't able to find a good solution for this. The scanner keeps throwing E_FAIL while the feeder is getting ready to scan the next page, which takes a couple of seconds (it is not a very fast scanner). So, I added a loop to keep trying for 10 seconds, which is a solution that I don't like, but it seems to work.

EDIT 2: This seems to be an issue with the printer's WIA driver. I tried this with a different brand printer and it didn't have this problem at all.

like image 641
vesan Avatar asked Sep 22 '15 04:09

vesan


1 Answers

I'm working on the same thing, and tried to use your code and code from this example: http://www.codeproject.com/Tips/792316/WIA-Scanner-in-Csharp-Windows-Forms

I tested your code on hp scanjet 5590, it only manages to get one image, even when I step through the code in debugger. On second call dialog.ShowTransfer throws ArgumentException with message "Value does not fall within the expected range." I managed to make it work by resetting 'image' and 'dialog' objects and also setting an explicit transfer format ID. Also your code wrote images to the same file. Here is what worked for me if applied to your code:

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\scan{0}.jpg", Path.GetRandomFileName()),
                                    ImageFormat.Jpeg);
                            }
                    }
                }
                catch (COMException)
                {
                    break;
                }
                finally
                {
                    if (image != null)
                        Marshal.FinalReleaseComObject(image);
                }
            }
        }

That CodeProject example failed on my hardware as well, but the same fixes helped. Try it if the code above still doesn't work for you, replace the original Scan method by this:

    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;
    }

Also replace btn_scan_Click method by this:

    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\scan{0}_{1}.jpg", DateTime.Now.ToString("yyyy-MM-dd HHmmss"), Path.GetRandomFileName());
                image.Save(path, ImageFormat.Jpeg);
            }
        }
        catch (Exception exc)
        {
            MessageBox.Show(exc.Message);
        }
    }
like image 80
shuribot Avatar answered Nov 15 '22 00:11

shuribot