Is there a way to scan synhronously? Or await asynchronously?

Issue #80 new
xiety created an issue

Is there simple way to scan synchronously, and then continue work with scanned images? Or some Task to asynchronously await, with images as result?

I just come with not so convenient solution:

var done = new ManualResetEvent(false);
twain.SourceDisabled += (s, e) => done.Set();
...
while (!done.WaitOne(100)) Thread.Sleep(100);

Is there better way?

Comments (8)

  1. xiety reporter

    Sorry. For some unknown reason I was thinking that the DataSource.Enable method was asynchronous. Maybe message loop confused me. Scanning is already synchronous, right?

  2. Eugene Wang repo owner

    TWAIN scanning is always async (non-blocking method call); i.e. Enable() returns before actual scanning happens where the paper/camera moves and then you get an event with the scanned data.

    Perhaps you are confusing sync/async with the UI blocking where window can't be moved during scanning. Those could be due to different reasons.

  3. xiety reporter

    In another issue you told that I can check for Cancel returning from the Enable method. So part of this method will be sync? It blocks until user choose settings in WIA wizard?

  4. Eugene Wang repo owner

    Yes that's a WIA thing. Real TWAIN settings dialog is async, and physical scanning time is also async.

  5. xiety reporter

    Wia and Twain work different. I get it, thank you. So is there a way to make method which will take scanner name as input and return images as output without using things like ManualResetEvent and Thread.Sleep? Or what is the default pattern to scan all papers and then continue to work with acquired images?

  6. Eugene Wang repo owner

    You can create a wrapper that does all the waiting hard work, like this example using task (this is a quick write-up and not guaranteed to work).

    class ScanTaskWrapper
    {
        TwainSession _session;
        TaskCompletionSource<List<string>> _tcs;
        List<string> _imageFiles;
    
        public ScanTaskWrapper()
        {
            _session = new TwainSession(DataGroups.Control | DataGroups.Image);
            _session.SourceDisabled += _session_SourceDisabled;
            _session.DataTransferred += _session_DataTransferred;
        }
    
        public Task<List<string>> ScanImages(string scanner)
        {
            // will have to check for return codes on all calls
            _session.Open();
            var source = _session.FirstOrDefault(device => device.Name == scanner);
            source.Open();
    
            _tcs = new TaskCompletionSource<List<string>>();
            _imageFiles = new List<string>();
    
            if (source.Enable(SourceEnableMode.ShowUI, false, IntPtr.Zero) != ReturnCode.Success)
            {
                _tcs.SetResult(_imageFiles);
            }
            return _tcs.Task;
        }
    
        private void _session_DataTransferred(object sender, DataTransferredEventArgs e)
        {
            var savedFile = ""; // maybe save data to file and add to image list
            _imageFiles.Add(savedFile);
        }
    
        private void _session_SourceDisabled(object sender, EventArgs e)
        {
            _tcs.SetResult(_imageFiles);
            // also check for return codes
            _session.CurrentSource.Close();
            _session.Close();
        }
    }
    
  7. Log in to comment