Example #1
0
        public async Task <bool> SavePDF(List <ScannedImage> images, ISaveNotify notify)
        {
            if (images.Any())
            {
                string savePath;

                var pdfSettings = pdfSettingsContainer.PdfSettings;
                if (pdfSettings.SkipSavePrompt && Path.IsPathRooted(pdfSettings.DefaultFileName))
                {
                    savePath = pdfSettings.DefaultFileName;
                }
                else
                {
                    if (!dialogHelper.PromptToSavePdf(pdfSettings.DefaultFileName, out savePath))
                    {
                        return(false);
                    }
                }

                var subSavePath = fileNamePlaceholders.SubstitutePlaceholders(savePath, DateTime.Now);
                var changeToken = changeTracker.State;
                if (await ExportPDF(subSavePath, images, false, null))
                {
                    changeTracker.Saved(changeToken);
                    notify?.PdfSaved(subSavePath);
                    return(true);
                }
            }
            return(false);
        }
            private void Save(DateTime now, int i, List <ScannedImage> images)
            {
                if (images.Count == 0)
                {
                    return;
                }

                var barcode = images[0].Barcode;

                var subPath = fileNamePlaceholders.SubstitutePlaceholders(Settings.SavePath, now, barcode, true, i);

                if (GetSavePathExtension().ToLower() == ".pdf")
                {
                    if (File.Exists(subPath))
                    {
                        subPath = fileNamePlaceholders.SubstitutePlaceholders(subPath, now, barcode, true, 0, 1);
                    }
                    var ocrLanguageCode = userConfigManager.Config.EnableOcr ? userConfigManager.Config.OcrLanguageCode : null;
                    pdfExporter.Export(subPath, images, pdfSettingsContainer.PdfSettings, ocrLanguageCode, j => true);
                }
                else
                {
                    var op = operationFactory.Create <SaveImagesOperation>();
                    op.Start(subPath, now, images, true);
                    op.WaitUntilFinished();
                }
            }
            private async Task Save(DateTime now, int i, List <ScannedImage> images)
            {
                if (images.Count == 0)
                {
                    return;
                }
                var subPath = fileNamePlaceholders.SubstitutePlaceholders(Settings.SavePath, now, true, i);

                if (GetSavePathExtension().ToLower() == ".pdf")
                {
                    if (File.Exists(subPath))
                    {
                        subPath = fileNamePlaceholders.SubstitutePlaceholders(subPath, now, true, 0, 1);
                    }
                    var snapshots = images.Select(x => x.Preserve()).ToList();
                    try
                    {
                        await pdfExporter.Export(subPath, snapshots, pdfSettingsContainer.PdfSettings, ocrManager.DefaultParams, (j, k) => { }, CancelToken);
                    }
                    finally
                    {
                        snapshots.ForEach(s => s.Dispose());
                    }
                }
                else
                {
                    var op = operationFactory.Create <SaveImagesOperation>();
                    op.Start(subPath, now, images, true);
                    await op.Success;
                }
            }
Example #4
0
        public bool SavePDF(List <ScannedImage> images)
        {
            if (images.Any())
            {
                string savePath;

                var pdfSettings = pdfSettingsContainer.PdfSettings;
                if (pdfSettings.SkipSavePrompt && Path.IsPathRooted(pdfSettings.DefaultFileName))
                {
                    savePath = pdfSettings.DefaultFileName;
                }
                else
                {
                    if (!dialogHelper.PromptToSavePdf(pdfSettings.DefaultFileName, out savePath))
                    {
                        return(false);
                    }
                }

                var subSavePath = fileNamePlaceholders.SubstitutePlaceholders(savePath, DateTime.Now);
                if (ExportPDF(subSavePath, images, false))
                {
                    changeTracker.HasUnsavedChanges = false;
                    notify.PdfSaved(subSavePath);
                    return(true);
                }
            }
            return(false);
        }
Example #5
0
        public async Task <bool> EmailPDF(List <ScannedImage> images)
        {
            if (!images.Any())
            {
                return(false);
            }

            if (userConfigManager.Config.EmailSetup == null)
            {
                // First run; prompt for a
                var form = formFactory.Create <FEmailProvider>();
                if (form.ShowDialog() != DialogResult.OK)
                {
                    return(false);
                }
            }

            var emailSettings  = emailSettingsContainer.EmailSettings;
            var invalidChars   = new HashSet <char>(Path.GetInvalidFileNameChars());
            var attachmentName = new string(emailSettings.AttachmentName.Where(x => !invalidChars.Contains(x)).ToArray());

            if (string.IsNullOrEmpty(attachmentName))
            {
                attachmentName = "Scan.pdf";
            }
            if (!attachmentName.EndsWith(".pdf", StringComparison.InvariantCultureIgnoreCase))
            {
                attachmentName += ".pdf";
            }
            attachmentName = fileNamePlaceholders.SubstitutePlaceholders(attachmentName, DateTime.Now, false);

            var tempFolder = new DirectoryInfo(Path.Combine(Paths.Temp, Path.GetRandomFileName()));

            tempFolder.Create();
            try
            {
                string targetPath  = Path.Combine(tempFolder.FullName, attachmentName);
                var    changeToken = changeTracker.State;

                var message = new EmailMessage();
                if (await ExportPDF(targetPath, images, true, message) != null)
                {
                    changeTracker.Saved(changeToken);
                    return(true);
                }
            }
            finally
            {
                tempFolder.Delete(true);
            }
            return(false);
        }
Example #6
0
        public bool SavePdf(string fileName, DateTime dateTime, ICollection <IScannedImage> images, PdfSettings pdfSettings, string ocrLanguageCode, Func <int, bool> progressCallback)
        {
            var subFileName = fileNamePlaceholders.SubstitutePlaceholders(fileName, dateTime);

            if (File.Exists(subFileName))
            {
                if (overwritePrompt.ConfirmOverwrite(subFileName) != DialogResult.Yes)
                {
                    return(false);
                }
            }

            try
            {
                pdfExporter.Export(subFileName, images, pdfSettings, ocrLanguageCode, progressCallback);
                return(true);
            }
            catch (UnauthorizedAccessException)
            {
                errorOutput.DisplayError(MiscResources.DontHavePermission);
            }
            catch (IOException ex)
            {
                Log.ErrorException(MiscResources.ErrorSaving, ex);
                errorOutput.DisplayError(MiscResources.ErrorSaving);
            }
            return(false);
        }
Example #7
0
        private bool PreCheckOverwriteFile()
        {
            if (options.OutputPath == null)
            {
                // Email, so no check needed
                return(true);
            }
            var subPath = fileNamePlaceholders.SubstitutePlaceholders(options.OutputPath, startTime);

            if (IsPdfFile(subPath) &&
                File.Exists(subPath) &&
                !options.ForceOverwrite)
            {
                errorOutput.DisplayError(string.Format(ConsoleResources.FileAlreadyExists, Path.GetFullPath(subPath)));
                return(false);
            }
            return(true);
        }
Example #8
0
            private void Save(DateTime now, int i, List <ScannedImage> images)
            {
                if (images.Count == 0)
                {
                    return;
                }
                var subPath = fileNamePlaceholders.SubstitutePlaceholders(Settings.SavePath, now, true, i);

                if (GetSavePathExtension().ToLower() == ".pdf")
                {
                    if (File.Exists(subPath))
                    {
                        subPath = fileNamePlaceholders.SubstitutePlaceholders(subPath, now, true, 0, 1);
                    }
                    pdfExporter.Export(subPath, images, pdfSettingsContainer.PdfSettings, ocrDependencyManager.DefaultLanguageCode, j => true);
                }
                else
                {
                    var op = operationFactory.Create <SaveImagesOperation>();
                    op.Start(subPath, now, images, true);
                    op.WaitUntilFinished();
                }
            }
Example #9
0
        private void EmailPDF(List <IScannedImage> images)
        {
            if (images.Any())
            {
                var emailSettings  = emailSettingsContainer.EmailSettings;
                var invalidChars   = new HashSet <char>(Path.GetInvalidFileNameChars());
                var attachmentName = new string(emailSettings.AttachmentName.Where(x => !invalidChars.Contains(x)).ToArray());
                if (string.IsNullOrEmpty(attachmentName))
                {
                    attachmentName = "Scan.pdf";
                }
                if (!attachmentName.EndsWith(".pdf", StringComparison.InvariantCultureIgnoreCase))
                {
                    attachmentName += ".pdf";
                }
                attachmentName = fileNamePlaceholders.SubstitutePlaceholders(attachmentName, DateTime.Now, false);

                var tempFolder = new DirectoryInfo(Path.Combine(Paths.Temp, Path.GetRandomFileName()));
                tempFolder.Create();
                try
                {
                    string targetPath = Path.Combine(tempFolder.FullName, attachmentName);
                    ExportPDF(targetPath, images);
                    var message = new EmailMessage
                    {
                        Attachments =
                        {
                            new EmailAttachment
                            {
                                FilePath       = targetPath,
                                AttachmentName = attachmentName
                            }
                        }
                    };

                    if (emailer.SendEmail(message))
                    {
                        changeTracker.HasUnsavedChanges = false;
                    }
                }
                finally
                {
                    tempFolder.Delete(true);
                }
            }
        }
Example #10
0
        public bool Start(string fileName, DateTime dateTime, ICollection <ScannedImage> images, PdfSettings pdfSettings, string ocrLanguageCode, bool email)
        {
            ProgressTitle = email ? MiscResources.EmailPdfProgress : MiscResources.SavePdfProgress;
            var subFileName = fileNamePlaceholders.SubstitutePlaceholders(fileName, dateTime);

            Status = new OperationStatus
            {
                StatusText  = string.Format(MiscResources.SavingFormat, Path.GetFileName(subFileName)),
                MaxProgress = images.Count
            };
            cancel = false;

            if (File.Exists(subFileName))
            {
                if (overwritePrompt.ConfirmOverwrite(subFileName) != DialogResult.Yes)
                {
                    return(false);
                }
            }

            thread = threadFactory.StartThread(() =>
            {
                try
                {
                    Status.Success = pdfExporter.Export(subFileName, images, pdfSettings, ocrLanguageCode, i =>
                    {
                        Status.CurrentProgress = i;
                        InvokeStatusChanged();
                        return(!cancel);
                    });
                }
                catch (UnauthorizedAccessException)
                {
                    InvokeError(MiscResources.DontHavePermission);
                }
                catch (Exception ex)
                {
                    Log.ErrorException(MiscResources.ErrorSaving, ex);
                    InvokeError(MiscResources.ErrorSaving);
                }
                GC.Collect();
                InvokeFinished();
            });

            return(true);
        }
Example #11
0
        /// <summary>
        /// Saves the provided collection of images to a file with the given name. The image type is inferred from the file extension.
        /// If multiple images are provided, they will be saved to files with numeric identifiers, e.g. img1.jpg, img2.jpg, etc..
        /// </summary>
        /// <param name="fileName">The name of the file to save. For multiple images, this is modified by appending a number before the extension.</param>
        /// <param name="dateTime"></param>
        /// <param name="images">The collection of images to save.</param>
        /// <param name="batch"></param>
        public bool Start(string fileName, DateTime dateTime, List <ScannedImage> images, bool batch = false)
        {
            Status = new OperationStatus
            {
                MaxProgress = images.Count
            };
            cancel = false;

            thread = threadFactory.StartThread(() =>
            {
                try
                {
                    var subFileName = fileNamePlaceholders.SubstitutePlaceholders(fileName, dateTime, batch);
                    if (Directory.Exists(subFileName))
                    {
                        // Not supposed to be a directory, but ok...
                        fileName    = Path.Combine(subFileName, "$(n).jpg");
                        subFileName = fileNamePlaceholders.SubstitutePlaceholders(fileName, dateTime, batch);
                    }
                    ImageFormat format = GetImageFormat(subFileName);

                    if (Equals(format, ImageFormat.Tiff))
                    {
                        if (File.Exists(subFileName))
                        {
                            if (overwritePrompt.ConfirmOverwrite(subFileName) != DialogResult.Yes)
                            {
                                return;
                            }
                        }
                        Status.StatusText = string.Format(MiscResources.SavingFormat, Path.GetFileName(subFileName));
                        Status.Success    = TiffHelper.SaveMultipage(images, subFileName, j =>
                        {
                            Status.CurrentProgress = j;
                            InvokeStatusChanged();
                            return(!cancel);
                        });
                        FirstFileSaved = subFileName;
                        return;
                    }

                    int i      = 0;
                    int digits = (int)Math.Floor(Math.Log10(images.Count)) + 1;
                    foreach (ScannedImage img in images)
                    {
                        if (cancel)
                        {
                            return;
                        }
                        Status.CurrentProgress = i;
                        InvokeStatusChanged();

                        if (images.Count == 1 && File.Exists(subFileName))
                        {
                            var dialogResult = overwritePrompt.ConfirmOverwrite(subFileName);
                            if (dialogResult == DialogResult.No)
                            {
                                continue;
                            }
                            if (dialogResult == DialogResult.Cancel)
                            {
                                return;
                            }
                        }
                        using (Bitmap baseImage = img.GetImage())
                        {
                            if (images.Count == 1)
                            {
                                Status.StatusText = string.Format(MiscResources.SavingFormat, Path.GetFileName(subFileName));
                                InvokeStatusChanged();
                                DoSaveImage(baseImage, subFileName, format);
                                FirstFileSaved = subFileName;
                            }
                            else
                            {
                                var fileNameN = fileNamePlaceholders.SubstitutePlaceholders(fileName, dateTime, true, i,
                                                                                            digits);
                                Status.StatusText = string.Format(MiscResources.SavingFormat, Path.GetFileName(fileNameN));
                                InvokeStatusChanged();
                                DoSaveImage(baseImage, fileNameN, format);

                                if (i == 0)
                                {
                                    FirstFileSaved = fileNameN;
                                }
                            }
                        }
                        i++;
                    }

                    Status.Success = true;
                }
                catch (UnauthorizedAccessException ex)
                {
                    InvokeError(MiscResources.DontHavePermission, ex);
                }
                catch (Exception ex)
                {
                    Log.ErrorException(MiscResources.ErrorSaving, ex);
                    InvokeError(MiscResources.ErrorSaving, ex);
                }
                finally
                {
                    GC.Collect();
                    InvokeFinished();
                }
            });

            return(true);
        }
Example #12
0
 private void txtFileName_TextChanged(object sender, EventArgs e)
 {
     lblPreview.Text = fileNamePlaceholders.SubstitutePlaceholders(txtFileName.Text, DateTime.Now, false);
 }
Example #13
0
        /// <summary>
        /// Saves the provided collection of images to a file with the given name. The image type is inferred from the file extension.
        /// If multiple images are provided, they will be saved to files with numeric identifiers, e.g. img1.jpg, img2.jpg, etc..
        /// </summary>
        /// <param name="fileName">The name of the file to save. For multiple images, this is modified by appending a number before the extension.</param>
        /// <param name="dateTime"></param>
        /// <param name="images">The collection of images to save.</param>
        /// <param name="batch"></param>
        public bool Start(string fileName, DateTime dateTime, List <ScannedImage> images, bool batch = false)
        {
            Status = new OperationStatus
            {
                MaxProgress = images.Count
            };

            var snapshots = images.Select(x => x.Preserve()).ToList();

            RunAsync(async() =>
            {
                try
                {
                    var subFileName = fileNamePlaceholders.SubstitutePlaceholders(fileName, dateTime, batch);
                    if (Directory.Exists(subFileName))
                    {
                        // Not supposed to be a directory, but ok...
                        fileName    = Path.Combine(subFileName, "$(n).jpg");
                        subFileName = fileNamePlaceholders.SubstitutePlaceholders(fileName, dateTime, batch);
                    }
                    ImageFormat format = GetImageFormat(subFileName);

                    if (Equals(format, ImageFormat.Tiff) && !imageSettingsContainer.ImageSettings.SinglePageTiff)
                    {
                        if (File.Exists(subFileName))
                        {
                            if (overwritePrompt.ConfirmOverwrite(subFileName) != DialogResult.Yes)
                            {
                                return(false);
                            }
                        }
                        Status.StatusText = string.Format(MiscResources.SavingFormat, Path.GetFileName(subFileName));
                        FirstFileSaved    = subFileName;
                        return(await tiffHelper.SaveMultipage(snapshots, subFileName, imageSettingsContainer.ImageSettings.TiffCompression, OnProgress, CancelToken));
                    }

                    int i      = 0;
                    int digits = (int)Math.Floor(Math.Log10(snapshots.Count)) + 1;
                    foreach (ScannedImage.Snapshot snapshot in snapshots)
                    {
                        if (CancelToken.IsCancellationRequested)
                        {
                            return(false);
                        }
                        Status.CurrentProgress = i;
                        InvokeStatusChanged();

                        if (snapshots.Count == 1 && File.Exists(subFileName))
                        {
                            var dialogResult = overwritePrompt.ConfirmOverwrite(subFileName);
                            if (dialogResult == DialogResult.No)
                            {
                                continue;
                            }
                            if (dialogResult == DialogResult.Cancel)
                            {
                                return(false);
                            }
                        }
                        if (snapshots.Count == 1)
                        {
                            Status.StatusText = string.Format(MiscResources.SavingFormat, Path.GetFileName(subFileName));
                            InvokeStatusChanged();
                            await DoSaveImage(snapshot, subFileName, format);
                            FirstFileSaved = subFileName;
                        }
                        else
                        {
                            var fileNameN = fileNamePlaceholders.SubstitutePlaceholders(fileName, dateTime, true, i,
                                                                                        digits);
                            Status.StatusText = string.Format(MiscResources.SavingFormat, Path.GetFileName(fileNameN));
                            InvokeStatusChanged();
                            await DoSaveImage(snapshot, fileNameN, format);

                            if (i == 0)
                            {
                                FirstFileSaved = fileNameN;
                            }
                        }
                        i++;
                    }

                    return(FirstFileSaved != null);
                }
                catch (UnauthorizedAccessException ex)
                {
                    InvokeError(MiscResources.DontHavePermission, ex);
                }
                catch (Exception ex)
                {
                    Log.ErrorException(MiscResources.ErrorSaving, ex);
                    InvokeError(MiscResources.ErrorSaving, ex);
                }
                finally
                {
                    snapshots.ForEach(s => s.Dispose());
                    GC.Collect();
                }
                return(false);
            });
            Success.ContinueWith(task =>
            {
                if (task.Result)
                {
                    Log.Event(EventType.SaveImages, new EventParams
                    {
                        Name       = MiscResources.SaveImages,
                        Pages      = snapshots.Count,
                        FileFormat = Path.GetExtension(fileName)
                    });
                }
            }, TaskContinuationOptions.OnlyOnRanToCompletion);

            return(true);
        }
Example #14
0
        public bool Start(string fileName, DateTime dateTime, ICollection <ScannedImage> images, PdfSettings pdfSettings, OcrParams ocrParams, bool email, EmailMessage emailMessage)
        {
            ProgressTitle = email ? MiscResources.EmailPdfProgress : MiscResources.SavePdfProgress;
            var subFileName = fileNamePlaceholders.SubstitutePlaceholders(fileName, dateTime);

            Status = new OperationStatus
            {
                StatusText  = string.Format(MiscResources.SavingFormat, Path.GetFileName(subFileName)),
                MaxProgress = images.Count
            };

            if (Directory.Exists(subFileName))
            {
                // Not supposed to be a directory, but ok...
                subFileName = fileNamePlaceholders.SubstitutePlaceholders(Path.Combine(subFileName, "$(n).pdf"), dateTime);
            }
            if (File.Exists(subFileName))
            {
                if (overwritePrompt.ConfirmOverwrite(subFileName) != DialogResult.Yes)
                {
                    return(false);
                }
            }

            var snapshots = images.Select(x => x.Preserve()).ToList();

            RunAsync(async() =>
            {
                bool result = false;
                try
                {
                    result = await pdfExporter.Export(subFileName, snapshots, pdfSettings, ocrParams, OnProgress, CancelToken);
                }
                catch (UnauthorizedAccessException ex)
                {
                    InvokeError(MiscResources.DontHavePermission, ex);
                }
                catch (IOException ex)
                {
                    if (File.Exists(subFileName))
                    {
                        InvokeError(MiscResources.FileInUse, ex);
                    }
                    else
                    {
                        Log.ErrorException(MiscResources.ErrorSaving, ex);
                        InvokeError(MiscResources.ErrorSaving, ex);
                    }
                }
                catch (Exception ex)
                {
                    Log.ErrorException(MiscResources.ErrorSaving, ex);
                    InvokeError(MiscResources.ErrorSaving, ex);
                }
                finally
                {
                    snapshots.ForEach(s => s.Dispose());
                    GC.Collect();
                }

                if (result && email && emailMessage != null)
                {
                    Status.StatusText      = MiscResources.UploadingEmail;
                    Status.CurrentProgress = 0;
                    Status.MaxProgress     = 1;
                    Status.ProgressType    = OperationProgressType.MB;
                    InvokeStatusChanged();

                    try
                    {
                        result = await emailProviderFactory.Default.SendEmail(emailMessage, OnProgress, CancelToken);
                    }
                    catch (OperationCanceledException)
                    {
                    }
                    catch (Exception ex)
                    {
                        Log.ErrorException(MiscResources.ErrorEmailing, ex);
                        InvokeError(MiscResources.ErrorEmailing, ex);
                    }
                }

                return(result);
            });
            Success.ContinueWith(task =>
            {
                if (task.Result)
                {
                    if (email)
                    {
                        Log.Event(EventType.Email, new EventParams
                        {
                            Name       = MiscResources.EmailPdf,
                            Pages      = snapshots.Count,
                            FileFormat = ".pdf"
                        });
                    }
                    else
                    {
                        Log.Event(EventType.SavePdf, new EventParams
                        {
                            Name       = MiscResources.SavePdf,
                            Pages      = snapshots.Count,
                            FileFormat = ".pdf"
                        });
                    }
                }
            }, TaskContinuationOptions.OnlyOnRanToCompletion);

            return(true);
        }
Example #15
0
        /// <summary>
        /// Saves the provided collection of images to a file with the given name. The image type is inferred from the file extension.
        /// If multiple images are provided, they will be saved to files with numeric identifiers, e.g. img1.jpg, img2.jpg, etc..
        /// </summary>
        /// <param name="fileName">The name of the file to save. For multiple images, this is modified by appending a number before the extension.</param>
        /// <param name="dateTime"></param>
        /// <param name="images">The collection of images to save.</param>
        public void SaveImages(string fileName, DateTime dateTime, ICollection <IScannedImage> images, Func <int, bool> progressCallback)
        {
            try
            {
                var         subFileName = fileNamePlaceholders.SubstitutePlaceholders(fileName, dateTime);
                ImageFormat format      = GetImageFormat(subFileName);

                if (Equals(format, ImageFormat.Tiff))
                {
                    if (File.Exists(subFileName))
                    {
                        if (overwritePrompt.ConfirmOverwrite(subFileName) != DialogResult.Yes)
                        {
                            return;
                        }
                    }
                    Image[] bitmaps = images.Select(x => (Image)x.GetImage()).ToArray();
                    TiffHelper.SaveMultipage(bitmaps, subFileName);
                    foreach (Image bitmap in bitmaps)
                    {
                        bitmap.Dispose();
                    }
                    return;
                }

                int i      = 1;
                int digits = (int)Math.Floor(Math.Log10(images.Count)) + 1;
                foreach (IScannedImage img in images)
                {
                    if (!progressCallback(i))
                    {
                        return;
                    }
                    if (images.Count == 1 && File.Exists(subFileName))
                    {
                        var dialogResult = overwritePrompt.ConfirmOverwrite(subFileName);
                        if (dialogResult == DialogResult.No)
                        {
                            continue;
                        }
                        if (dialogResult == DialogResult.Cancel)
                        {
                            return;
                        }
                    }
                    using (Bitmap baseImage = img.GetImage())
                    {
                        if (images.Count == 1)
                        {
                            DoSaveImage(baseImage, subFileName, format);
                        }
                        else
                        {
                            var fileNameN = fileNamePlaceholders.SubstitutePlaceholders(fileName, dateTime, true, i - 1, digits);
                            DoSaveImage(baseImage, fileNameN, format);
                        }
                    }
                    i++;
                }
            }
            catch (UnauthorizedAccessException)
            {
                errorOutput.DisplayError(MiscResources.DontHavePermission);
            }
            catch (IOException ex)
            {
                Log.ErrorException(MiscResources.ErrorSaving, ex);
                errorOutput.DisplayError(MiscResources.ErrorSaving);
            }
        }
        public bool Start(string fileName, DateTime dateTime, ICollection <ScannedImage> images, PdfSettings pdfSettings, OcrParams ocrParams, bool email, EmailMessage emailMessage)
        {
            ProgressTitle = email ? MiscResources.EmailPdfProgress : MiscResources.SavePdfProgress;
            Status        = new OperationStatus
            {
                MaxProgress = images.Count
            };

            if (Directory.Exists(fileNamePlaceholders.SubstitutePlaceholders(fileName, dateTime)))
            {
                // Not supposed to be a directory, but ok...
                fileName = Path.Combine(fileName, "$(n).pdf");
            }

            var singleFile  = !pdfSettings.SinglePagePdf || images.Count == 1;
            var subFileName = fileNamePlaceholders.SubstitutePlaceholders(fileName, dateTime);

            if (singleFile)
            {
                if (File.Exists(subFileName) && overwritePrompt.ConfirmOverwrite(subFileName) != DialogResult.Yes)
                {
                    return(false);
                }
            }

            var snapshots       = images.Select(x => x.Preserve()).ToList();
            var snapshotsByFile = pdfSettings.SinglePagePdf ? snapshots.Select(x => new[] { x }).ToArray() : new[] { snapshots.ToArray() };

            RunAsync(async() =>
            {
                bool result = false;
                try
                {
                    int digits = (int)Math.Floor(Math.Log10(snapshots.Count)) + 1;
                    int i      = 0;
                    foreach (var snapshotArray in snapshotsByFile)
                    {
                        subFileName       = fileNamePlaceholders.SubstitutePlaceholders(fileName, dateTime, true, i, singleFile ? 0 : digits);
                        Status.StatusText = string.Format(MiscResources.SavingFormat, Path.GetFileName(subFileName));
                        InvokeStatusChanged();
                        if (singleFile && IsFileInUse(subFileName, out var ex))
                        {
                            InvokeError(MiscResources.FileInUse, ex);
                            break;
                        }

                        var progress = singleFile ? OnProgress : (ProgressHandler)((j, k) => { });
                        result       = await pdfExporter.Export(subFileName, snapshotArray, pdfSettings, ocrParams, progress, CancelToken);
                        if (!result || CancelToken.IsCancellationRequested)
                        {
                            break;
                        }
                        emailMessage?.Attachments.Add(new EmailAttachment
                        {
                            FilePath       = subFileName,
                            AttachmentName = Path.GetFileName(subFileName)
                        });
                        if (i == 0)
                        {
                            FirstFileSaved = subFileName;
                        }
                        i++;
                        if (!singleFile)
                        {
                            OnProgress(i, snapshotsByFile.Length);
                        }
                    }
                }
                catch (UnauthorizedAccessException ex)
                {
                    InvokeError(MiscResources.DontHavePermission, ex);
                }
                catch (IOException ex)
                {
                    if (File.Exists(subFileName))
                    {
                        InvokeError(MiscResources.FileInUse, ex);
                    }
                    else
                    {
                        Log.ErrorException(MiscResources.ErrorSaving, ex);
                        InvokeError(MiscResources.ErrorSaving, ex);
                    }
                }
                catch (Exception ex)
                {
                    Log.ErrorException(MiscResources.ErrorSaving, ex);
                    InvokeError(MiscResources.ErrorSaving, ex);
                }
                finally
                {
                    snapshots.ForEach(s => s.Dispose());
                    GC.Collect();
                }

                if (result && !CancelToken.IsCancellationRequested && email && emailMessage != null)
                {
                    Status.StatusText      = MiscResources.UploadingEmail;
                    Status.CurrentProgress = 0;
                    Status.MaxProgress     = 1;
                    Status.ProgressType    = OperationProgressType.MB;
                    InvokeStatusChanged();

                    try
                    {
                        result = await emailProviderFactory.Default.SendEmail(emailMessage, OnProgress, CancelToken);
                    }
                    catch (OperationCanceledException)
                    {
                    }
                    catch (Exception ex)
                    {
                        Log.ErrorException(MiscResources.ErrorEmailing, ex);
                        InvokeError(MiscResources.ErrorEmailing, ex);
                    }
                }

                return(result);
            });
            Success.ContinueWith(task =>
            {
                if (task.Result)
                {
                    if (email)
                    {
                        Log.Event(EventType.Email, new Event
                        {
                            Name       = MiscResources.EmailPdf,
                            Pages      = snapshots.Count,
                            FileFormat = ".pdf"
                        });
                    }
                    else
                    {
                        Log.Event(EventType.SavePdf, new Event
                        {
                            Name       = MiscResources.SavePdf,
                            Pages      = snapshots.Count,
                            FileFormat = ".pdf"
                        });

                        if (pdfSettings.ShowFolder)
                        {
                            String filePath = Path.GetDirectoryName(fileName);
                            Process.Start("explorer.exe", filePath);
                        }
                    }
                }
            }, TaskContinuationOptions.OnlyOnRanToCompletion);

            return(true);
        }