private void DoTransfer(ScannedImageSource.Concrete source, WiaDevice device, WiaItem item) { if (ScanProfile.PaperSource != ScanSource.Glass && !device.SupportsFeeder()) { throw new NoFeederSupportException(); } if (ScanProfile.PaperSource == ScanSource.Duplex && !device.SupportsDuplex()) { throw new NoDuplexSupportException(); } InitProgress(device); ConfigureProps(device, item); using (var transfer = item.StartTransfer()) { int pageNumber = 1; transfer.PageScanned += (sender, args) => { try { using (args.Stream) { if (args.Stream.Length == 0) { return; } using (var output = Image.FromStream(args.Stream)) { ProduceImage(source, output, ref pageNumber); } } } catch (Exception e) { ScanException = e; } }; transfer.Progress += (sender, args) => smoothProgress.InputProgressChanged(args.Percent / 100.0); using (CancelToken.Register(transfer.Cancel)) { transfer.Download(); if (device.Version == WiaVersion.Wia10 && ScanProfile.PaperSource != ScanSource.Glass) { // For WIA 1.0 feeder scans, we need to repeatedly call Download until WIA_ERROR_PAPER_EMPTY is received. try { while (!CancelToken.IsCancellationRequested) { transfer.Download(); } } catch (WiaException e) when(e.ErrorCode == WiaErrorCodes.PAPER_EMPTY) { } } } } }
protected override async Task ScanInternal(ScannedImageSource.Concrete source) { var op = operationFactory.Create <WiaScanOperation>(); using (CancelToken.Register(op.Cancel)) { op.Start(ScanProfile, ScanDevice, ScanParams, DialogParent, source); Invoker.Current.SafeInvoke(() => { if (ScanParams.Modal && !ScanParams.NoUI) { operationProgress.ShowModalProgress(op); } else { operationProgress.ShowBackgroundProgress(op); } }); await op.Success; } if (op.ScanException != null) { op.ScanException.PreserveStackTrace(); throw op.ScanException; } }
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)); } }
private void DoWia20NativeTransfer(ScannedImageSource.Concrete source, WiaDeviceManager deviceManager, WiaDevice device) { // WIA 2.0 doesn't support normal transfers with native UI. // Instead we need to have it write the scans to a set of files and load those. if (DialogParent == null) { DialogParent = new BackgroundForm(); } var hwnd = Invoker.Current.InvokeGet(() => DialogParent.Handle); var paths = deviceManager.PromptForImage(hwnd, device); if (paths == null) { return; } int pageNumber = 1; InitProgress(device); try { foreach (var path in paths) { using (var stream = new FileStream(path, FileMode.Open)) using (var output = Image.FromStream(stream)) { int frameCount = output.GetFrameCount(FrameDimension.Page); for (int i = 0; i < frameCount; i++) { output.SelectActiveFrame(FrameDimension.Page, i); ProduceImage(source, output, ref pageNumber); } } } } finally { foreach (var path in paths) { try { File.Delete(path); } catch (Exception e) { Log.ErrorException("Error deleting WIA 2.0 native transferred file", e); } } } }
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); }
public ScannedImageSource Scan() { if (!IsSupported) { throw new DriverNotSupportedException(); } if (ScanProfile == null) { throw new InvalidOperationException("IScanDriver.ScanProfile must be specified before calling Scan()."); } if (ScanParams == null) { throw new InvalidOperationException("IScanDriver.ScanParams must be specified before calling Scan()."); } if (ScanDevice == null) { throw new InvalidOperationException("IScanDriver.ScanDevice must be specified before calling Scan()."); } if (DialogParent == null && !ScanParams.NoUI) { throw new InvalidOperationException("IScanDriver.DialogParent must be specified before calling Scan() without NoUI."); } var source = new ScannedImageSource.Concrete(); Task.Factory.StartNew(async() => { try { await ScanInternal(source); source.Done(); } catch (ScanDriverException e) { source.Error(e); } catch (FaultException <ScanDriverExceptionDetail> e) { source.Error(e.Detail.Exception); } catch (Exception e) { source.Error(new ScanDriverUnknownException(e)); } }, TaskCreationOptions.LongRunning); return(source); }
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 void Scan(IWin32Window dialogParent, ScanDevice scanDevice, ScanProfile scanProfile, ScanParams scanParams, CancellationToken cancelToken, ScannedImageSource.Concrete source, Action <ScannedImage, ScanParams, string> runBackgroundOcr) { try { InternalScan(scanProfile.TwainImpl, dialogParent, scanDevice, scanProfile, scanParams, cancelToken, source, runBackgroundOcr); } catch (DeviceNotFoundException) { if (scanProfile.TwainImpl == TwainImpl.Default) { // Fall back to OldDsm in case of no devices // This is primarily for Citrix support, which requires using twain_32.dll for TWAIN passthrough InternalScan(TwainImpl.OldDsm, dialogParent, scanDevice, scanProfile, scanParams, cancelToken, source, runBackgroundOcr); } else { throw; } } }
private void Scan(ScannedImageSource.Concrete source) { using (var deviceManager = new WiaDeviceManager(ScanProfile.WiaVersion)) using (var device = deviceManager.FindDevice(ScanProfile.Device.ID)) { if (device.Version == WiaVersion.Wia20 && ScanProfile.UseNativeUI) { DoWia20NativeTransfer(source, deviceManager, device); return; } using (var item = GetItem(device)) { if (item == null) { return; } DoTransfer(source, device, item); } } }
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); } } }
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); } }
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()); }
public bool Start(ScanProfile scanProfile, ScanParams scanParams, IWin32Window dialogParent, ScannedImageSource.Concrete source) { ScanProfile = scanProfile; ScanParams = scanParams; DialogParent = dialogParent; ProgressTitle = ScanProfile.Device?.Name; Status = new OperationStatus { StatusText = ScanProfile.PaperSource == ScanSource.Glass ? MiscResources.AcquiringData : string.Format(MiscResources.ScanProgressPage, 1), MaxProgress = 1000, ProgressType = OperationProgressType.BarOnly }; // TODO: NoUI // TODO: Test native UI in console behaviour (versus older behaviour) // TODO: What happens if you close FDesktop while a batch scan is in progress? RunAsync(() => { try { try { smoothProgress.Reset(); Scan(source); } catch (WiaException e) { WiaScanErrors.ThrowDeviceError(e); } return(true); } catch (Exception e) { // Don't call InvokeError; the driver will do the actual error handling ScanException = e; return(false); } finally { smoothProgress.Reset(); } }); return(true); }
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); } }
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 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 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 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 PdfDictionary resources = page.Elements.GetDictionary("/Resources"); // Get external objects dictionary PdfDictionary xObjects = resources?.Elements.GetDictionary("/XObject"); if (xObjects == null) { return; } // Iterate references to external objects foreach (PdfItem item in xObjects.Elements.Values) { // Is external object an image? if ((item as PdfReference)?.Value is PdfDictionary xObject && xObject.Elements.GetString("/Subtype") == "/Image") { // 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) { string[] 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 abstract Task ScanInternal(ScannedImageSource.Concrete source);