Simplifying dependencies wip

This commit is contained in:
Ben Olden-Cooligan 2018-12-03 20:12:20 -05:00
parent cf13a81afc
commit 0d8f393bc1
28 changed files with 295 additions and 143 deletions

View File

@ -61,8 +61,7 @@ namespace NAPS2.DI.Modules
Bind<EmailSettingsContainer>().ToSelf().InSingletonScope();
// Host
Bind<IWorkerServiceFactory>().To<NinjectWorkerServiceFactory>();
Bind<WorkerContext>().ToMethod(ctx => WorkerManager.NextWorker());
Bind<IWorkerServiceFactory>().ToMethod(ctx => WorkerManager.Factory);
// Misc
Bind<IFormFactory>().To<NinjectFormFactory>();
@ -71,7 +70,7 @@ namespace NAPS2.DI.Modules
Bind<ILogger>().To<NLogLogger>().InSingletonScope();
Bind<ChangeTracker>().ToSelf().InSingletonScope();
Bind<StillImage>().ToSelf().InSingletonScope();
Bind<IBlankDetector>().To<ThresholdBlankDetector>();
Bind<BlankDetector>().To<ThresholdBlankDetector>();
Bind<IAutoSave>().To<AutoSave>();
StaticConfiguration.Initialize();

View File

@ -90,7 +90,6 @@
<Compile Include="NinjectFormFactory.cs" />
<Compile Include="NinjectOperationFactory.cs" />
<Compile Include="NinjectScanDriverFactory.cs" />
<Compile Include="NinjectWorkerServiceFactory.cs" />
<Compile Include="NLogLogger.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="EntryPoints\WinFormsEntryPoint.cs" />

View File

@ -0,0 +1,64 @@
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Threading.Tasks;
using NAPS2.Images;
using NAPS2.Images.Storage;
using NAPS2.Scan;
using NAPS2.Scan.Wia;
namespace NAPS2.Sdk.Samples
{
public class FileStorageSample
{
public static async Task Run()
{
StorageManager.ConfigureImageType<GdiImage>();
// To save memory, we can store scanned images on disk after initial processing.
// This will put files in the system temp folder by default, which can be
// overriden by changing FileStorageManager.Current.
ScannedImage.ConfigureBackingStorage<IFileStorage>();
IScanDriver driver = new WiaScanDriver();
ScanDevice device = driver.GetDeviceList().First();
driver.ScanProfile = new ScanProfile
{
Device = device,
Resolution = ScanDpi.Dpi300
};
driver.ScanParams = new ScanParams
{
NoUI = true
};
// We can wait for the entire scan to complete and not worry about using an
// excessive amount of memory, since it is all stored on disk until rendered.
// This is just for illustration purposes; in real code you usually want to
// process images as they come rather than waiting for the full scan.
List<ScannedImage> images = await driver.Scan().ToList();
try
{
BitmapRenderer renderer = new BitmapRenderer();
foreach (var image in images)
{
// This seamlessly loads the image data from disk.
using (Bitmap bitmap = await renderer.Render(image))
{
// TODO: Do something with the bitmap
}
}
}
finally
{
foreach (var image in images)
{
// This cleanly deletes any data from the filesystem.
image.Dispose();
}
}
}
}
}

View File

@ -44,6 +44,7 @@
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="FileStorageSample.cs" />
<Compile Include="ScanToBitmapSample.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>

View File

@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Threading.Tasks;
using NAPS2.Images;
using NAPS2.Images.Storage;
using NAPS2.Scan;
@ -11,17 +12,11 @@ namespace NAPS2.Sdk.Samples
{
public class ScanToBitmapSample
{
public static async IAsyncEnumerable<Bitmap> Run()
public static async Task Run()
{
// TODO: Configure image factory.
// We configure scanned images to be stored in GDI+ format.
// This uses System.Drawing.Bitmap internally.
ScannedImage.ConfigureBackingStorage<GdiImage>();
// TODO: Put this in another sample.
// Alternatively, we could store images on disk to save memory.
// This would put files in the system temp folder by default,
// which can be overriden by changing FileStorageManager.Current.
// ScannedImage.ConfigureBackingStorage<IFileStorage>();
StorageManager.ConfigureImageType<GdiImage>();
// To select a device and scan, you need a driver.
// Windows supports Wia and Twain. Linux supports Sane. Mac supports Twain.
@ -39,7 +34,7 @@ namespace NAPS2.Sdk.Samples
Device = device,
Resolution = ScanDpi.Dpi300
};
// Configure meta scanning options
driver.ScanParams = new ScanParams
{
@ -55,13 +50,16 @@ namespace NAPS2.Sdk.Samples
// However, in other situations this abstracts away additional I/O or transforms.
BitmapRenderer renderer = new BitmapRenderer();
// Using the new C# 8.0 language features and IAsyncEnumerable allows this to be
// done cleanly and fully asynchronously.
await foreach (ScannedImage image in imageSource.AsAsyncEnumerable())
// ScannedImageSource has several different methods to help you consume images.
// ForEach allows you to asynchronously process images as they arrive.
await imageSource.ForEach(async image =>
{
Bitmap bitmap = await renderer.Render(image);
yield return bitmap;
}
using (image)
using (Bitmap bitmap = await renderer.Render(image))
{
// TODO: Do something with the bitmap
}
});
}
}
}

View File

@ -1,12 +1,9 @@
using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using NAPS2.Logging;
using NAPS2.Recovery;
using NAPS2.Scan;
using NAPS2.Images;
using NAPS2.Util;
@ -23,7 +20,6 @@ namespace NAPS2.ClientServer
private readonly IFormFactory formFactory;
public ProxiedScanDriver(ClientContextFactory clientContextFactory, IFormFactory formFactory, ScannedImageHelper scannedImageHelper)
: base(formFactory)
{
this.clientContextFactory = clientContextFactory;
this.formFactory = formFactory;

View File

@ -0,0 +1,23 @@
using System;
using System.Collections.Generic;
using System.Linq;
using NAPS2.Images.Storage;
using NAPS2.Scan;
namespace NAPS2.Images
{
public abstract class BlankDetector
{
private static BlankDetector _default = new ThresholdBlankDetector();
public static BlankDetector Default
{
get => _default;
set => _default = value ?? throw new ArgumentNullException(nameof(value));
}
public abstract bool IsBlank(IImage image, int whiteThresholdNorm, int coverageThresholdNorm);
public abstract bool ExcludePage(IImage image, ScanProfile scanProfile);
}
}

View File

@ -13,11 +13,15 @@ namespace NAPS2.Images
{
public class DeskewOperation : OperationBase
{
private readonly ScannedImageRenderer scannedImageRenderer;
private readonly ImageRenderer imageRenderer;
public DeskewOperation(ScannedImageRenderer scannedImageRenderer)
public DeskewOperation() : this(new ImageRenderer())
{
this.scannedImageRenderer = scannedImageRenderer;
}
public DeskewOperation(ImageRenderer imageRenderer)
{
this.imageRenderer = imageRenderer;
AllowCancel = true;
AllowBackground = true;
@ -42,7 +46,7 @@ namespace NAPS2.Images
return null;
}
memoryLimitingSem.WaitOne();
var bitmap = scannedImageRenderer.Render(img).Result;
var bitmap = imageRenderer.Render(img).Result;
try
{
if (CancelToken.IsCancellationRequested)

View File

@ -1,15 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using NAPS2.Images.Storage;
using NAPS2.Scan;
namespace NAPS2.Images
{
public interface IBlankDetector
{
bool IsBlank(IImage image, int whiteThresholdNorm, int coverageThresholdNorm);
bool ExcludePage(IImage image, ScanProfile scanProfile);
}
}

View File

@ -17,7 +17,7 @@ namespace NAPS2.Images
BackingStorageType = typeof(TStorage);
}
public static Type BackingStorageType { get; private set; } = typeof(IImage);
public static Type BackingStorageType { get; private set; } = typeof(IStorage);
private IImage thumbnail;
private int thumbnailState;

View File

@ -102,18 +102,30 @@ namespace NAPS2.Images
}
return tempFilePath;
}
private readonly IOperationFactory operationFactory;
private readonly IOperationProgress operationProgress;
private readonly OcrRequestQueue ocrRequestQueue;
private readonly OcrManager ocrManager;
private readonly BlankDetector blankDetector;
public ScannedImageHelper(IOperationFactory operationFactory, IOperationProgress operationProgress, OcrRequestQueue ocrRequestQueue, OcrManager ocrManager)
public ScannedImageHelper() : this(new StubOperationProgress())
{
}
public ScannedImageHelper(IOperationProgress operationProgress)
{
this.operationProgress = operationProgress;
if (OcrManager.HasDefault)
{
ocrRequestQueue = new OcrRequestQueue(OcrManager.Default, operationProgress);
}
blankDetector = BlankDetector.Default;
}
public ScannedImageHelper(IOperationProgress operationProgress, OcrRequestQueue ocrRequestQueue, BlankDetector blankDetector)
{
this.operationFactory = operationFactory;
this.operationProgress = operationProgress;
this.ocrRequestQueue = ocrRequestQueue;
this.ocrManager = ocrManager;
this.blankDetector = blankDetector;
}
public IImage PostProcessStep1(IImage output, ScanProfile profile, bool supportsNativeUI = true)
@ -123,8 +135,7 @@ namespace NAPS2.Images
{
scaleFactor = profile.AfterScanScale.ToIntScaleFactor();
}
// TODO: Scale
var result = output;//ImageScaleHelper.ScaleImage(output, scaleFactor);
var result = Transform.Perform(output, new ScaleTransform(scaleFactor));
if ((!profile.UseNativeUI || !supportsNativeUI) && (profile.ForcePageSize || profile.ForcePageSizeCrop))
{
@ -202,7 +213,7 @@ namespace NAPS2.Images
}
if (profile.AutoDeskew)
{
var op = operationFactory.Create<DeskewOperation>();
var op = new DeskewOperation();
if (op.Start(new[] { scannedImage }))
{
operationProgress.ShowProgress(op);
@ -217,7 +228,11 @@ namespace NAPS2.Images
public bool ShouldDoBackgroundOcr(ScanParams scanParams)
{
bool ocrEnabled = ocrManager.DefaultParams != null;
if (ocrRequestQueue == null)
{
return false;
}
bool ocrEnabled = OcrManager.Default.DefaultParams != null;
bool afterScanning = AppConfig.Current.OcrState == OcrState.Enabled && AppConfig.Current.OcrDefaultAfterScanning
|| AppConfig.Current.OcrState == OcrState.UserConfig &&
(UserConfig.Current.OcrAfterScanning ?? AppConfig.Current.OcrDefaultAfterScanning);
@ -263,5 +278,23 @@ namespace NAPS2.Images
scannedImage.SetThumbnail(Transform.Perform(image, new ThumbnailTransform()));
}
}
public ScannedImage PostProcess(IImage output, int pageNumber, ScanProfile scanProfile, ScanParams scanParams)
{
using (var result = PostProcessStep1(output, scanProfile))
{
if (blankDetector.ExcludePage(result, scanProfile))
{
return null;
}
ScanBitDepth bitDepth = scanProfile.UseNativeUI ? ScanBitDepth.C24Bit : scanProfile.BitDepth;
var image = new ScannedImage(result, bitDepth, scanProfile.MaxQuality, scanProfile.Quality);
PostProcessStep2(image, result, scanProfile, scanParams, pageNumber);
string tempPath = SaveForBackgroundOcr(result, scanParams);
RunBackgroundOcr(image, scanParams, tempPath);
return image;
}
}
}
}

View File

@ -15,7 +15,18 @@ namespace NAPS2.Images
public async Task<List<ScannedImage>> ToList()
{
var list = new List<ScannedImage>();
await ForEach(image => list.Add(image));
try
{
await ForEach(image => list.Add(image));
}
catch (Exception)
{
foreach (var image in list)
{
image.Dispose();
}
throw;
}
return list;
}
@ -28,6 +39,15 @@ namespace NAPS2.Images
}
}
public async Task ForEach(Func<ScannedImage, Task> action)
{
ScannedImage image;
while ((image = await Next()) != null)
{
await action(image);
}
}
public ScannedImageSource Then(Action<ScannedImage> action)
{
return new ThenSource(this, action);

View File

@ -12,7 +12,8 @@ namespace NAPS2.Images.Storage
static GdiImage()
{
StorageManager.RegisterConverters(new GdiConverters());
Transform.RegisterTransformers(typeof(GdiImage), new GdiTransformers());
StorageManager.RegisterImageFactory<GdiImage>(new GdiImageFactory());
Transform.RegisterTransformers<GdiImage>(new GdiTransformers());
}
public GdiImage(Bitmap bitmap)

View File

@ -2,15 +2,35 @@
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using NAPS2.Util;
namespace NAPS2.Images.Storage
{
public static class StorageManager
{
// TODO: Have this been configured elsewhere. Also make it a single LOC to configure.
public static Type PreferredImageType { get; set; } = typeof(GdiImage);
static StorageManager()
{
// TODO: Maybe not?
ConfigureImageType<GdiImage>();
}
public static IImageFactory ImageFactory { get; set; } = new GdiImageFactory();
public static void RegisterImageFactory<TImage>(IImageFactory factory) where TImage : IImage
{
ImageFactories[typeof(TImage)] = factory ?? throw new ArgumentNullException(nameof(factory));
}
public static void ConfigureImageType<TImage>() where TImage : IImage
{
RuntimeHelpers.RunClassConstructor(typeof(TImage).TypeHandle);
ImageType = typeof(TImage);
}
public static Type ImageType { get; private set; }
public static IImageFactory ImageFactory => ImageFactories.Get(ImageType) ?? throw new InvalidOperationException($"No factory has been registered for the image type {ImageType.FullName}.");
private static readonly Dictionary<Type, IImageFactory> ImageFactories = new Dictionary<Type, IImageFactory>();
public static IImageMetadataFactory ImageMetadataFactory { get; set; }
@ -40,7 +60,7 @@ namespace NAPS2.Images.Storage
{
return image;
}
return (IImage)Convert(storage, PreferredImageType, convertParams);
return (IImage)Convert(storage, ImageType, convertParams);
}
public static TStorage Convert<TStorage>(IStorage storage)

View File

@ -1,7 +1,5 @@
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.Linq;
using System.Runtime.InteropServices;
using NAPS2.Images.Storage;
@ -9,7 +7,7 @@ using NAPS2.Scan;
namespace NAPS2.Images
{
public class ThresholdBlankDetector : IBlankDetector
public class ThresholdBlankDetector : BlankDetector
{
// If the pixel value (0-255) >= white_threshold, then it counts as a white pixel.
private const int WHITE_THRESHOLD_MIN = 1;
@ -18,7 +16,7 @@ namespace NAPS2.Images
private const double COVERAGE_THRESHOLD_MIN = 0.00;
private const double COVERAGE_THRESHOLD_MAX = 0.01;
public bool IsBlank(IImage image, int whiteThresholdNorm, int coverageThresholdNorm)
public override bool IsBlank(IImage image, int whiteThresholdNorm, int coverageThresholdNorm)
{
if (image.PixelFormat == StoragePixelFormat.BW1)
{
@ -71,7 +69,7 @@ namespace NAPS2.Images
return coverage < coverageThreshold;
}
public bool ExcludePage(IImage image, ScanProfile scanProfile)
public override bool ExcludePage(IImage image, ScanProfile scanProfile)
{
return scanProfile.ExcludeBlankPages && IsBlank(image, scanProfile.BlankPageWhiteThreshold, scanProfile.BlankPageCoverageThreshold);
}

View File

@ -22,14 +22,9 @@ namespace NAPS2.Images.Transforms
/// Enumerates all methods on transformerObj that have a TransformerAttribute and registers them
/// for future use in Transform.Perform and Transform.PerformAll with the specified image type.
/// </summary>
/// <param name="imageType"></param>
/// <param name="transformerObj"></param>
public static void RegisterTransformers(Type imageType, object transformerObj)
public static void RegisterTransformers<TImage>(object transformerObj) where TImage : IImage
{
if (!typeof(IImage).IsAssignableFrom(imageType))
{
throw new ArgumentException($"The image type must implement {nameof(IImage)}.", nameof(imageType));
}
foreach (var method in transformerObj.GetType().GetMethods().Where(x => x.GetCustomAttributes(typeof(TransformerAttribute), true).Any()))
{
var methodParams = method.GetParameters();
@ -37,10 +32,10 @@ namespace NAPS2.Images.Transforms
var transformType = methodParams[1].ParameterType;
if (methodParams.Length == 2 &&
typeof(IImage).IsAssignableFrom(method.ReturnType) &&
storageType.IsAssignableFrom(imageType) &&
storageType.IsAssignableFrom(typeof(TImage)) &&
typeof(Transform).IsAssignableFrom(transformType))
{
Transformers.Add((imageType, transformType), (transformerObj, method));
Transformers[(typeof(TImage), transformType)] = (transformerObj, method);
}
}
}

View File

@ -187,6 +187,7 @@
<Compile Include="Ocr\Tesseract304Engine.cs" />
<Compile Include="Ocr\Tesseract302Engine.cs" />
<Compile Include="Operation\OperationProgressType.cs" />
<Compile Include="Operation\StubOperationProgress.cs" />
<Compile Include="Platform\ISystemCompat.cs" />
<Compile Include="Platform\LinuxSystemCompat.cs" />
<Compile Include="Platform\PlatformCompat.cs" />
@ -361,7 +362,7 @@
<Compile Include="Scan\Batch\BatchScanPerformer.cs" />
<Compile Include="Scan\Batch\BatchSettings.cs" />
<Compile Include="Scan\Exceptions\NoDuplexSupportException.cs" />
<Compile Include="Images\IBlankDetector.cs" />
<Compile Include="Images\BlankDetector.cs" />
<Compile Include="Images\ThresholdBlankDetector.cs" />
<Compile Include="Images\Transforms\BlackWhiteTransform.cs" />
<Compile Include="Images\Transforms\ColorHelper.cs" />
@ -773,6 +774,7 @@
<Compile Include="WinForms\WinFormsOverwritePrompt.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="Worker\WorkerServiceFactory.cs" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="ClientCreds.resx">

View File

@ -11,6 +11,8 @@ namespace NAPS2.Ocr
private static OcrManager _default;
public static bool HasDefault => _default != null;
public static OcrManager Default
{
// TODO: Verify package info

View File

@ -0,0 +1,30 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;
namespace NAPS2.Operation
{
public class StubOperationProgress : IOperationProgress
{
public void Attach(IOperation op)
{
}
public void ShowProgress(IOperation op)
{
}
public void ShowModalProgress(IOperation op)
{
}
public void ShowBackgroundProgress(IOperation op)
{
}
public void RenderStatus(IOperation op, Label textLabel, Label numberLabel, ProgressBar progressBar) => throw new NotSupportedException();
public List<IOperation> ActiveOperations => throw new NotSupportedException();
}
}

View File

@ -26,11 +26,10 @@ namespace NAPS2.Scan.Sane
private readonly SaneWrapper saneWrapper;
private readonly IFormFactory formFactory;
private readonly IBlankDetector blankDetector;
private readonly BlankDetector blankDetector;
private readonly ScannedImageHelper scannedImageHelper;
public SaneScanDriver(SaneWrapper saneWrapper, IFormFactory formFactory, IBlankDetector blankDetector, ScannedImageHelper scannedImageHelper)
: base(formFactory)
public SaneScanDriver(SaneWrapper saneWrapper, IFormFactory formFactory, BlankDetector blankDetector, ScannedImageHelper scannedImageHelper)
{
this.saneWrapper = saneWrapper;
this.formFactory = formFactory;

View File

@ -17,13 +17,6 @@ namespace NAPS2.Scan
/// </summary>
public abstract class ScanDriverBase : IScanDriver
{
private readonly IFormFactory formFactory;
protected ScanDriverBase(IFormFactory formFactory)
{
this.formFactory = formFactory;
}
public abstract string DriverName { get; }
public abstract bool IsSupported { get; }
@ -71,8 +64,10 @@ namespace NAPS2.Scan
throw new NoDevicesFoundException();
}
var form = formFactory.Create<FSelectDevice>();
form.DeviceList = deviceList;
var form = new FSelectDevice
{
DeviceList = deviceList
};
form.ShowDialog();
return form.SelectedDevice;
}
@ -121,7 +116,7 @@ namespace NAPS2.Scan
{
throw new InvalidOperationException("IScanDriver.DialogParent must be specified before calling Scan() without NoUI.");
}
var source = new ScannedImageSource.Concrete();
Task.Factory.StartNew(async () =>
{

View File

@ -5,7 +5,6 @@ using System.Threading.Tasks;
using NAPS2.Platform;
using NAPS2.Images;
using NAPS2.Util;
using NAPS2.WinForms;
using NAPS2.Worker;
namespace NAPS2.Scan.Twain
@ -18,8 +17,7 @@ namespace NAPS2.Scan.Twain
private readonly TwainWrapper twainWrapper;
private readonly ScannedImageHelper scannedImageHelper;
public TwainScanDriver(IWorkerServiceFactory workerServiceFactory, TwainWrapper twainWrapper, IFormFactory formFactory, ScannedImageHelper scannedImageHelper)
: base(formFactory)
public TwainScanDriver(IWorkerServiceFactory workerServiceFactory, TwainWrapper twainWrapper, ScannedImageHelper scannedImageHelper)
{
this.workerServiceFactory = workerServiceFactory;
this.twainWrapper = twainWrapper;

View File

@ -25,7 +25,7 @@ namespace NAPS2.Scan.Twain
private static readonly TWIdentity TwainAppId = TWIdentity.CreateFromAssembly(DataGroups.Image | DataGroups.Control, Assembly.GetEntryAssembly());
private readonly IFormFactory formFactory;
private readonly IBlankDetector blankDetector;
private readonly BlankDetector blankDetector;
private readonly ScannedImageHelper scannedImageHelper;
static TwainWrapper()
@ -46,7 +46,7 @@ namespace NAPS2.Scan.Twain
#endif
}
public TwainWrapper(IFormFactory formFactory, IBlankDetector blankDetector, ScannedImageHelper scannedImageHelper)
public TwainWrapper(IFormFactory formFactory, BlankDetector blankDetector, ScannedImageHelper scannedImageHelper)
{
this.formFactory = formFactory;
this.blankDetector = blankDetector;

View File

@ -8,22 +8,28 @@ using NAPS2.Scan.Exceptions;
using NAPS2.Images;
using NAPS2.Scan.Wia.Native;
using NAPS2.Util;
using NAPS2.WinForms;
namespace NAPS2.Scan.Wia
{
public class WiaScanDriver : ScanDriverBase
{
public const string DRIVER_NAME = "wia";
private readonly IOperationFactory operationFactory;
private readonly IOperationProgress operationProgress;
private readonly ScannedImageHelper scannedImageHelper;
public WiaScanDriver(IFormFactory formFactory, IOperationFactory operationFactory, IOperationProgress operationProgress)
: base(formFactory)
public WiaScanDriver() : this(new StubOperationProgress())
{
}
public WiaScanDriver(IOperationProgress operationProgress) : this(operationProgress, new ScannedImageHelper(operationProgress))
{
}
public WiaScanDriver(IOperationProgress operationProgress, ScannedImageHelper scannedImageHelper)
{
this.operationFactory = operationFactory;
this.operationProgress = operationProgress;
this.scannedImageHelper = scannedImageHelper;
}
public override string DriverName => DRIVER_NAME;
@ -69,7 +75,7 @@ namespace NAPS2.Scan.Wia
protected override async Task ScanInternal(ScannedImageSource.Concrete source)
{
var op = operationFactory.Create<WiaScanOperation>();
var op = new WiaScanOperation(scannedImageHelper);
using (CancelToken.Register(op.Cancel))
{
op.Start(ScanProfile, ScanParams, DialogParent, source);

View File

@ -1,7 +1,5 @@
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Linq;
using System.Windows.Forms;
@ -20,15 +18,21 @@ namespace NAPS2.Scan.Wia
public class WiaScanOperation : OperationBase
{
private readonly ScannedImageHelper scannedImageHelper;
private readonly IBlankDetector blankDetector;
private readonly IWorkerServiceFactory workerServiceFactory;
private readonly SmoothProgress smoothProgress = new SmoothProgress();
public WiaScanOperation(ScannedImageHelper scannedImageHelper, IBlankDetector blankDetector, IWorkerServiceFactory workerServiceFactory)
public WiaScanOperation() : this(new ScannedImageHelper())
{
}
public WiaScanOperation(ScannedImageHelper scannedImageHelper) : this(scannedImageHelper, WorkerManager.Factory)
{
}
public WiaScanOperation(ScannedImageHelper scannedImageHelper, IWorkerServiceFactory workerServiceFactory)
{
this.scannedImageHelper = scannedImageHelper;
this.blankDetector = blankDetector;
this.workerServiceFactory = workerServiceFactory;
AllowCancel = true;
AllowBackground = true;
@ -140,23 +144,14 @@ namespace NAPS2.Scan.Wia
private void ProduceImage(ScannedImageSource.Concrete source, IImage output, ref int pageNumber)
{
using (var result = scannedImageHelper.PostProcessStep1(output, ScanProfile))
var image = scannedImageHelper.PostProcess(output, pageNumber, ScanProfile, ScanParams);
if (image != null)
{
if (blankDetector.ExcludePage(result, ScanProfile))
{
return;
}
ScanBitDepth bitDepth = ScanProfile.UseNativeUI ? ScanBitDepth.C24Bit : ScanProfile.BitDepth;
var image = new ScannedImage(result, bitDepth, ScanProfile.MaxQuality, ScanProfile.Quality);
scannedImageHelper.PostProcessStep2(image, result, ScanProfile, ScanParams, pageNumber);
string tempPath = scannedImageHelper.SaveForBackgroundOcr(result, ScanParams);
scannedImageHelper.RunBackgroundOcr(image, ScanParams, tempPath);
source.Put(image);
pageNumber++;
InitNextPageProgress(pageNumber);
}
pageNumber++;
InitNextPageProgress(pageNumber);
}
private void DoWia20NativeTransfer(ScannedImageSource.Concrete source, WiaDeviceManager deviceManager, WiaDevice device)

View File

@ -9,6 +9,7 @@ using NAPS2.Util;
namespace NAPS2.WinForms
{
// TODO: Remove UserConfig dependency from reusable forms
public class FormBase : Form, IInvoker
{
private bool loaded;
@ -34,18 +35,7 @@ namespace NAPS2.WinForms
#region Helper Properties
private List<FormState> FormStates
{
get
{
if (UserConfig.Manager == null)
{
// Should only occur with the designer
return new List<FormState>();
}
return UserConfig.Current.FormStates;
}
}
private List<FormState> FormStates => UserConfig.Current.FormStates;
private FormState FormState
{

View File

@ -119,5 +119,14 @@ namespace NAPS2.Worker
StartWorkerService();
}
}
// TODO: This should not be set by default
private static IWorkerServiceFactory _factory = new WorkerServiceFactory();
public static IWorkerServiceFactory Factory
{
get => _factory;
set => _factory = value ?? throw new ArgumentNullException(nameof(value));
}
}
}

View File

@ -2,25 +2,15 @@
using System.Collections.Generic;
using System.Linq;
using System.ServiceModel;
using NAPS2.Recovery;
using NAPS2.Images.Storage;
using NAPS2.Worker;
using Ninject;
namespace NAPS2.DI
namespace NAPS2.Worker
{
public class NinjectWorkerServiceFactory : IWorkerServiceFactory
public class WorkerServiceFactory : IWorkerServiceFactory
{
private readonly IKernel kernel;
public NinjectWorkerServiceFactory(IKernel kernel)
{
this.kernel = kernel;
}
public WorkerContext Create()
{
var worker = kernel.Get<WorkerContext>();
var worker = WorkerManager.NextWorker();
try
{
// TODO: Simplify
@ -29,7 +19,7 @@ namespace NAPS2.DI
catch (EndpointNotFoundException)
{
// Retry once
worker = kernel.Get<WorkerContext>();
worker = WorkerManager.NextWorker();
worker.Service.Init(((RecoveryStorageManager)FileStorageManager.Current).RecoveryFolderPath);
}
return worker;