private async Task GetImagesFromPage(PdfPage page, ImportParams importParams, ScannedImageSource.Concrete source) { if (page.CustomValues.Elements.ContainsKey("/NAPS2ImportedPage")) { source.Put(await ExportRawPdfPage(page, importParams)); return; } // Get resources dictionary var resources = page.Elements.GetDictionary("/Resources"); // Get external objects dictionary var xObjects = resources?.Elements.GetDictionary("/XObject"); if (xObjects == null) { return; } // Iterate references to external objects foreach (var item in xObjects.Elements.Values) { // Is external object an image? if (!((item as PdfReference)?.Value is PdfDictionary xObject) || xObject.Elements.GetString("/Subtype") != "/Image") { continue; } // Support multiple filter schemes var element = xObject.Elements.Single(x => x.Key == "/Filter"); var elementAsArray = element.Value as PdfArray; var elementAsName = element.Value as PdfName; if (elementAsArray != null) { var arrayElements = elementAsArray.Elements.Select(x => x.ToString()).ToArray(); if (arrayElements.Length == 2) { source.Put(DecodeImage(arrayElements[1], page, xObject, Filtering.Decode(xObject.Stream.Value, arrayElements[0]), importParams)); } } else if (elementAsName != null) { source.Put(DecodeImage(elementAsName.Value, page, xObject, xObject.Stream.Value, importParams)); } else { throw new NotImplementedException("Unsupported filter"); } } }
protected override async Task ScanInternal(ScannedImageSource.Concrete source) { await Task.Factory.StartNew(async() => { if (UseWorker) { using (var worker = workerServiceFactory.Create()) { worker.Callback.ImageCallback += (img, tempPath) => { if (tempPath != null) { scannedImageHelper.RunBackgroundOcr(img, ScanParams, tempPath); } source.Put(img); }; CancelToken.Register(worker.Service.CancelTwainScan); await worker.Service.TwainScan(ScanDevice, ScanProfile, ScanParams, DialogParent?.SafeHandle() ?? IntPtr.Zero); } } else { twainWrapper.Scan(DialogParent, ScanDevice, ScanProfile, ScanParams, CancelToken, source, scannedImageHelper.RunBackgroundOcr); } }, TaskCreationOptions.LongRunning).Unwrap(); }
protected override async Task ScanInternal(ScannedImageSource.Concrete source) { using (var eventLoop = new WiaBackgroundEventLoop(ScanProfile, ScanDevice)) { bool supportsFeeder = eventLoop.GetSync(wia => WiaApi.DeviceSupportsFeeder(wia.Device)); if (ScanProfile.PaperSource != ScanSource.Glass && !supportsFeeder) { throw new NoFeederSupportException(); } bool supportsDuplex = eventLoop.GetSync(wia => WiaApi.DeviceSupportsDuplex(wia.Device)); if (ScanProfile.PaperSource == ScanSource.Duplex && !supportsDuplex) { throw new NoDuplexSupportException(); } int pageNumber = 1; int retryCount = 0; bool retry = false; bool done = false; do { ScannedImage image; try { if (pageNumber > 1 && ScanProfile.WiaDelayBetweenScans) { int delay = (int)(ScanProfile.WiaDelayBetweenScansSeconds.Clamp(0, 30) * 1000); Thread.Sleep(delay); } (image, done) = await TransferImage(eventLoop, pageNumber); pageNumber++; retryCount = 0; retry = false; } catch (ScanDriverException e) { if (ScanProfile.WiaRetryOnFailure && e.InnerException is COMException comError && (uint)comError.ErrorCode == 0x80004005 && retryCount < MAX_RETRIES) { Thread.Sleep(1000); retryCount += 1; retry = true; continue; } throw; } if (image != null) { source.Put(image); } } while (!CancelToken.IsCancellationRequested && (retry || !done && ScanProfile.PaperSource != ScanSource.Glass)); } }
public ScannedImageSource Scan() { var source = new ScannedImageSource.Concrete(); Task.Factory.StartNew(() => { for (int i = 0; i < ImageCount; i++) { Thread.Sleep(500); source.Put(MakeImage()); } }, TaskCreationOptions.LongRunning); return(source); }
protected override async Task ScanInternal(ScannedImageSource.Concrete source) { // TODO: Test ADF var options = new Lazy <KeyValueScanOptions>(GetOptions); var pageNumber = 1; var(img, done) = await Transfer(options, pageNumber); if (img != null) { source.Put(img); } if (!done && ScanProfile.PaperSource != ScanSource.Glass) { try { while (true) { (img, done) = await Transfer(options, ++pageNumber); if (done) { break; } if (img != null) { source.Put(img); } } } catch (Exception e) { Log.ErrorException("Error in SANE. This may be a normal ADF termination.", e); } } }
protected override async Task ScanInternal(ScannedImageSource.Concrete source) { await Task.Factory.StartNew(async() => { if (UseWorker) { var parentHandle = DialogParent?.SafeHandle() ?? IntPtr.Zero; try { using (var worker = workerServiceFactory.Create()) { worker.Callback.ImageCallback += (img, tempPath) => { if (tempPath != null) { scannedImageHelper.RunBackgroundOcr(img, ScanParams, tempPath); } source.Put(img); }; CancelToken.Register(worker.Service.CancelTwainScan); await worker.Service.TwainScan(ScanDevice, ScanProfile, ScanParams, parentHandle); } } finally { if (parentHandle != IntPtr.Zero) { // If the worker process hard crashes while a modal window is open, it may leave the parent // window in a state where it can't be interacted with. This fixes that interaction. // // At the Windows API level, a modal window is implemented by doing two things: // 1. Setting the parent on the child window // 2. Disabling the parent window // The first is implicitly undone when the worker process dies. The second is undone here. Win32.EnableWindow(parentHandle, true); } } } else { twainWrapper.Scan(DialogParent, ScanDevice, ScanProfile, ScanParams, CancelToken, source, scannedImageHelper.RunBackgroundOcr); } }, TaskCreationOptions.LongRunning).Unwrap(); }
private void ProduceImage(ScannedImageSource.Concrete source, Image output, ref int pageNumber) { var results = new[] { scannedImageHelper.PostProcessStep1(output, ScanProfile) }; if (ScanProfile.DivideScanIntoTwoPages) { var result = results[0]; // Should probably detect portrait vs landscape and split appropriately but this is the // main use case. var halfHeight = result.Height / 2; var firstRect = new Rectangle(0, 0, result.Width, halfHeight); var secondRect = new Rectangle(0, halfHeight, result.Width, halfHeight); var firstPage = result.Clone(secondRect, result.PixelFormat); firstPage.RotateFlip(RotateFlipType.Rotate90FlipNone); var secondPage = result.Clone(firstRect, result.PixelFormat); secondPage.RotateFlip(RotateFlipType.Rotate90FlipNone); results = new[] { firstPage, secondPage }; result.Dispose(); } foreach (var result in results) { if (blankDetector.ExcludePage(result, ScanProfile)) { continue; } 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); result.Dispose(); scannedImageHelper.RunBackgroundOcr(image, ScanParams, tempPath); source.Put(image); pageNumber++; InitNextPageProgress(pageNumber); } }
private void ProduceImage(ScannedImageSource.Concrete source, Image output, ref int pageNumber) { using (var result = scannedImageHelper.PostProcessStep1(output, ScanProfile)) { 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); } }
public static void Scan(ScanProfile settings, ScanDevice device, IWin32Window pForm, IFormFactory formFactory, ScannedImageSource.Concrete source) { var tw = new Twain(); if (!tw.Init(pForm.Handle)) { throw new DeviceNotFoundException(); } if (!tw.SelectByName(device.ID)) { throw new DeviceNotFoundException(); } var form = formFactory.Create <FTwainGui>(); var mf = new TwainMessageFilter(settings, tw, form); form.ShowDialog(pForm); foreach (var b in mf.Bitmaps) { source.Put(b); } }
public static void Scan(ScanProfile settings, ScanDevice device, IWin32Window pForm, IFormFactory formFactory, ScannedImageSource.Concrete source) { var tw = new Twain(); var windowHandle = (Invoker.Current as Form)?.Handle ?? pForm.Handle; if (!tw.Init(windowHandle)) { throw new DeviceNotFoundException(); } if (!tw.SelectByName(device.Id)) { throw new DeviceNotFoundException(); } var form = Invoker.Current.InvokeGet(formFactory.Create <FTwainGui>); var mf = new TwainMessageFilter(settings, tw, form); Invoker.Current.Invoke(() => form.ShowDialog(pForm)); foreach (var b in mf.Bitmaps) { source.Put(b); } }
public ScannedImageSource Import(string filePath, ImportParams importParams, ProgressHandler progressCallback, CancellationToken cancelToken) { var source = new ScannedImageSource.Concrete(); Task.Factory.StartNew(() => { try { if (cancelToken.IsCancellationRequested) { source.Done(); return; } Bitmap toImport; try { toImport = new Bitmap(filePath); } catch (Exception e) { Log.ErrorException("Error importing image: " + filePath, e); // Handle and notify the user outside the method so that errors importing multiple files can be aggregated throw; } using (toImport) { int frameCount = toImport.GetFrameCount(FrameDimension.Page); int i = 0; foreach (var frameIndex in importParams.Slice.Indices(frameCount)) { progressCallback(i++, frameCount); if (cancelToken.IsCancellationRequested) { source.Done(); return; } toImport.SelectActiveFrame(FrameDimension.Page, frameIndex); var image = new ScannedImage(toImport, ScanBitDepth.C24Bit, IsLossless(toImport.RawFormat), -1); if (!importParams.NoThumbnails) { image.SetThumbnail(thumbnailRenderer.RenderThumbnail(toImport)); } if (importParams.DetectPatchCodes) { image.PatchCode = PatchCodeDetector.Detect(toImport); } source.Put(image); } progressCallback(frameCount, frameCount); } source.Done(); } catch (Exception e) { source.Error(e); } }, TaskCreationOptions.LongRunning); return(source); }
public ScannedImageSource Import(string filePath, ImportParams importParams, ProgressHandler progressCallback, CancellationToken cancelToken) { var source = new ScannedImageSource.Concrete(); Task.Factory.StartNew(async() => { if (cancelToken.IsCancellationRequested) { source.Done(); } int passwordAttempts = 0; bool aborted = false; int i = 0; try { PdfDocument document = PdfReader.Open(filePath, PdfDocumentOpenMode.Import, args => { if (!pdfPasswordProvider.ProvidePassword(Path.GetFileName(filePath), passwordAttempts++, out args.Password)) { args.Abort = true; aborted = true; } }); if (passwordAttempts > 0 && !document.SecuritySettings.HasOwnerPermissions && !document.SecuritySettings.PermitExtractContent) { errorOutput.DisplayError(string.Format(MiscResources.PdfNoPermissionToExtractContent, Path.GetFileName(filePath))); source.Done(); } var pages = importParams.Slice.Indices(document.PageCount) .Select(index => document.Pages[index]) .TakeWhile(page => { progressCallback(i++, document.PageCount); return(!cancelToken.IsCancellationRequested); }); if (document.Info.Creator != MiscResources.NAPS2 && document.Info.Author != MiscResources.NAPS2) { pdfRenderer.ThrowIfCantRender(); foreach (var page in pages) { source.Put(await ExportRawPdfPage(page, importParams)); } } else { foreach (var page in pages) { await GetImagesFromPage(page, importParams, source); } } } catch (ImageRenderException e) { errorOutput.DisplayError(string.Format(MiscResources.ImportErrorNAPS2Pdf, Path.GetFileName(filePath))); Log.ErrorException("Error importing PDF file.", e); } catch (Exception e) { if (!aborted) { errorOutput.DisplayError(string.Format(MiscResources.ImportErrorCouldNot, Path.GetFileName(filePath))); Log.ErrorException("Error importing PDF file.", e); } } finally { source.Done(); } }, TaskCreationOptions.LongRunning); return(source); }
private void InternalScan(TwainImpl twainImpl, IWin32Window dialogParent, ScanDevice scanDevice, ScanProfile scanProfile, ScanParams scanParams, CancellationToken cancelToken, ScannedImageSource.Concrete source, Action <ScannedImage, ScanParams, string> runBackgroundOcr) { if (dialogParent == null) { dialogParent = new BackgroundForm(); } if (twainImpl == TwainImpl.Legacy) { Legacy.TwainApi.Scan(scanProfile, scanDevice, dialogParent, formFactory, source); return; } PlatformInfo.Current.PreferNewDSM = twainImpl != TwainImpl.OldDsm; var session = new TwainSession(TwainAppId); var twainForm = Invoker.Current.InvokeGet(() => scanParams.NoUI ? null : formFactory.Create <FTwainGui>()); Exception error = null; bool cancel = false; DataSource ds = null; var waitHandle = new AutoResetEvent(false); int pageNumber = 0; session.TransferReady += (sender, eventArgs) => { Debug.WriteLine("NAPS2.TW - TransferReady"); if (cancel) { eventArgs.CancelAll = true; } }; session.DataTransferred += (sender, eventArgs) => { try { Debug.WriteLine("NAPS2.TW - DataTransferred"); pageNumber++; using (var output = twainImpl == TwainImpl.MemXfer ? GetBitmapFromMemXFer(eventArgs.MemoryData, eventArgs.ImageInfo) : Image.FromStream(eventArgs.GetNativeImageStream())) { using (var result = scannedImageHelper.PostProcessStep1(output, scanProfile)) { if (blankDetector.ExcludePage(result, scanProfile)) { return; } var bitDepth = output.PixelFormat == PixelFormat.Format1bppIndexed ? ScanBitDepth.BlackWhite : ScanBitDepth.C24Bit; var image = new ScannedImage(result, bitDepth, scanProfile.MaxQuality, scanProfile.Quality); if (scanParams.DetectPatchCodes) { foreach (var patchCodeInfo in eventArgs.GetExtImageInfo(ExtendedImageInfo.PatchCode)) { if (patchCodeInfo.ReturnCode == ReturnCode.Success) { image.PatchCode = GetPatchCode(patchCodeInfo); } } } scannedImageHelper.PostProcessStep2(image, result, scanProfile, scanParams, pageNumber); string tempPath = scannedImageHelper.SaveForBackgroundOcr(result, scanParams); runBackgroundOcr(image, scanParams, tempPath); source.Put(image); } } } catch (Exception ex) { Debug.WriteLine("NAPS2.TW - DataTransferred - Error"); error = ex; cancel = true; StopTwain(); } }; session.TransferError += (sender, eventArgs) => { Debug.WriteLine("NAPS2.TW - TransferError"); if (eventArgs.Exception != null) { error = eventArgs.Exception; } else if (eventArgs.SourceStatus != null) { Log.Error("TWAIN Transfer Error. Return code = {0}; condition code = {1}; data = {2}.", eventArgs.ReturnCode, eventArgs.SourceStatus.ConditionCode, eventArgs.SourceStatus.Data); } else { Log.Error("TWAIN Transfer Error. Return code = {0}.", eventArgs.ReturnCode); } cancel = true; StopTwain(); }; session.SourceDisabled += (sender, eventArgs) => { Debug.WriteLine("NAPS2.TW - SourceDisabled"); StopTwain(); }; void StopTwain() { waitHandle.Set(); if (!scanParams.NoUI) { Invoker.Current.Invoke(() => twainForm.Close()); } } void InitTwain() { try { var windowHandle = (Invoker.Current as Form)?.Handle; ReturnCode rc = windowHandle != null?session.Open(new WindowsFormsMessageLoopHook(windowHandle.Value)) : session.Open(); if (rc != ReturnCode.Success) { Debug.WriteLine("NAPS2.TW - Could not open session - {0}", rc); StopTwain(); return; } ds = session.FirstOrDefault(x => x.Name == scanDevice.ID); if (ds == null) { Debug.WriteLine("NAPS2.TW - Could not find DS - DS count = {0}", session.Count()); throw new DeviceNotFoundException(); } rc = ds.Open(); if (rc != ReturnCode.Success) { Debug.WriteLine("NAPS2.TW - Could not open DS - {0}", rc); StopTwain(); return; } ConfigureDS(ds, scanProfile, scanParams); var ui = scanProfile.UseNativeUI ? SourceEnableMode.ShowUI : SourceEnableMode.NoUI; Debug.WriteLine("NAPS2.TW - Enabling DS"); rc = scanParams.NoUI ? ds.Enable(ui, true, windowHandle ?? IntPtr.Zero) : ds.Enable(ui, true, twainForm.Handle); Debug.WriteLine("NAPS2.TW - Enable finished"); if (rc != ReturnCode.Success) { Debug.WriteLine("NAPS2.TW - Enable failed - {0}, rc"); StopTwain(); } else { cancelToken.Register(() => { Debug.WriteLine("NAPS2.TW - User Cancel"); cancel = true; session.ForceStepDown(5); }); } } catch (Exception ex) { Debug.WriteLine("NAPS2.TW - Error"); error = ex; StopTwain(); } } if (!scanParams.NoUI) { twainForm.Shown += (sender, eventArgs) => { InitTwain(); }; twainForm.Closed += (sender, args) => waitHandle.Set(); } if (scanParams.NoUI) { Debug.WriteLine("NAPS2.TW - Init with no form"); Invoker.Current.Invoke(InitTwain); } else if (!scanParams.Modal) { Debug.WriteLine("NAPS2.TW - Init with non-modal form"); Invoker.Current.Invoke(() => twainForm.Show(dialogParent)); } else { Debug.WriteLine("NAPS2.TW - Init with modal form"); Invoker.Current.Invoke(() => twainForm.ShowDialog(dialogParent)); } waitHandle.WaitOne(); Debug.WriteLine("NAPS2.TW - Operation complete"); if (ds != null && session.IsSourceOpen) { Debug.WriteLine("NAPS2.TW - Closing DS"); ds.Close(); } if (session.IsDsmOpen) { Debug.WriteLine("NAPS2.TW - Closing session"); session.Close(); } if (error != null) { Debug.WriteLine("NAPS2.TW - Throwing error - {0}", error); if (error is ScanDriverException) { throw error; } throw new ScanDriverUnknownException(error); } }
protected override Task ScanInternal(ScannedImageSource.Concrete source) { if (ScanProfile.ProxyConfig == null) { throw new InvalidOperationException("ScanProfile.ProxyConfig must be specified to use ProxiedScanDriver."); } return(Task.Factory.StartNew(async() => { try { using (var client = clientContextFactory.Create(ScanProfile.ProxyConfig)) { var noUi = ScanParams.NoUi; var form = Invoker.Current.InvokeGet(() => noUi ? null : formFactory.Create <FScanProgress>()); var pageNumber = 1; var sem = new Semaphore(0, int.MaxValue); client.Callback.ImageCallback += (imageBytes, indexImage) => { try { indexImage.FileName = RecoveryImage.GetNextFileName() + Path.GetExtension(indexImage.FileName); var recoveryFilePath = Path.Combine(RecoveryImage.RecoveryFolder.FullName, indexImage.FileName); File.WriteAllBytes(recoveryFilePath, imageBytes); var image = new ScannedImage(indexImage); using (var bitmap = new Bitmap(new MemoryStream(imageBytes))) { scannedImageHelper.PostProcessStep2(image, bitmap, ScanProfile, ScanParams, pageNumber++, false); } source.Put(image); if (form != null) { form.PageNumber = pageNumber; Invoker.Current.SafeInvoke(() => form.RefreshStatus()); } } finally { sem.Release(); } }; var scanTask = client.Service.Scan(ScanProfile, ScanParams).ContinueWith(t => { for (var i = 0; i < t.Result; i++) { sem.WaitOne(); } }); if (!noUi) { form.PageNumber = pageNumber; form.AsyncTransfer = async() => await scanTask; form.CancelToken.Register(client.Service.CancelScan); } CancelToken.Register(client.Service.CancelScan); if (noUi) { await scanTask; } else if (ScanParams.Modal) { Invoker.Current.SafeInvoke(() => form.ShowDialog()); } else { Invoker.Current.SafeInvoke(() => form.Show()); await scanTask; } } } catch (Exception e) { Log.ErrorException("Error scanning with proxy", e); } }, TaskCreationOptions.LongRunning).Unwrap()); }