saraff-9EB1047A4BEB4cef8506B29BA325BD5A / Saraff.Twain.NET

Saraff.Twain.NET is the skillful scanning component which allows you to control work of flatbed scanner, web and digital camera and any other TWAIN device from .NET environment. You can use this library in your programs written in any programming languages compatible with .NET technology.
GNU General Public License v3.0
102 stars 35 forks source link

Is Acquire an async operation #113

Closed gourango-modak closed 4 months ago

gourango-modak commented 4 months ago

I have a WinForms application where I scan images one by one and display all images in a form using a loop until the user stops the loop. However, when I invoke the Acquire method, it opens the device-specific settings UI, but before the scan completes, it goes to the next line and continues the loop. Therefore, I am unable to acquire any images. How do I call the Acquire method synchronously, so that after one scan completes, it opens the UI again and scans the next image? Please help me how can I achieve this functionality.

Application: WinForms application using Visual Studio Library: Saraff.Twain.NET v1.0.32.732

I am having another issue when running the Saraff.Twain.MultithreadingSample1 sample program and click Acquire button. The Form1 form window and the components inside it change size and become smaller. Please help me understand what could be causing this issue.

Initial window preview -

image

After clicking on Acquire button -

image
saraff-9EB1047A4BEB4cef8506B29BA325BD5A commented 4 months ago

Hello, @gourango-modak Regarding the first issue, you need to set the Twain32.DisableAfterAcquire property to false and handle the Twain32.EndXfer event (see Native Mode Transfer ) instead of calling the Twain32.Acquiry method in a loop.

Regarding the second issue, the scanner window may be trying to adjust the screen settings to ensure proper operation. Try using a different scanner driver or set the default screen settings (96 dpi or 100% scaling)

gourango-modak commented 4 months ago

@saraff-9EB1047A4BEB4cef8506B29BA325BD5A

Thank you so much for your guidance. I am facing another issue when trying to scan multiple times using Twain32.DisableAfterAcquire = false. I get the following exception:

Attempted to read or write protected memory. This is often an indication that other memory is corrupt.

I am using TaskCompletionSource<bool> to wait for my image scan to complete. When the scan completes, I call _scanCompletionSource.SetResult(true) to signal that the operation has finished, allowing the dependent code that awaits this task to execute. Could you please explain what might be causing this issue?

saraff-9EB1047A4BEB4cef8506B29BA325BD5A commented 4 months ago

Hello, @gourango-modak The problem is probably in the use of asynchronous calls. Access to GUI elements should only be possible from the thread that created it. Try handle Twain32.AcquireCompleted event to signal that the operation has finished.

gourango-modak commented 4 months ago

@saraff-9EB1047A4BEB4cef8506B29BA325BD5A

Thanks for the prompt reply. I tried your suggested solution, but I am still encountering the same exception. It appears that the issue is related to the use of asynchronous calls.

Could you please provide guidance on how to meet the following requirements - In my Windows Forms Application, after each image scan completes, I need to display the scanned image in a form with multiple sections, where each section displays a scanned image. Additionally, there are other actions that need to be performed after each image scan completion.

image
saraff-9EB1047A4BEB4cef8506B29BA325BD5A commented 4 months ago

the Twain32.EndXfer event invoke for every transfer to indicate has received all the data it expected.

private void _twain32_EndXfer(object sender,Twain32.EndXferEventArgs e) {
    try {
        using(var _image = e.Image) {
            _image.Save("filename.tif",ImageFormat.Tiff);
        }
   } catch(Exception ex) {
        MessageBox.Show(ex.Message,ex.GetType().Name,MessageBoxButtons.OK,MessageBoxIcon.Error);
    }
}

the Twain32.AcquireCompleted event is called after all images have been transferred.

private void _twain32_AcquireCompleted(object sender,EventArgs e) {
    try {
        for(int i=0; i<this._twain32.ImageCount; i++) {
            using(var _image=this._twain32.GetImage(i)){
                _image.Save(Path.GetTempFileName());
            }
        }
    } catch(Exception ex) {
        MessageBox.Show(ex.Message,ex.GetType().Name,MessageBoxButtons.OK,MessageBoxIcon.Error);
    }
}
gourango-modak commented 4 months ago

@saraff-9EB1047A4BEB4cef8506B29BA325BD5A

Thank you for your guidance. I have another requirement: upon clicking a button, I want to close the scanner UI that opens when the Acquire method is called. I have closed the data source and DSM, but the scanner UI still shows. Is there a way to close it?

saraff-9EB1047A4BEB4cef8506B29BA325BD5A commented 4 months ago

Hello, @gourango-modak Try follow:

private void _twain32_EndXfer(object sender,Twain32.EndXferEventArgs e) {
    try {
        // ...
        if (expr) {
            _twain32.DisableAfterAcquire = true;
            e.Cancel = true;
        }
   } catch(Exception ex) {
        MessageBox.Show(ex.Message,ex.GetType().Name,MessageBoxButtons.OK,MessageBoxIcon.Error);
    }
}
gourango-modak commented 4 months ago

@saraff-9EB1047A4BEB4cef8506B29BA325BD5A

This solution only works when the _twain32_EndXfer callback method is called, but I want to be able to cancel it from outside of this method.

saraff-9EB1047A4BEB4cef8506B29BA325BD5A commented 4 months ago

@gourango-modak

This solution only works when the _twain32_EndXfer callback method is called, but I want to be able to cancel it from outside of this method.

This is impossible.

gourango-modak commented 4 months ago

Hello @saraff-9EB1047A4BEB4cef8506B29BA325BD5A

I am using the following virtual scanner to test this library. However, when I click the cancel button in the scanner UI, I don't receive a cancel exception from the Acquire method. However, I get an exception from the Dynamsoft library. What might be causing this issue? (NOTE: I have set the parent)

On the other hand, with the following TWAIN import driver (XPCTWAIN TIFF Multipage/Multifile TWAIN Import Driver Demo Version), I receive the cancel exception from the Acquire method of Saraff.Twain.

image

I am facing another issue when using the virtual scanner to scan. In this case, the scanner UI doesn't block the form from which I call the acquire method. However, when I use the TWAIN import driver to scan, it blocks the form until I click 'Scan' or 'Cancel'. Why is it behaving differently? However, It works fine with the Dynamsoft Library.

image
saraff-9EB1047A4BEB4cef8506B29BA325BD5A commented 4 months ago

Hello, @gourango-modak The Twain32.Acquire method should not block the form, because it must be asynchronous (the exception is console applications, since they do not have an message loop). You can use the Twain32.Parent property to block user input into parent form.

To handle exceptions from the DataSource (thrown during scanning), you must use the Twain32.AcquireError event

gourango-modak commented 3 months ago

Hello, @saraff-9EB1047A4BEB4cef8506B29BA325BD5A

For this specific device TWAIN import driver (XPCTWAIN TIFF Multipage/Multifile TWAIN Import Driver Demo Version), it blocks UI interaction with the form behind it. Please refer to the video below for a demonstration.

https://drive.google.com/file/d/1yURWaPc72MCizcZuTeJ-689n0kOgNt5T/view

We've set the Twain32.Parent property to keep the device UI always on top of the parent form. This behavior is specific to this device. Is there a way to modify the library so that it behaves like other devices?

Another issue observed with this device is that when we call the Acquire method, it becomes a synchronous operation until the user interacts with the device UI. Additionally, the Twain state doesn't transition to 'DSEnabled' immediately upon opening; it transitions to 'DSEnabled' only when the 'Scan' button is clicked. Furthermore, the data source state becomes disabled immediately after the scan completes, even though the device UI remains open.

Is there a possibility to address these issues by modifying the library?

saraff-9EB1047A4BEB4cef8506B29BA325BD5A commented 3 months ago

Hello @gourango-modak

For this specific device TWAIN import driver (XPCTWAIN TIFF Multipage/Multifile TWAIN Import Driver Demo Version), it blocks UI interaction with the form behind it. Please refer to the video below for a demonstration. https://drive.google.com/file/d/1yURWaPc72MCizcZuTeJ-689n0kOgNt5T/view

This is completely normal behavior. That's how it should be.

We've set the Twain32.Parent property to keep the device UI always on top of the parent form. This behavior is specific to this device. Is there a way to modify the library so that it behaves like other devices?

Both the Saraff.Twain32.NET library and the DataSource behave as they should in this situation. There's no reason to change anything.

Another issue observed with this device is that when we call the Acquire method, it becomes a synchronous operation until the user interacts with the device UI.

It depends on the DataSource. The Saraff.Twain.NET library only interacts with the device in accordance with the TWAIN specification.

Additionally, the Twain state doesn't transition to 'DSEnabled' immediately upon opening; it transitions to 'DSEnabled' only when the 'Scan' button is clicked. Furthermore, the data source state becomes disabled immediately after the scan completes, even though the device UI remains open.

That's how it should be. Otherwise, it would be impossible to get or set the DataSource Capabilities.

Is there a possibility to address these issues by modifying the library?

There is no reason for this. Everything works like clockwork. See TWAIN Specification