Skip to content

Commit 857abf8

Browse files
committed
Merge branch 'release/2.7.0'
2 parents 7e567a6 + aacc127 commit 857abf8

File tree

6 files changed

+157
-28
lines changed

6 files changed

+157
-28
lines changed

README.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -164,9 +164,9 @@ public async Task<Stream> CreateFromMarkdown()
164164
.AddAsyncHeaderFooter(async
165165
b => b.SetHeader(await System.IO.File.ReadAllTextAsync(headerPath))
166166
.SetFooter(await System.IO.File.ReadAllBytesAsync(footerPath))
167-
).WithDimensions(dimBuilder =>
167+
).WithPageProperties(pp =>
168168
{
169-
dimBuilder.SetPaperSize(PaperSizes.A4)
169+
pp.SetPaperSize(PaperSizes.A4)
170170
.SetMargins(Margins.None)
171171
.SetScale(.90)
172172
.SetLandscape();
@@ -213,9 +213,9 @@ IEnumerable<UrlRequestBuilder> CreateBuilders(IEnumerable<Uri> uris)
213213
docBuilder.SetHeader(GetHeadFoot(uri.Host.Replace("www.", string.Empty).ToUpper()))
214214
.SetFooter(GetHeadFoot(uri.ToString()));
215215
})
216-
.WithDimensions(dimBuilder =>
216+
.WithPageProperties(pp =>
217217
{
218-
dimBuilder.UseChromeDefaults()
218+
pp.UseChromeDefaults()
219219
.SetScale(.90)
220220
.SetLandscape()
221221
.SetMarginLeft(.5)

lib/Domain/Builders/Faceted/ConfigBuilder.cs

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@
1313
// See the License for the specific language governing permissions and
1414
// limitations under the License.
1515

16+
using Gotenberg.Sharp.API.Client.Domain.Pages;
17+
1618
namespace Gotenberg.Sharp.API.Client.Domain.Builders.Faceted;
1719

1820
public sealed class ConfigBuilder
@@ -25,12 +27,16 @@ internal ConfigBuilder(RequestConfig requestConfig)
2527
}
2628

2729

28-
public ConfigBuilder SetPageRanges(string pageRanges)
30+
public ConfigBuilder SetPageRanges(string? pageRanges)
2931
{
30-
if (pageRanges.IsNotSet())
31-
throw new ArgumentException("Cannot be null or empty", nameof(pageRanges));
32+
this._requestConfig.PageRanges = Pages.PageRanges.Create(pageRanges);
3233

33-
this._requestConfig.PageRanges = pageRanges;
34+
return this;
35+
}
36+
37+
public ConfigBuilder SetPageRanges(PageRanges? pageRanges)
38+
{
39+
this._requestConfig.PageRanges = pageRanges ?? Pages.PageRanges.All;
3440

3541
return this;
3642
}

lib/Domain/Dimensions/Dimension.cs

Lines changed: 19 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ namespace Gotenberg.Sharp.API.Client.Domain.Dimensions;
5454
public sealed class Dimension(double value, DimensionUnitType unitType) : IEquatable<Dimension?>
5555
{
5656
private static readonly Regex ValidDimensionRegex =
57-
new(@"^\s*(\d+(\.\d+)?)\s*(pt|px|in|mm|cm|pc)\s*$", RegexOptions.IgnoreCase);
57+
new(@"^\s*(\d+(\.\d+)?)\s*(pt|px|in|mm|cm|pc)?\s*$", RegexOptions.IgnoreCase);
5858

5959
/// <summary>
6060
/// UnitType value
@@ -73,29 +73,28 @@ public bool Equals(Dimension? other)
7373
UnitType == other.UnitType;
7474
}
7575

76+
/// <summary>
77+
/// Parses a string like "200px", "11in", or defaults to inches if no unit is provided (e.g., "3.4").
78+
/// </summary>
79+
/// <param name="dimension"></param>
80+
/// <returns></returns>
81+
/// <exception cref="ArgumentException"></exception>
7682
public static Dimension Parse(string dimension)
7783
{
7884
if (string.IsNullOrWhiteSpace(dimension))
79-
{
80-
throw new ArgumentException("Dimension cannot be null or empty.",
81-
nameof(dimension));
82-
}
85+
throw new ArgumentException("Dimension cannot be null or empty.", nameof(dimension));
8386

8487
var match = ValidDimensionRegex.Match(dimension);
8588
if (!match.Success)
86-
{
87-
throw new ArgumentException(
88-
"Invalid dimension format. Expected formats: '200px', '11in', etc.",
89-
nameof(dimension));
90-
}
89+
throw new ArgumentException("Invalid dimension format. Expected formats: '200px', '11in', or default to inches.", nameof(dimension));
9190

92-
var value = double.Parse(match.Groups[1].Value);
93-
var unitStr = match.Groups[3].Value.ToLower();
91+
double value = double.Parse(match.Groups[1].Value);
92+
string? unitStr = match.Groups[3].Success ? match.Groups[3].Value.ToLower() : null;
9493

95-
if (!TryParseUnit(unitStr, out var unit))
96-
{
97-
throw new ArgumentException($"Unknown unitType '{unitStr}'", nameof(dimension));
98-
}
94+
// Default to Inches if no unit is provided
95+
DimensionUnitType unit = unitStr is not null && TryParseUnit(unitStr, out var parsedUnit)
96+
? parsedUnit
97+
: DimensionUnitType.Inches;
9998

10099
return new Dimension(value, unit);
101100
}
@@ -147,7 +146,10 @@ public static Dimension FromPicas(double picas)
147146

148147
public override string ToString()
149148
{
150-
return $"{Value}{UnitType.GetDescription()}";
149+
// if it's inches, don't supply anything.
150+
var unitType = UnitType == DimensionUnitType.Inches ? "" : UnitType.GetDescription();
151+
152+
return $"{Value}{unitType}";
151153
}
152154

153155
public override bool Equals(object? obj)

lib/Domain/Pages/PageRanges.cs

Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
// Copyright 2019-2025 Chris Mohan, Jaben Cargman
2+
// and GotenbergSharpApiClient Contributors
3+
//
4+
// Licensed under the Apache License, Version 2.0 (the "License");
5+
// you may not use this file except in compliance with the License.
6+
// You may obtain a copy of the License at
7+
//
8+
// http://www.apache.org/licenses/LICENSE-2.0
9+
//
10+
// Unless required by applicable law or agreed to in writing, software
11+
// distributed under the License is distributed on an "AS IS" BASIS,
12+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
// See the License for the specific language governing permissions and
14+
// limitations under the License.
15+
16+
using System.Text.RegularExpressions;
17+
18+
namespace Gotenberg.Sharp.API.Client.Domain.Pages;
19+
20+
public sealed class PageRanges : IEquatable<PageRanges>
21+
{
22+
private static readonly Regex PageRangePattern =
23+
new(@"^\s*(\d+(-\d+)?)(\s*,\s*(\d+(-\d+)?))*\s*$");
24+
25+
private PageRanges(IReadOnlyCollection<int> pages)
26+
{
27+
Pages = pages.OrderBy(p => p).ToArray();
28+
}
29+
30+
public static PageRanges All { get; } = new(Array.Empty<int>());
31+
32+
public IReadOnlyCollection<int> Pages { get; }
33+
34+
public bool Equals(PageRanges? other)
35+
{
36+
return other is not null && Pages.SequenceEqual(other.Pages);
37+
}
38+
39+
public static PageRanges Create(string? input)
40+
{
41+
if (string.IsNullOrWhiteSpace(input))
42+
{
43+
return All;
44+
}
45+
46+
if (!PageRangePattern.IsMatch(input))
47+
{
48+
throw new ArgumentOutOfRangeException(nameof(input),
49+
"Invalid page range format. Expected format: '1-5, 8, 11-13'.");
50+
}
51+
52+
var pages = new SortedSet<int>();
53+
foreach (var part in input!.Split([','], StringSplitOptions.RemoveEmptyEntries))
54+
{
55+
var trimmed = part.Trim();
56+
if (trimmed.Contains('-'))
57+
{
58+
var bounds = trimmed.Split('-').Select(int.Parse).ToArray();
59+
if (bounds.Length == 2 && bounds[0] <= bounds[1])
60+
{
61+
for (var i = bounds[0]; i <= bounds[1]; i++)
62+
{
63+
pages.Add(i);
64+
}
65+
}
66+
}
67+
else if (int.TryParse(trimmed, out var singlePage))
68+
{
69+
pages.Add(singlePage);
70+
}
71+
}
72+
73+
return new PageRanges(pages);
74+
}
75+
76+
private string GetPageRangeString()
77+
{
78+
// empty is "all"
79+
if (Pages.Count == 0)
80+
{
81+
return "";
82+
}
83+
84+
var ranges = new List<string>();
85+
int start = Pages.First(), end = start;
86+
87+
foreach (var page in Pages.Skip(1))
88+
{
89+
if (page == end + 1)
90+
{
91+
end = page;
92+
}
93+
else
94+
{
95+
ranges.Add(start == end ? start.ToString() : $"{start}-{end}");
96+
start = end = page;
97+
}
98+
}
99+
100+
ranges.Add(start == end ? start.ToString() : $"{start}-{end}");
101+
return string.Join(", ", ranges);
102+
}
103+
104+
public override string ToString()
105+
{
106+
return GetPageRangeString();
107+
}
108+
109+
public override bool Equals(object? obj)
110+
{
111+
return obj is PageRanges other && Pages.SequenceEqual(other.Pages);
112+
}
113+
114+
public override int GetHashCode()
115+
{
116+
return Pages.Aggregate(0, (hash, page) => hash ^ page.GetHashCode());
117+
}
118+
}

lib/Domain/Requests/Facets/RequestConfig.cs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@
1313
// See the License for the specific language governing permissions and
1414
// limitations under the License.
1515

16+
using Gotenberg.Sharp.API.Client.Domain.Pages;
17+
1618
namespace Gotenberg.Sharp.API.Client.Domain.Requests.Facets;
1719

1820
/// <summary>
@@ -29,7 +31,7 @@ public sealed class RequestConfig : IConvertToHttpContent
2931
// ReSharper disable once MethodTooLong
3032
public IEnumerable<HttpContent> ToHttpContent()
3133
{
32-
if (this.PageRanges.IsSet())
34+
if (this.PageRanges?.Pages.Any() ?? false)
3335
yield return BuildRequestBase.CreateFormDataItem(
3436
this.PageRanges,
3537
Constants.Gotenberg.Chromium.Shared.PageProperties.PageRanges);
@@ -64,7 +66,7 @@ public void Validate()
6466
/// The format is the same as the one from the print options of Google Chrome, e.g. 1-5,8,11-13.
6567
/// This may move...
6668
/// </remarks>
67-
public string? PageRanges { get; set; }
69+
public PageRanges? PageRanges { get; set; }
6870

6971
/// <summary>
7072
/// If provided, the API will return the resulting PDF file with the given filename. Otherwise a random filename is

lib/Gotenberg.Sharp.Api.Client.csproj

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,14 @@
1414
</PropertyGroup>
1515

1616
<PropertyGroup Label="PackageInfo">
17-
<PackageVersion>2.6</PackageVersion>
17+
<PackageVersion>2.7</PackageVersion>
1818
<PackageTags>Gotenberg pdf C# ApiClient unoconv</PackageTags>
1919
<Description>
2020
C# API client for interacting with the Gotenberg v7 &amp; v8 micro-service's API, a docker-powered stateless API for converting &amp; merging HTML, Markdown and Office documents to PDF. The client supports a configurable Polly retry policy with exponential back-off for handling transient exceptions.
2121
</Description>
2222
<IncludeSymbols>True</IncludeSymbols>
2323
<PackageReleaseNotes>
24+
v2.7 - Fixes issue with "Inches".
2425
v2.6 - Updated office Extensions. Added document metadata support. Add Dimension.FromUnit() support for dimensional values.
2526
v2.5 - Renamed "Dimentions" to "PageProperties". Added support for 'GenerateDocumentOutline' and 'OmitBackground.'
2627
v2.4 - Updated dependencies. Removed Annotations. Add support for PDF/UA form field. Thank you for the PR @lennartb-!

0 commit comments

Comments
 (0)