mirror of
https://github.com/cyanfish/naps2.git
synced 2024-11-11 02:45:19 +03:00
Simplifying dependencies wip
This commit is contained in:
parent
cf13a81afc
commit
0d8f393bc1
@ -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();
|
||||
|
@ -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" />
|
||||
|
64
NAPS2.Sdk.Samples/FileStorageSample.cs
Normal file
64
NAPS2.Sdk.Samples/FileStorageSample.cs
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -44,6 +44,7 @@
|
||||
<Reference Include="System.Xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="FileStorageSample.cs" />
|
||||
<Compile Include="ScanToBitmapSample.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
</ItemGroup>
|
||||
|
@ -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
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
23
NAPS2.Sdk/Images/BlankDetector.cs
Normal file
23
NAPS2.Sdk/Images/BlankDetector.cs
Normal 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);
|
||||
}
|
||||
}
|
@ -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)
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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">
|
||||
|
@ -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
|
||||
|
30
NAPS2.Sdk/Operation/StubOperationProgress.cs
Normal file
30
NAPS2.Sdk/Operation/StubOperationProgress.cs
Normal 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();
|
||||
}
|
||||
}
|
@ -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;
|
||||
|
@ -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 () =>
|
||||
{
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
{
|
||||
|
@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
Loading…
Reference in New Issue
Block a user