Skip to content

Commit 5e424fd

Browse files
authored
Merge pull request #10 from sakisk/issue/9
#9: Support replacing a range of pages
2 parents 54469ec + d8e7790 commit 5e424fd

File tree

6 files changed

+111
-18
lines changed

6 files changed

+111
-18
lines changed

src/Kevsoft.PDFtk/IPDFtk.cs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,17 @@ Task<IPDFtkResult<byte[]>> FillFormAsync(string pdfFilePath,
7676
/// <param name="replacementFilePath">A PDF file path to replace the page with.</param>
7777
/// <returns>A result with the PDF form filled as a byte array.</returns>
7878
Task<IPDFtkResult<byte[]>> ReplacePage(string pdfFilePath, int page, string replacementFilePath);
79+
80+
/// <summary>
81+
/// Replaces a range of pages in a PDF with another PDF
82+
/// </summary>
83+
/// <param name="pdfFilePath">A PDF file path input.</param>
84+
/// <param name="startPage">The page to replace</param>
85+
/// <param name="endPage">The page to replace</param>
86+
/// <param name="replacementFilePath">A PDF file path to replace the page with.</param>
87+
/// <returns>A result with the PDF form filled as a byte array.</returns>
88+
Task<IPDFtkResult<byte[]>> ReplacePages(string pdfFilePath, int startPage, int endPage, string replacementFilePath);
89+
7990

8091
/// <summary>
8192
/// Extracts attachments from a PDF file.

src/Kevsoft.PDFtk/PDFtk.cs

Lines changed: 28 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -218,22 +218,29 @@ private static async Task<IPDFtkResult<IEnumerable<KeyValuePair<string, byte[]>>
218218
/// <inheritdoc/>
219219
public async Task<IPDFtkResult<byte[]>> ReplacePage(string pdfFilePath, int page, string replacementFilePath)
220220
{
221+
return await ReplacePages(pdfFilePath, page, page, replacementFilePath);
222+
}
223+
224+
/// <inheritdoc/>
225+
public async Task<IPDFtkResult<byte[]>> ReplacePages(string pdfFilePath, int startPage, int endPage, string replacementFilePath)
226+
{
227+
var range = new Range(startPage, endPage);
221228
var numberOfPagesAsync = await GetNumberOfPagesAsync(pdfFilePath);
222229
if (!numberOfPagesAsync.Success)
223230
return new PDFtkResult<byte[]>(numberOfPagesAsync.ExecutionResult, Array.Empty<byte>());
224-
var totalPages = numberOfPagesAsync.Result;
225-
if (page <= 0 || page > totalPages)
226-
throw new ArgumentException($"Invalid page to replace, min page is 1 and maximum is {totalPages}");
227231

228-
using var outputFile = TempPDFtkFile.Create();
232+
var totalPages = numberOfPagesAsync.Result;
233+
if (!range.IsValid || !range.IsInBounds(totalPages))
234+
throw new ArgumentException($"Invalid range of pages to replace, min page is 1 and maximum is {totalPages}");
229235

230-
var bounds = (firstPage: page == 1, lastPage: page == totalPages) switch
236+
var bounds = (firstPage: range.HasFirst(), lastPage: range.HasLast(totalPages)) switch
231237
{
232-
(firstPage: true, lastPage: false) => new[] { "B", $"A{page + 1}-end" },
233-
(firstPage: false, lastPage: true) => new[] { $"A1-{page - 1}", "B" },
234-
_ => new[] { $"A1-{page - 1}", "B", $"A{page + 1}-end" },
238+
(firstPage: true, lastPage: false) => new[] { "B", $"A{range.End + 1}-end" },
239+
(firstPage: false, lastPage: true) => new[] { $"A1-{range.Start - 1}", "B" },
240+
_ => new[] { $"A1-{range.Start - 1}", "B", $"A{range.End + 1}-end" },
235241
};
236242

243+
using var outputFile = TempPDFtkFile.Create();
237244
var args = new List<string>(8)
238245
{
239246
$"A={pdfFilePath}",
@@ -243,14 +250,11 @@ public async Task<IPDFtkResult<byte[]>> ReplacePage(string pdfFilePath, int page
243250
args.AddRange(bounds);
244251
args.Add("output");
245252
args.Add(outputFile.TempFileName);
246-
var executeProcessResult = await _pdftkProcess.ExecuteAsync(
247-
args.ToArray()
248-
);
253+
var executeProcessResult = await _pdftkProcess.ExecuteAsync(args.ToArray());
249254

250255
return await ResolveSingleFileExecutionResultAsync(executeProcessResult, outputFile);
251256
}
252257

253-
/// <inheritdoc/>
254258
public async Task<IPDFtkResult<IEnumerable<KeyValuePair<string, byte[]>>>> ExtractAttachments(string pdfFilePath)
255259
{
256260
using var outputDirectory = TempPDFtkDirectory.Create();
@@ -264,5 +268,17 @@ public async Task<IPDFtkResult<IEnumerable<KeyValuePair<string, byte[]>>>> Extra
264268

265269
return await ResolveSingleDirectoryExecutionResultAsync(executeProcessResult, outputDirectory, "*");
266270
}
271+
272+
private class Range
273+
{
274+
public int Start { get; }
275+
public int End { get; }
276+
public bool IsValid => Start <= End && Start > 0 && End > 0;
277+
public Range(int start, int end) => (Start, End) = (start, end);
278+
public bool IsInBounds(int? upper) => IsInBounds(1, upper);
279+
public bool IsInBounds(int? lower, int? upper) => Start >= lower && End <= upper;
280+
public bool HasFirst() => HasFirst(1);
281+
public bool HasFirst(int? first) => Start == first;
282+
public bool HasLast(int? last) => End == last;
267283
}
268284
}

src/Kevsoft.PDFtk/PDFtkByteArrayExtensions.cs

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -137,9 +137,27 @@ public static async Task<IPDFtkResult<byte[]>> FillFormAsync(this IPDFtk pdftk,
137137
public static async Task<IPDFtkResult<byte[]>> ReplacePage(this IPDFtk pdftk, byte[] fileBytes, int page, byte[] replacementFileBytes)
138138
{
139139
using var inputFile = await TempPDFtkFile.FromAsync(fileBytes);
140-
using var stampFile = await TempPDFtkFile.FromAsync(replacementFileBytes);
140+
using var replacementFile = await TempPDFtkFile.FromAsync(replacementFileBytes);
141141

142-
return await pdftk.ReplacePage(inputFile.TempFileName, page, stampFile.TempFileName);
142+
return await pdftk.ReplacePage(inputFile.TempFileName, page, replacementFile.TempFileName);
143+
}
144+
145+
/// <summary>
146+
/// Replaces a page in a PDF with another PDF
147+
/// </summary>
148+
/// <param name="pdftk">The IPDFtk object.</param>
149+
/// <param name="fileBytes">A byte array of the PDF file input.</param>
150+
/// <param name="startPage">The page to replace</param>
151+
/// <param name="endPage">The page to replace</param>
152+
/// <param name="replacementFileBytes">A byte array of the PDF file to replace the page with.</param>
153+
/// <returns>A result with the PDF form filled as a byte array.</returns>
154+
public static async Task<IPDFtkResult<byte[]>> ReplacePages(this IPDFtk pdftk, byte[] fileBytes, int startPage, int endPage,
155+
byte[] replacementFileBytes)
156+
{
157+
using var inputFile = await TempPDFtkFile.FromAsync(fileBytes);
158+
using var replacementFile = await TempPDFtkFile.FromAsync(replacementFileBytes);
159+
160+
return await pdftk.ReplacePages(inputFile.TempFileName, startPage, endPage, replacementFile.TempFileName);
143161
}
144162

145163
/// <summary>
@@ -154,6 +172,5 @@ public static async Task<IPDFtkResult<IEnumerable<KeyValuePair<string, byte[]>>>
154172

155173
return await pdftk.ExtractAttachments(inputFile.TempFileName);
156174
}
157-
158175
}
159176
}

src/Kevsoft.PDFtk/PDFtkStreamExtensions.cs

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -134,9 +134,26 @@ public static async Task<IPDFtkResult<byte[]>> FillFormAsync(this IPDFtk pdftk,
134134
public static async Task<IPDFtkResult<byte[]>> ReplacePage(this IPDFtk pdftk, Stream pdfFile, int page, Stream replacementPdfFile)
135135
{
136136
using var inputFile = await TempPDFtkFile.FromAsync(pdfFile);
137-
using var stampFile = await TempPDFtkFile.FromAsync(replacementPdfFile);
137+
using var replacementFile = await TempPDFtkFile.FromAsync(replacementPdfFile);
138138

139-
return await pdftk.ReplacePage(inputFile.TempFileName, page, stampFile.TempFileName);
139+
return await pdftk.ReplacePage(inputFile.TempFileName, page, replacementFile.TempFileName);
140+
}
141+
142+
/// <summary>
143+
/// Replaces a range of pages in a PDF with another PDF
144+
/// </summary>
145+
/// <param name="pdftk">The IPDFtk object.</param>
146+
/// <param name="pdfFile">A stream of the PDF file input.</param>
147+
/// <param name="startPage">The page to replace</param>
148+
/// <param name="endPage">The page to replace</param>
149+
/// <param name="replacementPdfFile">A stream of the PDF file to replace the page with.</param>
150+
/// <returns>A result with the PDF form filled as a byte array.</returns>
151+
public static async Task<IPDFtkResult<byte[]>> ReplacePage(this IPDFtk pdftk, Stream pdfFile, int startPage, int endPage, Stream replacementPdfFile)
152+
{
153+
using var inputFile = await TempPDFtkFile.FromAsync(pdfFile);
154+
using var replacementFile = await TempPDFtkFile.FromAsync(replacementPdfFile);
155+
156+
return await pdftk.ReplacePages(inputFile.TempFileName, startPage, endPage, replacementFile.TempFileName);
140157
}
141158

142159
/// <summary>

test/Kevsoft.PDFtk.Tests/ReplacePageTests.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ public async Task ShouldReturnPdfWithReplacedPage_ForReplacementPdfFile()
8383
result.Success.Should().BeFalse();
8484
result.Result.Should().BeEmpty();
8585
}
86-
86+
8787
[Theory]
8888
[InlineData(0)]
8989
[InlineData(11)]
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
using System;
2+
using System.IO;
3+
using System.Threading.Tasks;
4+
using FluentAssertions;
5+
using Xunit;
6+
7+
namespace Kevsoft.PDFtk.Tests
8+
{
9+
public class ReplacePagesTests
10+
{
11+
private readonly PDFtk _pdFtk = new();
12+
13+
private const int FirstPage = 1;
14+
private const int LastPage = 10;
15+
16+
[Theory]
17+
[InlineData(FirstPage, 3)]
18+
[InlineData(8, LastPage)]
19+
[InlineData(4, 6)]
20+
[InlineData(4, 8)]
21+
public async Task ShouldReturnPdfWithReplacedRangeOfPages(int start, int end)
22+
{
23+
const int totalPagesInserted = 2;
24+
25+
var result = await _pdFtk.ReplacePages(TestFiles.TestFile1Path, start,end, TestFiles.TestFileWith2PagesPath);
26+
27+
result.Success.Should().BeTrue();
28+
result.Result.Should().NotBeEmpty();
29+
(await _pdFtk.GetNumberOfPagesAsync(result.Result)).Result.Should().Be(LastPage - (end - start + 1) + totalPagesInserted);
30+
}
31+
}
32+
}

0 commit comments

Comments
 (0)