diff --git a/NAPS2.Sdk/Remoting/Worker/WorkerService.proto b/NAPS2.Sdk/Remoting/Worker/WorkerService.proto index 194c7ddd8..3144ea455 100644 --- a/NAPS2.Sdk/Remoting/Worker/WorkerService.proto +++ b/NAPS2.Sdk/Remoting/Worker/WorkerService.proto @@ -110,7 +110,6 @@ message TwainScanResponse { TwainPageStart pageStart = 2; TwainNativeImage nativeImage = 3; TwainMemoryBuffer memoryBuffer = 4; - TwainScanComplete scanComplete = 5; } } @@ -141,6 +140,3 @@ message TwainMemoryBuffer { int32 yOffset = 5; int32 bytesPerRow = 6; } - -message TwainScanComplete { -} diff --git a/NAPS2.Sdk/Remoting/Worker/WorkerServiceAdapter.cs b/NAPS2.Sdk/Remoting/Worker/WorkerServiceAdapter.cs index 30626a7bc..0acd018a9 100644 --- a/NAPS2.Sdk/Remoting/Worker/WorkerServiceAdapter.cs +++ b/NAPS2.Sdk/Remoting/Worker/WorkerServiceAdapter.cs @@ -53,24 +53,34 @@ public class WorkerServiceAdapter { OptionsXml = options.ToXml() }; - var streamingCall = _client.Scan(req, cancellationToken: cancelToken); - while (await streamingCall.ResponseStream.MoveNext()) + try { - var resp = streamingCall.ResponseStream.Current; - RemotingHelper.HandleErrors(resp.Error); - if (resp.PageStart != null) + var streamingCall = _client.Scan(req, cancellationToken: cancelToken); + while (await streamingCall.ResponseStream.MoveNext()) { - scanEvents.PageStart(); + var resp = streamingCall.ResponseStream.Current; + RemotingHelper.HandleErrors(resp.Error); + if (resp.PageStart != null) + { + scanEvents.PageStart(); + } + if (resp.Progress != null) + { + scanEvents.PageProgress(resp.Progress.Value); + } + if (resp.Image != null) + { + var renderableImage = SerializedImageHelper.Deserialize(scanningContext, resp.Image, + new SerializedImageHelper.DeserializeOptions()); + imageCallback?.Invoke(renderableImage, resp.Image.RenderedFilePath); + } } - if (resp.Progress != null) + } + catch (RpcException ex) + { + if (ex.Status.StatusCode != StatusCode.Cancelled) { - scanEvents.PageProgress(resp.Progress.Value); - } - if (resp.Image != null) - { - var renderableImage = SerializedImageHelper.Deserialize(scanningContext, resp.Image, - new SerializedImageHelper.DeserializeOptions()); - imageCallback?.Invoke(renderableImage, resp.Image.RenderedFilePath); + throw; } } } @@ -121,22 +131,32 @@ public class WorkerServiceAdapter { OptionsXml = options.ToXml() }; - var streamingCall = _client.TwainScan(req, cancellationToken: cancelToken); - while (await streamingCall.ResponseStream.MoveNext()) + try { - var resp = streamingCall.ResponseStream.Current; - RemotingHelper.HandleErrors(resp.Error); - if (resp.PageStart != null) + var streamingCall = _client.TwainScan(req, cancellationToken: cancelToken); + while (await streamingCall.ResponseStream.MoveNext()) { - twainEvents.PageStart(resp.PageStart); + var resp = streamingCall.ResponseStream.Current; + RemotingHelper.HandleErrors(resp.Error); + if (resp.PageStart != null) + { + twainEvents.PageStart(resp.PageStart); + } + if (resp.NativeImage != null) + { + twainEvents.NativeImageTransferred(resp.NativeImage); + } + if (resp.MemoryBuffer != null) + { + twainEvents.MemoryBufferTransferred(resp.MemoryBuffer); + } } - if (resp.NativeImage != null) + } + catch (RpcException ex) + { + if (ex.Status.StatusCode != StatusCode.Cancelled) { - twainEvents.NativeImageTransferred(resp.NativeImage); - } - if (resp.MemoryBuffer != null) - { - twainEvents.MemoryBufferTransferred(resp.MemoryBuffer); + throw; } } } diff --git a/NAPS2.Sdk/Remoting/Worker/WorkerServiceImpl.cs b/NAPS2.Sdk/Remoting/Worker/WorkerServiceImpl.cs index a170ab112..aa31e813d 100644 --- a/NAPS2.Sdk/Remoting/Worker/WorkerServiceImpl.cs +++ b/NAPS2.Sdk/Remoting/Worker/WorkerServiceImpl.cs @@ -6,6 +6,7 @@ using NAPS2.ImportExport.Email.Mapi; using NAPS2.ImportExport.Pdf; using NAPS2.Scan; using NAPS2.Scan.Internal; +using NAPS2.Scan.Internal.Twain; using NAPS2.Scan.Wia; using NAPS2.Wia; using NAPS2.Serialization; @@ -22,13 +23,15 @@ public class WorkerServiceImpl : WorkerService.WorkerServiceBase private readonly AutoResetEvent _ongoingCallFinished = new(false); private int _ongoingCallCount; - public WorkerServiceImpl(ScanningContext scanningContext, ThumbnailRenderer thumbnailRenderer, IMapiWrapper mapiWrapper) + public WorkerServiceImpl(ScanningContext scanningContext, ThumbnailRenderer thumbnailRenderer, + IMapiWrapper mapiWrapper) : this(scanningContext, new RemoteScanController(scanningContext), thumbnailRenderer, mapiWrapper) { } - internal WorkerServiceImpl(ScanningContext scanningContext, IRemoteScanController remoteScanController, ThumbnailRenderer thumbnailRenderer, + internal WorkerServiceImpl(ScanningContext scanningContext, IRemoteScanController remoteScanController, + ThumbnailRenderer thumbnailRenderer, IMapiWrapper mapiWrapper) { _scanningContext = scanningContext; @@ -89,7 +92,8 @@ public class WorkerServiceImpl : WorkerService.WorkerServiceBase } } - public override async Task GetDeviceList(GetDeviceListRequest request, ServerCallContext context) + public override async Task GetDeviceList(GetDeviceListRequest request, + ServerCallContext context) { using var callRef = StartCall(); try @@ -107,10 +111,10 @@ public class WorkerServiceImpl : WorkerService.WorkerServiceBase } } - public override async Task Scan(ScanRequest request, IServerStreamWriter responseStream, ServerCallContext context) + public override async Task Scan(ScanRequest request, IServerStreamWriter responseStream, + ServerCallContext context) { using var callRef = StartCall(); - Log.Error("Scan start"); var sequencedWriter = new SequencedWriter(responseStream); try { @@ -148,7 +152,8 @@ public class WorkerServiceImpl : WorkerService.WorkerServiceBase await sequencedWriter.WaitForCompletion(); } - public override async Task SendMapiEmail(SendMapiEmailRequest request, ServerCallContext context) + public override async Task SendMapiEmail(SendMapiEmailRequest request, + ServerCallContext context) { using var callRef = StartCall(); try @@ -166,7 +171,8 @@ public class WorkerServiceImpl : WorkerService.WorkerServiceBase } } - public override async Task RenderThumbnail(RenderThumbnailRequest request, ServerCallContext context) + public override async Task RenderThumbnail(RenderThumbnailRequest request, + ServerCallContext context) { using var callRef = StartCall(); try @@ -229,6 +235,38 @@ public class WorkerServiceImpl : WorkerService.WorkerServiceBase return Task.FromResult(new StopWorkerResponse()); } + public override async Task TwainScan(TwainScanRequest request, + IServerStreamWriter responseStream, ServerCallContext context) + { + using var callRef = StartCall(); + var sequencedWriter = new SequencedWriter(responseStream); + try + { + var twainEvents = new TwainEvents( + pageStart => sequencedWriter.Write(new TwainScanResponse + { + PageStart = pageStart + }), + nativeImage => sequencedWriter.Write(new TwainScanResponse + { + NativeImage = nativeImage + }), + memoryBuffer => sequencedWriter.Write(new TwainScanResponse + { + MemoryBuffer = memoryBuffer + }) + ); + var twainController = new LocalTwainController(); + var options = request.OptionsXml.FromXml(); + await twainController.StartScan(options, twainEvents, context.CancellationToken); + } + catch (Exception e) + { + sequencedWriter.Write(new TwainScanResponse { Error = RemotingHelper.ToError(e) }); + } + await sequencedWriter.WaitForCompletion(); + } + public event EventHandler? OnStop; private CallReference StartCall() => new(this); diff --git a/NAPS2.Sdk/Scan/Internal/ScanBridgeFactory.cs b/NAPS2.Sdk/Scan/Internal/ScanBridgeFactory.cs index 9522be38a..929b99abe 100644 --- a/NAPS2.Sdk/Scan/Internal/ScanBridgeFactory.cs +++ b/NAPS2.Sdk/Scan/Internal/ScanBridgeFactory.cs @@ -3,7 +3,7 @@ internal class ScanBridgeFactory : IScanBridgeFactory { private readonly InProcScanBridge _inProcScanBridge; - private readonly WorkerScanBridge _workerScanBridge; + private readonly WorkerScanBridge _workerScanBridge; // TODO: remove private readonly NetworkScanBridge _networkScanBridge; public ScanBridgeFactory(ScanningContext scanningContext) @@ -27,11 +27,6 @@ internal class ScanBridgeFactory : IScanBridgeFactory // The physical scanner is connected to a different computer, so we connect to a NAPS2 server process over the network return _networkScanBridge; } - if (options.Driver == Driver.Twain && options.TwainOptions.Dsm != TwainDsm.NewX64 && Environment.Is64BitProcess) - { - // 32-bit twain can only be used by a 32-bit process, so we use a separate worker process - return _workerScanBridge; - } return _inProcScanBridge; } } diff --git a/NAPS2.Sdk/Scan/Internal/Twain/ITwainEvents.cs b/NAPS2.Sdk/Scan/Internal/Twain/ITwainEvents.cs index b3dddcd3b..809b5e0e2 100644 --- a/NAPS2.Sdk/Scan/Internal/Twain/ITwainEvents.cs +++ b/NAPS2.Sdk/Scan/Internal/Twain/ITwainEvents.cs @@ -5,8 +5,8 @@ namespace NAPS2.Scan.Internal.Twain; public interface ITwainEvents { void PageStart(TwainPageStart pageStart); - + void NativeImageTransferred(TwainNativeImage nativeImage); - + void MemoryBufferTransferred(TwainMemoryBuffer memoryBuffer); } \ No newline at end of file diff --git a/NAPS2.Sdk/Scan/Internal/Twain/TwainEvents.cs b/NAPS2.Sdk/Scan/Internal/Twain/TwainEvents.cs new file mode 100644 index 000000000..2122a8029 --- /dev/null +++ b/NAPS2.Sdk/Scan/Internal/Twain/TwainEvents.cs @@ -0,0 +1,33 @@ +using NAPS2.Remoting.Worker; + +namespace NAPS2.Scan.Internal.Twain; + +class TwainEvents : ITwainEvents +{ + private readonly Action _pageStartCallback; + private readonly Action _nativeImageCallback; + private readonly Action _memoryBufferCallback; + + public TwainEvents(Action pageStartCallback, Action nativeImageCallback, + Action memoryBufferCallback) + { + _pageStartCallback = pageStartCallback; + _nativeImageCallback = nativeImageCallback; + _memoryBufferCallback = memoryBufferCallback; + } + + public void PageStart(TwainPageStart pageStart) + { + _pageStartCallback(pageStart); + } + + public void NativeImageTransferred(TwainNativeImage nativeImage) + { + _nativeImageCallback(nativeImage); + } + + public void MemoryBufferTransferred(TwainMemoryBuffer memoryBuffer) + { + _memoryBufferCallback(memoryBuffer); + } +} \ No newline at end of file diff --git a/NAPS2.Sdk/Scan/Internal/WorkerScanBridge.cs b/NAPS2.Sdk/Scan/Internal/WorkerScanBridge.cs index 27250f254..f4d7a6a78 100644 --- a/NAPS2.Sdk/Scan/Internal/WorkerScanBridge.cs +++ b/NAPS2.Sdk/Scan/Internal/WorkerScanBridge.cs @@ -24,17 +24,7 @@ internal class WorkerScanBridge : IScanBridge public async Task Scan(ScanOptions options, CancellationToken cancelToken, IScanEvents scanEvents, Action callback) { using var ctx = _scanningContext.WorkerFactory.Create(); - try - { - await ctx.Service.Scan(_scanningContext, options, cancelToken, scanEvents, - (image, tempPath) => { callback(image, new PostProcessingContext { TempPath = tempPath }); }); - } - catch (RpcException ex) - { - if (ex.Status.StatusCode != StatusCode.Cancelled) - { - throw; - } - } + await ctx.Service.Scan(_scanningContext, options, cancelToken, scanEvents, + (image, tempPath) => { callback(image, new PostProcessingContext { TempPath = tempPath }); }); } } \ No newline at end of file