Skip to content

Commit 1dfe282

Browse files
committed
Centralized the PdfOutput features.
1 parent bbe70f5 commit 1dfe282

21 files changed

Lines changed: 391 additions & 268 deletions

README.md

Lines changed: 11 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -216,7 +216,7 @@ public async Task<Stream> DoOfficeMerge(string sourceDirectory)
216216
{
217217
var builder = new MergeOfficeBuilder()
218218
.WithAsyncAssets(async a => a.AddItems(await GetDocsAsync(sourceDirectory)))
219-
.SetPdfFormat(LibrePdfFormats.A2b);
219+
.SetPdfOutputOptions(o => o.SetPdfFormat(PdfFormat.A2b));
220220

221221
var request = await builder.BuildAsync();
222222
return await _sharpClient.MergeOfficeDocsAsync(request);
@@ -281,16 +281,13 @@ public async Task<Stream> CreatePdfWithMetadata()
281281
{
282282
var builder = new HtmlRequestBuilder()
283283
.AddDocument(doc => doc.SetBody("<html><body><h1>Document with Metadata</h1></body></html>"))
284-
.SetConversionBehaviors(b =>
284+
.SetPdfOutputOptions(o => o.SetMetadata(new Dictionary<string, object>
285285
{
286-
b.SetMetadata(new Dictionary<string, object>
287-
{
288-
{ "Author", "John Doe" },
289-
{ "Title", "My Document" },
290-
{ "Subject", "Important Report" },
291-
{ "Keywords", "report, PDF, gotenberg" }
292-
});
293-
})
286+
{ "Author", "John Doe" },
287+
{ "Title", "My Document" },
288+
{ "Subject", "Important Report" },
289+
{ "Keywords", "report, PDF, gotenberg" }
290+
}))
294291
.WithPageProperties(pp => pp.UseChromeDefaults());
295292

296293
var request = await builder.BuildAsync();
@@ -306,7 +303,7 @@ public async Task<Stream> ConvertToPdfA(string pdfPath)
306303
{
307304
var builder = new PdfConversionBuilder()
308305
.WithPdfs(b => b.AddItem("document.pdf", File.ReadAllBytes(pdfPath)))
309-
.SetPdfFormat(LibrePdfFormats.A2b);
306+
.SetPdfOutputOptions(o => o.SetPdfFormat(PdfFormat.A2b));
310307

311308
var request = await builder.BuildAsync();
312309
return await _sharpClient.ConvertPdfDocumentsAsync(request);
@@ -441,7 +438,7 @@ public async Task<Stream> CreateAccessiblePdf()
441438
{
442439
var builder = new HtmlRequestBuilder()
443440
.AddDocument(doc => doc.SetBody("<html><body><h1>Accessible Document</h1></body></html>"))
444-
.SetConversionBehaviors(b => b.SetPdfUa(true))
441+
.SetPdfOutputOptions(o => o.SetPdfUa())
445442
.WithPageProperties(pp => pp.UseChromeDefaults());
446443

447444
var request = await builder.BuildAsync();
@@ -457,8 +454,7 @@ public async Task<Stream> ConvertToAccessiblePdfA(string pdfPath)
457454
{
458455
var builder = new PdfConversionBuilder()
459456
.WithPdfs(b => b.AddItem("document.pdf", File.ReadAllBytes(pdfPath)))
460-
.SetPdfFormat(LibrePdfFormats.A2b)
461-
.EnablePdfUa(true);
457+
.SetPdfOutputOptions(o => o.SetPdfFormat(PdfFormat.A2b).SetPdfUa());
462458

463459
var request = await builder.BuildAsync();
464460
return await _sharpClient.ConvertPdfDocumentsAsync(request);
@@ -473,7 +469,7 @@ public async Task<Stream> FlattenPdf(string pdfPath)
473469
{
474470
var builder = new PdfConversionBuilder()
475471
.WithPdfs(b => b.AddItem("form.pdf", File.ReadAllBytes(pdfPath)))
476-
.EnableFlatten(true);
472+
.SetPdfOutputOptions(o => o.SetFlatten());
477473

478474
var request = await builder.BuildAsync();
479475
return await _sharpClient.ConvertPdfDocumentsAsync(request);

examples/OfficeMerge/Program.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ static async Task<string> DoOfficeMerge(string sourceDirectory, string destinati
3939
var builder = new MergeOfficeBuilder()
4040
.ConfigureRequest(c => c.SetTrace("ConsoleExample"))
4141
.WithAsyncAssets(async b => b.AddItems(await GetDocsAsync(sourceDirectory)))
42-
.SetPdfFormat(LibrePdfFormats.A2b)
42+
.SetPdfOutputOptions(o => o.SetPdfFormat(PdfFormat.A2b))
4343
.SetPageRanges("1-3"); // Only one of the files has more than 1 page.
4444

4545
var response = await client.MergeOfficeDocsAsync(builder).ConfigureAwait(false);

examples/PdfConvert/Program.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ static async Task<string> DoConversion(string sourcePath, string destinationPath
5454

5555
var builder = new PdfConversionBuilder()
5656
.WithPdfs(b => b.AddItems(toConvert))
57-
.SetPdfFormat(LibrePdfFormats.A2b);
57+
.SetPdfOutputOptions(o => o.SetPdfFormat(PdfFormat.A2b));
5858

5959
var request = builder.Build();
6060
var response = await sharpClient.ConvertPdfDocumentsAsync(request);

examples/PdfMerge/Program.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ static async Task<string> DoMerge(string sourcePath, string destinationPath, Got
5050
var toMerge = items.Select(item => KeyValuePair.Create(item.Info.Name, File.ReadAllBytes(item.Path)));
5151

5252
var builder = new MergeBuilder()
53-
.SetPdfFormat(LibrePdfFormats.A2b)
53+
.SetPdfOutputOptions(o => o.SetPdfFormat(PdfFormat.A2b))
5454
.WithAssets(b => { b.AddItems(toMerge); });
5555

5656
var request = builder.Build();

src/Gotenberg.Sharp.Api.Client/Domain/Builders/BaseBuilder.cs

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,35 @@ public TBuilder ConfigureRequest(RequestConfig config)
5959
return (TBuilder)this;
6060
}
6161

62+
/// <summary>
63+
/// Configures PDF output options shared across all request types, including PDF/A format,
64+
/// PDF/UA accessibility, flatten, tagged PDF generation, and metadata.
65+
/// </summary>
66+
/// <param name="action">Configuration action for PDF output options.</param>
67+
/// <returns>The builder instance for method chaining.</returns>
68+
public TBuilder SetPdfOutputOptions(Action<PdfOutputOptionsBuilder> action)
69+
{
70+
if (action == null) throw new ArgumentNullException(nameof(action));
71+
72+
this.Request.PdfOutputOptions ??= new PdfOutputOptions();
73+
74+
action(new PdfOutputOptionsBuilder(this.Request.PdfOutputOptions));
75+
76+
return (TBuilder)this;
77+
}
78+
79+
/// <summary>
80+
/// Sets pre-configured PDF output options.
81+
/// </summary>
82+
/// <param name="options">Pre-configured PdfOutputOptions instance.</param>
83+
/// <returns>The builder instance for method chaining.</returns>
84+
public TBuilder SetPdfOutputOptions(PdfOutputOptions options)
85+
{
86+
this.Request.PdfOutputOptions = options ?? throw new ArgumentNullException(nameof(options));
87+
88+
return (TBuilder)this;
89+
}
90+
6291
/// <summary>
6392
/// Builds the request synchronously. Use when all content is already in memory (no async operations).
6493
/// </summary>

src/Gotenberg.Sharp.Api.Client/Domain/Builders/Faceted/HtmlConversionBehaviorBuilder.cs

Lines changed: 31 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
1-
// Copyright 2019-2025 Chris Mohan, Jaben Cargman
1+
// Copyright 2019-2025 Chris Mohan, Jaben Cargman
22
// and GotenbergSharpApiClient Contributors
3-
//
3+
//
44
// Licensed under the Apache License, Version 2.0 (the "License");
55
// you may not use this file except in compliance with the License.
66
// You may obtain a copy of the License at
7-
//
7+
//
88
// http://www.apache.org/licenses/LICENSE-2.0
9-
//
9+
//
1010
// Unless required by applicable law or agreed to in writing, software
1111
// distributed under the License is distributed on an "AS IS" BASIS,
1212
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -19,8 +19,12 @@ namespace Gotenberg.Sharp.API.Client.Domain.Builders.Faceted;
1919

2020
/// <summary>
2121
/// Configures Chromium rendering behaviors for HTML and URL to PDF conversions.
22-
/// Includes settings for wait delays, HTTP headers, cookies, metadata, PDF format, and accessibility.
22+
/// Includes settings for wait delays, HTTP headers, cookies, media emulation, and error handling.
2323
/// </summary>
24+
/// <remarks>
25+
/// PDF output options (PDF/A, PDF/UA, flatten, tagged PDF, metadata) have moved to
26+
/// <see cref="PdfOutputOptionsBuilder"/> which is available via <c>SetPdfOutputOptions()</c> on all builders.
27+
/// </remarks>
2428
public sealed class HtmlConversionBehaviorBuilder
2529
{
2630
private readonly HtmlConversionBehaviors _htmlConversionBehaviors;
@@ -137,39 +141,6 @@ public HtmlConversionBehaviorBuilder AddCookie(Cookie cookie)
137141
return this;
138142
}
139143

140-
/// <summary>
141-
/// Sets the document metadata.
142-
/// Not all metadata are writable. Consider taking a look at https://exiftool.org/TagNames/XMP.html#pdf for an
143-
/// (exhaustive?) list of available metadata.
144-
/// </summary>
145-
/// <param name="dictionary"></param>
146-
/// <returns></returns>
147-
public HtmlConversionBehaviorBuilder SetMetadata(IDictionary<string, object> dictionary)
148-
{
149-
SetMetadata(JObject.FromObject(dictionary));
150-
151-
return this;
152-
}
153-
154-
/// <summary>
155-
/// Sets the document metadata.
156-
/// Not all metadata are writable. Consider taking a look at https://exiftool.org/TagNames/XMP.html#pdf for an
157-
/// (exhaustive?) list of available metadata.
158-
/// </summary>
159-
/// <param name="metadata"></param>
160-
/// <returns></returns>
161-
public HtmlConversionBehaviorBuilder SetMetadata(JObject metadata)
162-
{
163-
if (metadata == null)
164-
{
165-
throw new InvalidOperationException("metadata is null");
166-
}
167-
168-
_htmlConversionBehaviors.MetaData = metadata;
169-
170-
return this;
171-
}
172-
173144
/// <summary>
174145
/// Tells gotenberg to return a 409 response if there are exceptions in the Chromium console.
175146
/// </summary>
@@ -204,40 +175,47 @@ public HtmlConversionBehaviorBuilder SkipNetworkIdleEvent()
204175
}
205176

206177
/// <summary>
207-
/// Sets the format of the resulting PDF document
178+
/// Sets the format of the resulting PDF document.
208179
/// </summary>
209-
/// <param name="format"></param>
210-
/// <returns></returns>
211-
/// <exception cref="InvalidOperationException"></exception>
180+
[Obsolete("Use SetPdfOutputOptions(o => o.SetPdfFormat(...)) on the builder instead")]
212181
public HtmlConversionBehaviorBuilder SetPdfFormat(ConversionPdfFormats format)
213182
{
214-
if (format == default)
215-
{
216-
throw new InvalidOperationException("Invalid PDF format specified");
217-
}
218-
219-
_htmlConversionBehaviors.PdfFormat = format;
220-
221183
return this;
222184
}
223185

224186
/// <summary>
225187
/// This tells gotenberg to enable Universal Access for the resulting PDF.
226188
/// </summary>
189+
[Obsolete("Use SetPdfOutputOptions(o => o.SetPdfUa()) on the builder instead")]
227190
public HtmlConversionBehaviorBuilder SetPdfUa(bool enablePdfUa = true)
228191
{
229-
_htmlConversionBehaviors.EnablePdfUa = enablePdfUa;
230-
231192
return this;
232193
}
233194

234195
/// <summary>
235196
/// This tells gotenberg to enable embeds logical structure tags for accessibility during generation.
236197
/// </summary>
198+
[Obsolete("Use SetPdfOutputOptions(o => o.SetGenerateTaggedPdf()) on the builder instead")]
237199
public HtmlConversionBehaviorBuilder SetGenerateTaggedPdf(bool generateTaggedPdf = true)
238200
{
239-
_htmlConversionBehaviors.GenerateTaggedPdf = generateTaggedPdf;
201+
return this;
202+
}
203+
204+
/// <summary>
205+
/// Sets the document metadata.
206+
/// </summary>
207+
[Obsolete("Use SetPdfOutputOptions(o => o.SetMetadata(...)) on the builder instead")]
208+
public HtmlConversionBehaviorBuilder SetMetadata(IDictionary<string, object> dictionary)
209+
{
210+
return this;
211+
}
240212

213+
/// <summary>
214+
/// Sets the document metadata.
215+
/// </summary>
216+
[Obsolete("Use SetPdfOutputOptions(o => o.SetMetadata(...)) on the builder instead")]
217+
public HtmlConversionBehaviorBuilder SetMetadata(JObject metadata)
218+
{
241219
return this;
242220
}
243-
}
221+
}
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
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+
/// <summary>
21+
/// PDF/A conformance formats supported by Gotenberg across all modules (Chromium, LibreOffice, PDF Engines).
22+
/// </summary>
23+
[SuppressMessage("ReSharper", "InconsistentNaming")]
24+
public enum PdfFormat
25+
{
26+
/// <summary>
27+
/// No PDF conformance format specified.
28+
/// </summary>
29+
None = 0,
30+
31+
/// <summary>
32+
/// PDF/A-1b format.
33+
/// Long-term archiving conformance with basic visual reproducibility.
34+
/// </summary>
35+
A1b = 1,
36+
37+
/// <summary>
38+
/// PDF/A-2b format.
39+
/// Similar to A-2a but without requiring logical structure or tagging.
40+
/// </summary>
41+
A2b = 2,
42+
43+
/// <summary>
44+
/// PDF/A-3b format.
45+
/// Like A-3a but focused on visual fidelity, without logical tagging.
46+
/// </summary>
47+
A3b = 3,
48+
}

0 commit comments

Comments
 (0)