Allow slice notation in the --import option

This commit is contained in:
Ben Olden-Cooligan 2018-03-01 21:53:50 -05:00
parent a48f63cf96
commit f9f98f27f5
11 changed files with 248 additions and 19 deletions

View File

@ -265,7 +265,8 @@ namespace NAPS2.Automation
i++;
try
{
var images = scannedImageImporter.Import(filePath, (j, k) => true).ToList();
var slice = Slice.Parse(filePath, out string actualPath);
var images = scannedImageImporter.Import(actualPath, slice, (j, k) => true).ToList();
scanList.Add(images);
}
catch (Exception ex)

View File

@ -15,7 +15,7 @@ namespace NAPS2.Automation
public string OutputPath { get; set; }
[Option('a', "autosave", HelpText = "Use the Auto Save settings from the selected profile." +
" Only works if the profile has Auto Save enabled.")]
" Only works if the profile has Auto Save enabled.")]
public bool AutoSave { get; set; }
[Option("install", HelpText = "Use this option to download and install optional components (e.g. \"ocr-eng\", \"generic-import\").")]
@ -27,7 +27,8 @@ namespace NAPS2.Automation
[Option('i', "import", HelpText = "The name and path of one or more pdf/image files to import." +
" Imported files are prepended to the output in the order they are specified." +
" Multiple files are separated by a semicolon (\";\").")]
" Multiple files are separated by a semicolon (\";\")." +
" Slice notation can be used to only import some pages (e.g. \"[0]\" for the first page or \"[:2]\" for the first two pages).")]
public string ImportPath { get; set; }
[Option("importpassword", HelpText = "The password to use to import one or more encrypted PDF files.")]
@ -53,7 +54,7 @@ namespace NAPS2.Automation
#endregion
#region Order Options
[Option("interleave", HelpText = "Interleave pages before saving.")]
public bool Interleave { get; set; }
@ -133,12 +134,12 @@ namespace NAPS2.Automation
public string EmailFileName { get; set; }
[Option("subject", HelpText = "The email message's subject." +
//" You can use \"<date>\" and/or \"<time>\" to insert the date/time of the scan." +
//" You can use \"<date>\" and/or \"<time>\" to insert the date/time of the scan." +
" Requires -e/--email.")]
public string EmailSubject { get; set; }
[Option("body", HelpText = "The email message's body text." +
//" You can use \"<date>\" and/or \"<time>\" to insert the date/time of the scan." +
//" You can use \"<date>\" and/or \"<time>\" to insert the date/time of the scan." +
" Requires -e/--email.")]
public string EmailBody { get; set; }

View File

@ -2,11 +2,12 @@
using System.Collections.Generic;
using System.Linq;
using NAPS2.Scan.Images;
using NAPS2.Util;
namespace NAPS2.ImportExport
{
public interface IScannedImageImporter
{
IEnumerable<ScannedImage> Import(string filePath, Func<int, int, bool> progressCallback);
IEnumerable<ScannedImage> Import(string filePath, Slice slice, Func<int, int, bool> progressCallback);
}
}

View File

@ -18,7 +18,7 @@ namespace NAPS2.ImportExport.Images
this.thumbnailRenderer = thumbnailRenderer;
}
public IEnumerable<ScannedImage> Import(string filePath, Func<int, int, bool> progressCallback)
public IEnumerable<ScannedImage> Import(string filePath, Slice slice, Func<int, int, bool> progressCallback)
{
if (!progressCallback(0, 1))
{
@ -38,13 +38,14 @@ namespace NAPS2.ImportExport.Images
using (toImport)
{
int frameCount = toImport.GetFrameCount(FrameDimension.Page);
for (int i = 0; i < frameCount; ++i)
int i = 0;
foreach(var frameIndex in slice.Indices(frameCount))
{
if (!progressCallback(i, frameCount))
if (!progressCallback(i++, frameCount))
{
yield break;
}
toImport.SelectActiveFrame(FrameDimension.Page, i);
toImport.SelectActiveFrame(FrameDimension.Page, frameIndex);
var image = new ScannedImage(toImport, ScanBitDepth.C24Bit, IsLossless(toImport.RawFormat), -1);
image.SetThumbnail(thumbnailRenderer.RenderThumbnail(toImport));
yield return image;

View File

@ -55,7 +55,7 @@ namespace NAPS2.ImportExport
{
Status.StatusText = string.Format(MiscResources.ImportingFormat, Path.GetFileName(fileName));
InvokeStatusChanged();
var images = scannedImageImporter.Import(fileName, (i, j) =>
var images = scannedImageImporter.Import(fileName, Slice.Default, (i, j) =>
{
if (oneFile)
{

View File

@ -34,7 +34,7 @@ namespace NAPS2.ImportExport.Pdf
this.pdfRenderer = pdfRenderer;
}
public IEnumerable<ScannedImage> Import(string filePath, Func<int, int, bool> progressCallback)
public IEnumerable<ScannedImage> Import(string filePath, Slice slice, Func<int, int, bool> progressCallback)
{
if (!progressCallback(0, 0))
{
@ -63,10 +63,16 @@ namespace NAPS2.ImportExport.Pdf
if (document.Info.Creator != MiscResources.NAPS2 && document.Info.Author != MiscResources.NAPS2)
{
pdfRenderer.ThrowIfCantRender();
return document.Pages.Cast<PdfPage>().TakeWhile(page => progressCallback(i++, document.PageCount)).Select(ExportRawPdfPage);
return slice.Indices(document.PageCount)
.Select(index => document.Pages[index])
.TakeWhile(page => progressCallback(i++, document.PageCount))
.Select(ExportRawPdfPage);
}
return document.Pages.Cast<PdfPage>().TakeWhile(page => progressCallback(i++, document.PageCount)).SelectMany(GetImagesFromPage);
return slice.Indices(document.PageCount)
.Select(index => document.Pages[index])
.TakeWhile(page => progressCallback(i++, document.PageCount))
.SelectMany(GetImagesFromPage);
}
catch (ImageRenderException e)
{

View File

@ -5,6 +5,7 @@ using System.Linq;
using NAPS2.ImportExport.Images;
using NAPS2.ImportExport.Pdf;
using NAPS2.Scan.Images;
using NAPS2.Util;
namespace NAPS2.ImportExport
{
@ -19,7 +20,7 @@ namespace NAPS2.ImportExport
this.imageImporter = imageImporter;
}
public IEnumerable<ScannedImage> Import(string filePath, Func<int, int, bool> progressCallback)
public IEnumerable<ScannedImage> Import(string filePath, Slice slice, Func<int, int, bool> progressCallback)
{
if (filePath == null)
{
@ -28,9 +29,9 @@ namespace NAPS2.ImportExport
switch (Path.GetExtension(filePath).ToLowerInvariant())
{
case ".pdf":
return pdfImporter.Import(filePath, progressCallback);
return pdfImporter.Import(filePath, slice, progressCallback);
default:
return imageImporter.Import(filePath, progressCallback);
return imageImporter.Import(filePath, slice, progressCallback);
}
}
}

View File

@ -310,6 +310,7 @@
<Compile Include="Host\ProcessJob.cs" />
<Compile Include="ImportExport\DirectImageTransfer.cs" />
<Compile Include="Util\KeyboardShortcutManager.cs" />
<Compile Include="Util\Slice.cs" />
<Compile Include="Util\StillImage.cs" />
<Compile Include="Util\StringWrapper.cs" />
<Compile Include="Util\ThreadFactory.cs" />

144
NAPS2.Core/Util/Slice.cs Normal file
View File

@ -0,0 +1,144 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
namespace NAPS2.Util
{
public class Slice
{
public static readonly Slice Default = new Slice(null, null, null);
private static readonly Regex ParseRegex = new Regex(@"^(.*)\[([^\[\]]*)\](\s*)$");
public static Slice Parse(string input, out string rest)
{
var match = ParseRegex.Match(input);
if (!match.Success)
{
rest = input;
return Default;
}
var sliceStr = match.Groups[2].Value;
rest = match.Groups[1].Value + match.Groups[3].Value;
var parts = sliceStr.Split(':');
int? start = null, end = null, step = null;
if (parts.Length == 1)
{
if (int.TryParse(parts[0], out int s))
{
return Item(s);
}
return Item(null);
}
if (parts.Length >= 2)
{
if (int.TryParse(parts[0], out int s))
{
start = s;
}
if (int.TryParse(parts[1], out int e))
{
end = e;
}
}
if (parts.Length >= 3)
{
if (int.TryParse(parts[2], out int s))
{
step = s;
}
}
return Range(start, end, step);
}
public static Slice Item(int? index)
{
return new Slice(index);
}
public static Slice Range(int? start, int? end, int? step)
{
return new Slice(start, end, step);
}
private Slice(int? index)
{
Index = index;
}
private Slice(int? start, int? end, int? step)
{
Start = start;
End = end;
Step = step;
}
public int? Index { get; }
public int? Start { get; }
public int? End { get; }
public int? Step { get; }
public IEnumerable<int> Indices(int collectionLength)
{
if (Index.HasValue)
{
int i = Index.Value < 0 ? collectionLength + Index.Value : Index.Value;
if (i >= 0 && i < collectionLength)
{
yield return i;
}
yield break;
}
bool reverse = Step.HasValue && Step.Value < 0;
int start, end, step;
if (Start.HasValue)
{
start = Start.Value < 0 ? collectionLength + Start.Value : Start.Value;
}
else
{
start = reverse ? collectionLength - 1 : 0;
}
if (End.HasValue)
{
end = End.Value < 0 ? collectionLength + End.Value : End.Value;
}
else
{
end = reverse ? -1 : collectionLength;
}
if (Step.HasValue)
{
step = Step.Value == 0 ? 1 : Step.Value;
}
else
{
step = 1;
}
if (reverse)
{
for (int i = Math.Min(start, collectionLength - 1); i > Math.Max(end, -1); i += step)
{
yield return i;
}
}
else
{
for (int i = Math.Max(start, 0); i < Math.Min(end, collectionLength); i += step)
{
yield return i;
}
}
}
}
}

View File

@ -70,6 +70,7 @@
<ItemGroup>
<Compile Include="Base\BasePdfExporterTests.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Unit\SliceTests.cs" />
</ItemGroup>
<ItemGroup>
<None Include="in\test.1p.in.pdf">
@ -84,7 +85,6 @@
</ItemGroup>
<ItemGroup>
<Folder Include="Integration\" />
<Folder Include="Unit\" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\NAPS2.Core\NAPS2.Core.csproj">

View File

@ -0,0 +1,73 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using NAPS2.Util;
using NUnit.Framework;
namespace NAPS2.Tests.Unit
{
[TestFixture(Category = "unit,fast")]
class SliceTests
{
[Test]
public void Parse()
{
string rest;
AssertSlice(Slice.Parse("[]", out rest), null, null, null, null);
AssertSlice(Slice.Parse("[0]", out rest), 0, null, null, null);
AssertSlice(Slice.Parse("[1]", out rest), 1, null, null, null);
AssertSlice(Slice.Parse("[-1]", out rest), -1, null, null, null);
AssertSlice(Slice.Parse("[-2]", out rest), -2, null, null, null);
AssertSlice(Slice.Parse("[asdpsakoid2238(*S(D)*A(]", out rest), null, null, null, null);
AssertSlice(Slice.Parse("[2:]", out rest), null, 2, null, null);
AssertSlice(Slice.Parse("[:2]", out rest), null, null, 2, null);
AssertSlice(Slice.Parse("[2:-2]", out rest), null, 2, -2, null);
AssertSlice(Slice.Parse("[::2]", out rest), null, null, null, 2);
AssertSlice(Slice.Parse("[::-2]", out rest), null, null, null, -2);
AssertSlice(Slice.Parse("[2:3:4]", out rest), null, 2, 3, 4);
}
private void AssertSlice(Slice s, int? index, int? start, int? end, int? step)
{
Assert.AreEqual(index, s.Index);
Assert.AreEqual(start, s.Start);
Assert.AreEqual(end, s.End);
Assert.AreEqual(step, s.Step);
}
[Test]
public void Indices()
{
CollectionAssert.AreEqual(new [] { 0 }, Slice.Item(0).Indices(7));
CollectionAssert.AreEqual(new [] { 1 }, Slice.Item(1).Indices(7));
CollectionAssert.AreEqual(new [] { 6 }, Slice.Item(-1).Indices(7));
CollectionAssert.AreEqual(new [] { 5 }, Slice.Item(-2).Indices(7));
CollectionAssert.AreEqual(new int[] { }, Slice.Item(7).Indices(7));
CollectionAssert.AreEqual(new [] { 0 }, Slice.Item(-7).Indices(7));
CollectionAssert.AreEqual(new int[] { }, Slice.Item(-8).Indices(7));
CollectionAssert.AreEqual(new[] { 0, 1, 2, 3, 4, 5, 6 }, Slice.Range(null, null, null).Indices(7));
CollectionAssert.AreEqual(new[] { 2, 3, 4, 5, 6 }, Slice.Range(2, null, null).Indices(7));
CollectionAssert.AreEqual(new int[] { }, Slice.Range(7, null, null).Indices(7));
CollectionAssert.AreEqual(new[] { 5, 6 }, Slice.Range(-2, null, null).Indices(7));
CollectionAssert.AreEqual(new[] { 0, 1 }, Slice.Range(null, 2, null).Indices(7));
CollectionAssert.AreEqual(new[] { 0, 1, 2, 3, 4 }, Slice.Range(null, -2, null).Indices(7));
CollectionAssert.AreEqual(new int[] { }, Slice.Range(null, -7, null).Indices(7));
CollectionAssert.AreEqual(new[] { 0, 1, 2, 3, 4, 5, 6 }, Slice.Range(null, null, 0).Indices(7));
CollectionAssert.AreEqual(new[] { 0, 1, 2, 3, 4, 5, 6 }, Slice.Range(null, null, 1).Indices(7));
CollectionAssert.AreEqual(new[] { 6, 5, 4, 3, 2, 1, 0 }, Slice.Range(null, null, -1).Indices(7));
CollectionAssert.AreEqual(new[] { 0, 2, 4, 6 }, Slice.Range(null, null, 2).Indices(7));
CollectionAssert.AreEqual(new[] { 6, 4, 2, 0 }, Slice.Range(null, null, -2).Indices(7));
CollectionAssert.AreEqual(new[] { 1, 4 }, Slice.Range(1, 5, 3).Indices(7));
CollectionAssert.AreEqual(new[] { 6, 3 }, Slice.Range(6, 2, -3).Indices(7));
}
}
}