Skip to content

Commit 3462d99

Browse files
committed
Getting the Pdf Format working properly
Added SetPdfUa in all the places it's supported. Added "Flatten" Support.
1 parent 173ba60 commit 3462d99

29 files changed

Lines changed: 595 additions & 501 deletions

lib/Domain/Builders/BaseMergeBuilder.cs

Lines changed: 4 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright 2019-2025 Chris Mohan, Jaben Cargman
1+
// Copyright 2019-2025 Chris Mohan, Jaben Cargman
22
// and GotenbergSharpApiClient Contributors
33
//
44
// Licensed under the Apache License, Version 2.0 (the "License");
@@ -13,28 +13,11 @@
1313
// See the License for the specific language governing permissions and
1414
// limitations under the License.
1515

16-
17-
1816
namespace Gotenberg.Sharp.API.Client.Domain.Builders;
1917

20-
public abstract class BaseMergeBuilder<TRequest, TBuilder>(TRequest request)
21-
: BaseBuilder<TRequest, TBuilder>(request)
22-
where TRequest : BuildRequestBase
23-
where TBuilder : BaseMergeBuilder<TRequest, TBuilder>
18+
public abstract class BaseMergeBuilder<TRequest, TBuilder>(TRequest request) : BaseBuilder<TRequest, TBuilder>(request)
19+
where TRequest : BuildRequestBase where TBuilder : BaseMergeBuilder<TRequest, TBuilder>
2420
{
25-
/// <summary>
26-
/// This tells gotenberg to have OfficeLibre perform the conversion.
27-
/// If you set <see cref="MergeOfficeRequest.UseNativePdfFormat" /> to true
28-
/// then gotenberg will hand the work off to unoconv to do the work
29-
/// </summary>
30-
31-
public TBuilder SetPdfFormat(PdfFormats format)
32-
{
33-
this.Request.Format = format;
34-
return (TBuilder)this;
35-
}
36-
37-
3821
public TBuilder WithAssets(Action<AssetBuilder> action)
3922
{
4023
if (action == null) throw new ArgumentNullException(nameof(action));
@@ -44,13 +27,11 @@ public TBuilder WithAssets(Action<AssetBuilder> action)
4427
return (TBuilder)this;
4528
}
4629

47-
4830
public TBuilder WithAsyncAssets(Func<AssetBuilder, Task> asyncAction)
4931
{
5032
if (asyncAction == null) throw new ArgumentNullException(nameof(asyncAction));
5133

52-
this.BuildTasks.Add(
53-
asyncAction(new AssetBuilder(this.Request.Assets ??= new AssetDictionary())));
34+
this.BuildTasks.Add(asyncAction(new AssetBuilder(this.Request.Assets ??= new AssetDictionary())));
5435

5536
return (TBuilder)this;
5637
}

lib/Domain/Builders/Faceted/AssetBuilder.cs

Lines changed: 12 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright 2019-2025 Chris Mohan, Jaben Cargman
1+
// Copyright 2019-2025 Chris Mohan, Jaben Cargman
22
// and GotenbergSharpApiClient Contributors
33
//
44
// Licensed under the Apache License, Version 2.0 (the "License");
@@ -13,8 +13,6 @@
1313
// See the License for the specific language governing permissions and
1414
// limitations under the License.
1515

16-
17-
1816
namespace Gotenberg.Sharp.API.Client.Domain.Builders.Faceted
1917
{
2018
public sealed class AssetBuilder
@@ -26,12 +24,10 @@ internal AssetBuilder(AssetDictionary assets)
2624
this._assets = assets;
2725
}
2826

29-
3027
public AssetBuilder AddItem(string name, ContentItem value)
3128
{
3229
// ReSharper disable once ComplexConditionExpression
33-
if (name.IsNotSet() || new FileInfo(name).Extension.IsNotSet()
34-
|| name.LastIndexOf('/') >= 0)
30+
if (name.IsNotSet() || new FileInfo(name).Extension.IsNotSet() || name.LastIndexOf('/') >= 0)
3531
{
3632
throw new ArgumentOutOfRangeException(
3733
nameof(name),
@@ -43,23 +39,16 @@ public AssetBuilder AddItem(string name, ContentItem value)
4339
return this;
4440
}
4541

46-
47-
public AssetBuilder AddItem(string name, string value) =>
48-
AddItem(name, new ContentItem(value));
42+
public AssetBuilder AddItem(string name, string value) => AddItem(name, new ContentItem(value));
4943

50-
51-
public AssetBuilder AddItem(string name, byte[] value) =>
52-
AddItem(name, new ContentItem(value));
44+
public AssetBuilder AddItem(string name, byte[] value) => AddItem(name, new ContentItem(value));
5345

54-
55-
public AssetBuilder AddItem(string name, Stream value) =>
56-
AddItem(name, new ContentItem(value));
46+
public AssetBuilder AddItem(string name, Stream value) => AddItem(name, new ContentItem(value));
5747

5848
#region 'n' assets
5949

6050
#region from dictionaries
6151

62-
6352
public AssetBuilder AddItems(Dictionary<string, ContentItem>? items)
6453
{
6554
foreach (var item in items.IfNullEmpty())
@@ -70,47 +59,39 @@ public AssetBuilder AddItems(Dictionary<string, ContentItem>? items)
7059
return this;
7160
}
7261

73-
7462
public AssetBuilder AddItems(Dictionary<string, string>? assets) =>
7563
AddItems(assets?.ToDictionary(a => a.Key, a => new ContentItem(a.Value)));
7664

77-
7865
public AssetBuilder AddItems(Dictionary<string, byte[]>? assets) =>
7966
AddItems(assets?.ToDictionary(a => a.Key, a => new ContentItem(a.Value)));
8067

81-
8268
public AssetBuilder AddItems(Dictionary<string, Stream>? assets) =>
8369
AddItems(assets?.ToDictionary(a => a.Key, a => new ContentItem(a.Value)));
8470

8571
#endregion
8672

8773
#region from KVP enumerables
8874

89-
9075
public AssetBuilder AddItems(IEnumerable<KeyValuePair<string, ContentItem>> assets) =>
9176
AddItems(
9277
new Dictionary<string, ContentItem>(
93-
assets?.ToDictionary(a => a.Key, a => a.Value) ??
94-
throw new ArgumentNullException(nameof(assets))));
78+
assets?.ToDictionary(a => a.Key, a => a.Value) ?? throw new ArgumentNullException(nameof(assets))));
9579

96-
9780
public AssetBuilder AddItems(IEnumerable<KeyValuePair<string, string>> assets) =>
9881
AddItems(
9982
new Dictionary<string, ContentItem>(
100-
assets?.ToDictionary(a => a.Key, a => new ContentItem(a.Value)) ??
101-
throw new ArgumentNullException(nameof(assets))));
83+
assets?.ToDictionary(a => a.Key, a => new ContentItem(a.Value))
84+
?? throw new ArgumentNullException(nameof(assets))));
10285

103-
10486
public AssetBuilder AddItems(IEnumerable<KeyValuePair<string, byte[]>> assets) =>
10587
AddItems(
106-
assets?.ToDictionary(a => a.Key, a => new ContentItem(a.Value)) ??
107-
throw new ArgumentNullException(nameof(assets)));
88+
assets?.ToDictionary(a => a.Key, a => new ContentItem(a.Value))
89+
?? throw new ArgumentNullException(nameof(assets)));
10890

109-
11091
public AssetBuilder AddItems(IEnumerable<KeyValuePair<string, Stream>> assets) =>
11192
AddItems(
112-
assets?.ToDictionary(s => s.Key, a => new ContentItem(a.Value)) ??
113-
throw new ArgumentNullException(nameof(assets)));
93+
assets?.ToDictionary(s => s.Key, a => new ContentItem(a.Value))
94+
?? throw new ArgumentNullException(nameof(assets)));
11495

11596
#endregion
11697

lib/Domain/Builders/Faceted/ConfigBuilder.cs

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright 2019-2025 Chris Mohan, Jaben Cargman
1+
// Copyright 2019-2025 Chris Mohan, Jaben Cargman
22
// and GotenbergSharpApiClient Contributors
33
//
44
// Licensed under the Apache License, Version 2.0 (the "License");
@@ -26,7 +26,6 @@ internal ConfigBuilder(RequestConfig requestConfig)
2626
this._requestConfig = requestConfig;
2727
}
2828

29-
3029
public ConfigBuilder SetPageRanges(string? pageRanges)
3130
{
3231
this._requestConfig.PageRanges = Pages.PageRanges.Create(pageRanges);
@@ -41,14 +40,12 @@ public ConfigBuilder SetPageRanges(PageRanges? pageRanges)
4140
return this;
4241
}
4342

44-
4543
[Obsolete("Renamed: Use SetPageRanges")]
4644
public ConfigBuilder PageRanges(string pageRanges)
4745
{
4846
return this.SetPageRanges(pageRanges);
4947
}
5048

51-
5249
public ConfigBuilder SetResultFileName(string resultFileName)
5350
{
5451
if (resultFileName.IsNotSet())
@@ -59,13 +56,12 @@ public ConfigBuilder SetResultFileName(string resultFileName)
5956
return this;
6057
}
6158

62-
6359
[Obsolete("Renamed: Use SetResultFileName")]
6460
public ConfigBuilder ResultFileName(string resultFileName)
6561
{
6662
return this.SetResultFileName(resultFileName);
6763
}
68-
64+
6965
public ConfigBuilder SetTrace(string trace)
7066
{
7167
if (trace.IsNotSet())
@@ -93,7 +89,7 @@ public ConfigBuilder SetWebhook(Webhook webhook)
9389

9490
return this;
9591
}
96-
92+
9793
[Obsolete("Renamed: Use SetWebhook instead.")]
9894
public ConfigBuilder AddWebhook(Webhook webhook)
9995
{
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
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+
namespace Gotenberg.Sharp.API.Client.Domain.Builders.Faceted
17+
{
18+
public enum ConversionPdfFormats
19+
{
20+
/// <summary>
21+
/// No PDF conformance format specified.
22+
/// </summary>
23+
None = 0,
24+
25+
/// <summary>
26+
/// PDF/A-1b format.
27+
/// Long-term archiving conformance with basic visual reproducibility.
28+
/// </summary>
29+
A1b = 1,
30+
31+
/// <summary>
32+
/// PDF/A-2b format.
33+
/// Similar to A-2a but without requiring logical structure or tagging.
34+
/// </summary>
35+
A2b = 2,
36+
37+
/// <summary>
38+
/// PDF/A-3b format.
39+
/// Like A-3a but focused on visual fidelity, without logical tagging.
40+
/// </summary>
41+
A3b = 3,
42+
}
43+
}

lib/Domain/Builders/Faceted/HtmlConversionBehaviorBuilder.cs

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ public HtmlConversionBehaviorBuilder AddAdditionalHeaders(JObject extraHeaders)
110110
/// <returns></returns>
111111
public HtmlConversionBehaviorBuilder SetMetadata(IDictionary<string, object> dictionary)
112112
{
113-
SetMetadata(new JObject(dictionary));
113+
SetMetadata(JObject.FromObject(dictionary));
114114

115115
return this;
116116
}
@@ -121,7 +121,6 @@ public HtmlConversionBehaviorBuilder SetMetadata(IDictionary<string, object> dic
121121
/// </summary>
122122
/// <param name="metadata"></param>
123123
/// <returns></returns>
124-
125124
public HtmlConversionBehaviorBuilder SetMetadata(JObject metadata)
126125
{
127126
if (metadata == null) throw new InvalidOperationException("metadata is null");
@@ -170,12 +169,22 @@ public HtmlConversionBehaviorBuilder SkipNetworkIdleEvent()
170169
/// <param name="format"></param>
171170
/// <returns></returns>
172171
/// <exception cref="InvalidOperationException"></exception>
173-
public HtmlConversionBehaviorBuilder SetPdfFormat(PdfFormats format)
172+
public HtmlConversionBehaviorBuilder SetPdfFormat(ConversionPdfFormats format)
174173
{
175174
if (format == default) throw new InvalidOperationException("Invalid PDF format specified");
176175

177176
this._htmlConversionBehaviors.PdfFormat = format;
178177

179178
return this;
180179
}
180+
181+
/// <summary>
182+
/// This tells gotenberg to enable Universal Access for the resulting PDF.
183+
/// </summary>
184+
public HtmlConversionBehaviorBuilder SetPdfUa(bool enablePdfUa = true)
185+
{
186+
this._htmlConversionBehaviors.EnablePdfUa = enablePdfUa;
187+
188+
return this;
189+
}
181190
}
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
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.Diagnostics.CodeAnalysis;
17+
18+
namespace Gotenberg.Sharp.API.Client.Domain.Builders.Faceted;
19+
20+
[SuppressMessage("ReSharper", "InconsistentNaming")]
21+
public enum LibrePdfFormats
22+
{
23+
/// <summary>
24+
/// No PDF conformance format specified.
25+
/// </summary>
26+
None = 0,
27+
28+
/// <summary>
29+
/// PDF/A-1a format.
30+
/// Ensures accessibility and document structure (tagged PDF).
31+
/// Obsolete as of Gotenberg 7.6 — LibreOffice no longer supports it.
32+
/// </summary>
33+
[Obsolete(
34+
"Beginning with version Gotenberg 7.6, LibreOffice has discontinued support for PDF/A-1a: https://gotenberg.dev/docs/troubleshooting#pdfa-1a")]
35+
A1a = 1,
36+
37+
/// <summary>
38+
/// PDF/A-1b format.
39+
/// Long-term archiving conformance with basic visual reproducibility.
40+
/// </summary>
41+
A1b = 2,
42+
43+
/// <summary>
44+
/// PDF/A-2a format.
45+
/// Builds on A-1a with improved compression and transparency support; includes tagged structure.
46+
/// </summary>
47+
A2a = 3,
48+
49+
/// <summary>
50+
/// PDF/A-2b format.
51+
/// Similar to A-2a but without requiring logical structure or tagging.
52+
/// </summary>
53+
A2b = 4,
54+
55+
/// <summary>
56+
/// PDF/A-2u format.
57+
/// Like A-2b but requires Unicode mapping for all text (for searchability).
58+
/// </summary>
59+
A2u = 5,
60+
61+
/// <summary>
62+
/// PDF/A-3a format.
63+
/// Allows embedded files; includes full tagging for accessibility.
64+
/// Useful for workflows that require attaching source data (e.g., XML, spreadsheets).
65+
/// </summary>
66+
A3a = 6,
67+
68+
/// <summary>
69+
/// PDF/A-3b format.
70+
/// Like A-3a but focused on visual fidelity, without logical tagging.
71+
/// </summary>
72+
A3b = 7,
73+
74+
/// <summary>
75+
/// PDF/A-3u format.
76+
/// Combines A-3b conformance with Unicode text requirements.
77+
/// </summary>
78+
A3u = 8
79+
}

lib/Domain/Builders/Faceted/PagePropertyBuilder.cs

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -269,10 +269,5 @@ public PagePropertyBuilder UseChromeDefaults()
269269
return this.SetPageProperties(PageProperties.ToChromeDefaults());
270270
}
271271

272-
public PagePropertyBuilder UseDeliverableDefaults()
273-
{
274-
return this.SetPageProperties(PageProperties.ToDeliverableDefault());
275-
}
276-
277272
#endregion
278273
}

0 commit comments

Comments
 (0)