mirror of
https://github.com/cyanfish/naps2.git
synced 2024-11-11 02:45:19 +03:00
Allow slice notation in the --import option
This commit is contained in:
parent
a48f63cf96
commit
f9f98f27f5
@ -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)
|
||||
|
@ -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; }
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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
144
NAPS2.Core/Util/Slice.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -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">
|
||||
|
73
NAPS2.Tests/Unit/SliceTests.cs
Normal file
73
NAPS2.Tests/Unit/SliceTests.cs
Normal 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));
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user