naps2/NAPS2.Lib/ImportExport/AutoSaver.cs

164 lines
5.9 KiB
C#
Raw Normal View History

2022-10-11 04:44:13 +03:00
using NAPS2.EtoForms;
using NAPS2.EtoForms.Notifications;
2022-08-21 03:50:38 +03:00
using NAPS2.ImportExport.Images;
2023-02-19 00:04:18 +03:00
using NAPS2.Pdf;
2022-08-21 03:50:38 +03:00
using NAPS2.Scan;
namespace NAPS2.ImportExport;
public class AutoSaver
{
private readonly ErrorOutput _errorOutput;
private readonly DialogHelper _dialogHelper;
private readonly OperationProgress _operationProgress;
private readonly ISaveNotify _notify;
private readonly PdfExporter _pdfExporter;
2022-08-21 03:50:38 +03:00
private readonly IOverwritePrompt _overwritePrompt;
private readonly Naps2Config _config;
private readonly ImageContext _imageContext;
public AutoSaver(ErrorOutput errorOutput, DialogHelper dialogHelper,
OperationProgress operationProgress, ISaveNotify notify, PdfExporter pdfExporter,
IOverwritePrompt overwritePrompt, Naps2Config config, ImageContext imageContext)
2022-08-21 03:50:38 +03:00
{
_errorOutput = errorOutput;
_dialogHelper = dialogHelper;
_operationProgress = operationProgress;
_notify = notify;
_pdfExporter = pdfExporter;
_overwritePrompt = overwritePrompt;
_config = config;
_imageContext = imageContext;
}
public IAsyncEnumerable<ProcessedImage> Save(AutoSaveSettings settings, IAsyncEnumerable<ProcessedImage> images)
2022-08-21 03:50:38 +03:00
{
return AsyncProducers.RunProducer<ProcessedImage>(async produceImage =>
2022-08-21 03:50:38 +03:00
{
var imageList = new List<ProcessedImage>();
try
2022-08-21 03:50:38 +03:00
{
await foreach (var img in images)
2022-08-21 03:50:38 +03:00
{
imageList.Add(img);
if (!settings.ClearImagesAfterSaving)
2022-08-21 03:50:38 +03:00
{
2022-12-30 08:50:04 +03:00
produceImage(img.Clone());
2022-08-21 03:50:38 +03:00
}
}
}
finally
2022-08-21 03:50:38 +03:00
{
if (!await InternalSave(settings, imageList) && settings.ClearImagesAfterSaving)
2022-08-21 03:50:38 +03:00
{
// Fallback in case auto save failed; pipe all the images back at once
foreach (var img in imageList)
{
produceImage(img);
}
2022-08-21 03:50:38 +03:00
}
2022-12-30 08:50:04 +03:00
else
{
foreach (var img in imageList)
{
img.Dispose();
}
}
2022-08-21 03:50:38 +03:00
}
});
}
private async Task<bool> InternalSave(AutoSaveSettings settings, List<ProcessedImage> images)
{
try
{
bool ok = true;
var placeholders = Placeholders.All.WithDate(DateTime.Now);
int i = 0;
string? firstFileSaved = null;
var scans = SaveSeparatorHelper.SeparateScans(new[] { images }, settings.Separator).ToList();
foreach (var imageList in scans)
{
(bool success, string? filePath) =
await SaveOneFile(settings, placeholders, i++, imageList, scans.Count == 1);
if (!success)
{
ok = false;
}
if (success && firstFileSaved == null)
{
firstFileSaved = filePath;
}
}
// TODO: Shouldn't this give duplicate notifications?
if (scans.Count > 1 && ok)
{
// Can't just do images.Count because that includes patch codes
int imageCount = scans.SelectMany(x => x).Count();
_notify.ImagesSaved(imageCount, firstFileSaved!);
}
return ok;
}
catch (Exception ex)
{
Log.ErrorException(MiscResources.AutoSaveError, ex);
_errorOutput.DisplayError(MiscResources.AutoSaveError, ex);
return false;
}
}
private async Task<(bool, string?)> SaveOneFile(AutoSaveSettings settings, Placeholders placeholders, int i,
List<ProcessedImage> images, bool doNotify)
{
if (images.Count == 0)
{
return (true, null);
}
string subPath = placeholders.Substitute(settings.FilePath, true, i);
if (settings.PromptForFilePath)
{
2023-10-09 04:20:09 +03:00
Invoker.Current.Invoke(() =>
2022-08-21 03:50:38 +03:00
{
2023-10-09 04:20:09 +03:00
if (_dialogHelper.PromptToSavePdfOrImage(subPath, out string? newPath))
{
subPath = placeholders.Substitute(newPath!, true, i);
}
});
2022-08-21 03:50:38 +03:00
}
// TODO: This placeholder handling is complex and wrong in some cases (e.g. FilePerScan with ext = "jpg")
// TODO: Maybe have initial placeholders that replace date, then rely on the ops to increment the file num
2022-08-21 03:50:38 +03:00
var extension = Path.GetExtension(subPath);
if (extension != null && extension.Equals(".pdf", StringComparison.InvariantCultureIgnoreCase))
{
if (File.Exists(subPath))
{
subPath = placeholders.Substitute(subPath, true, 0, 1);
}
var op = new SavePdfOperation(_pdfExporter, _overwritePrompt);
if (op.Start(subPath, placeholders, images, _config.Get(c => c.PdfSettings), _config.DefaultOcrParams()))
{
_operationProgress.ShowProgress(op);
}
bool success = await op.Success;
if (success && doNotify)
{
_notify.PdfSaved(subPath);
2022-08-21 03:50:38 +03:00
}
return (success, subPath);
}
else
{
var op = new SaveImagesOperation(_overwritePrompt, _imageContext);
2022-08-21 03:50:38 +03:00
if (op.Start(subPath, placeholders, images, _config.Get(c => c.ImageSettings)))
{
_operationProgress.ShowProgress(op);
}
bool success = await op.Success;
if (success && doNotify && op.FirstFileSaved != null)
{
_notify.ImagesSaved(images.Count, op.FirstFileSaved);
2022-08-21 03:50:38 +03:00
}
return (success, subPath);
}
}
}