Finish implementing TwainScan worker method

This commit is contained in:
Ben Olden-Cooligan 2022-06-29 17:06:34 -07:00
parent a7ccd947df
commit b6fd79c4e3
7 changed files with 129 additions and 57 deletions

View File

@ -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 {
}

View File

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

View File

@ -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<GetDeviceListResponse> GetDeviceList(GetDeviceListRequest request, ServerCallContext context)
public override async Task<GetDeviceListResponse> 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<ScanResponse> responseStream, ServerCallContext context)
public override async Task Scan(ScanRequest request, IServerStreamWriter<ScanResponse> responseStream,
ServerCallContext context)
{
using var callRef = StartCall();
Log.Error("Scan start");
var sequencedWriter = new SequencedWriter<ScanResponse>(responseStream);
try
{
@ -148,7 +152,8 @@ public class WorkerServiceImpl : WorkerService.WorkerServiceBase
await sequencedWriter.WaitForCompletion();
}
public override async Task<SendMapiEmailResponse> SendMapiEmail(SendMapiEmailRequest request, ServerCallContext context)
public override async Task<SendMapiEmailResponse> SendMapiEmail(SendMapiEmailRequest request,
ServerCallContext context)
{
using var callRef = StartCall();
try
@ -166,7 +171,8 @@ public class WorkerServiceImpl : WorkerService.WorkerServiceBase
}
}
public override async Task<RenderThumbnailResponse> RenderThumbnail(RenderThumbnailRequest request, ServerCallContext context)
public override async Task<RenderThumbnailResponse> 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<TwainScanResponse> responseStream, ServerCallContext context)
{
using var callRef = StartCall();
var sequencedWriter = new SequencedWriter<TwainScanResponse>(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<ScanOptions>();
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);

View File

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

View File

@ -5,8 +5,8 @@ namespace NAPS2.Scan.Internal.Twain;
public interface ITwainEvents
{
void PageStart(TwainPageStart pageStart);
void NativeImageTransferred(TwainNativeImage nativeImage);
void MemoryBufferTransferred(TwainMemoryBuffer memoryBuffer);
}

View File

@ -0,0 +1,33 @@
using NAPS2.Remoting.Worker;
namespace NAPS2.Scan.Internal.Twain;
class TwainEvents : ITwainEvents
{
private readonly Action<TwainPageStart> _pageStartCallback;
private readonly Action<TwainNativeImage> _nativeImageCallback;
private readonly Action<TwainMemoryBuffer> _memoryBufferCallback;
public TwainEvents(Action<TwainPageStart> pageStartCallback, Action<TwainNativeImage> nativeImageCallback,
Action<TwainMemoryBuffer> 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);
}
}

View File

@ -24,17 +24,7 @@ internal class WorkerScanBridge : IScanBridge
public async Task Scan(ScanOptions options, CancellationToken cancelToken, IScanEvents scanEvents, Action<ProcessedImage, PostProcessingContext> 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 }); });
}
}