Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,26 @@ public async Task<Stream> DoOfficeMerge(string sourceDirectory)
return await _sharpClient.MergeOfficeDocsAsync(request);
}
```

### LibreOffice Conversion Options
*Fine-tune LibreOffice conversions with image compression, bookmarks, and native watermarks:*

```csharp
public async Task<Stream> ConvertWithOptions(string sourceDirectory)
{
var builder = new MergeOfficeBuilder()
.WithAsyncAssets(async a => a.AddItems(await GetDocsAsync(sourceDirectory)))
.SetLibreOfficeOptions(o => o
.SetQuality(85)
.SetReduceImageResolution()
.SetMaxImageResolution(300)
.SetExportBookmarks()
.SetNativeWatermarkText("DRAFT"));

var request = await builder.BuildAsync();
return await _sharpClient.MergeOfficeDocsAsync(request);
}
```
### Markdown to PDF
*Markdown to PDF conversion with embedded assets:*

Expand Down
2 changes: 2 additions & 0 deletions examples/LibreOfficeOptions/LibreOfficeOptions.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
<Project Sdk="Microsoft.NET.Sdk">
</Project>
74 changes: 74 additions & 0 deletions examples/LibreOfficeOptions/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
using Gotenberg.Sharp.API.Client;
using Gotenberg.Sharp.API.Client.Domain.Builders;
using Gotenberg.Sharp.API.Client.Domain.Settings;
using Gotenberg.Sharp.API.Client.Infrastructure.Pipeline;

using Microsoft.Extensions.Configuration;

var config = new ConfigurationBuilder()
.SetBasePath(AppContext.BaseDirectory)
.AddJsonFile("appsettings.json")
.Build();

var options = new GotenbergSharpClientOptions();
config.GetSection(nameof(GotenbergSharpClient)).Bind(options);

var sourceDirectory = args.Length > 0 ? args[0] : Path.Combine(AppContext.BaseDirectory, "resources", "OfficeDocs");
var destinationDirectory = args.Length > 1 ? args[1] : Path.Combine(Directory.GetCurrentDirectory(), "output");
Directory.CreateDirectory(destinationDirectory);

var path = await ConvertWithLibreOfficeOptions(sourceDirectory, destinationDirectory, options);
Console.WriteLine($"PDF with LibreOffice options created: {path}");

static async Task<string> ConvertWithLibreOfficeOptions(string sourceDirectory, string destinationDirectory, GotenbergSharpClientOptions options)
{
var handler = new HttpClientHandler();
HttpMessageHandler effectiveHandler = handler;
if (!string.IsNullOrWhiteSpace(options.BasicAuthUsername) && !string.IsNullOrWhiteSpace(options.BasicAuthPassword))
effectiveHandler = new BasicAuthHandler(options.BasicAuthUsername, options.BasicAuthPassword) { InnerHandler = handler };

using var httpClient = new HttpClient(effectiveHandler, disposeHandler: true)
{
BaseAddress = options.ServiceUrl,
Timeout = options.TimeOut
};

var client = new GotenbergSharpClient(httpClient);

// Demonstrates LibreOffice-specific conversion options
var builder = new MergeOfficeBuilder()
.WithAsyncAssets(async b => b.AddItems(await GetDocsAsync(sourceDirectory)))
.SetLibreOfficeOptions(o => o
// Image compression
.SetQuality(85)
.SetReduceImageResolution()
.SetMaxImageResolution(300)
// Export options
.SetExportBookmarks()
.SetExportFormFields(false)
.SetUpdateIndexes()
// Native watermark
.SetNativeWatermarkText("DRAFT")
.SetNativeWatermarkFontName("Arial")
)
.SetPdfOutputOptions(o => o.SetPdfFormat(PdfFormat.A2b));

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

var resultPath = Path.Combine(destinationDirectory, $"LibreOfficeOptions-{DateTime.Now:yyyyMMddHHmmss}.pdf");

await using var destinationStream = File.Create(resultPath);
await response.CopyToAsync(destinationStream, CancellationToken.None);

return resultPath;
}

static async Task<IEnumerable<KeyValuePair<string, byte[]>>> GetDocsAsync(string sourceDirectory)
{
var paths = Directory.GetFiles(sourceDirectory, "*.*", SearchOption.TopDirectoryOnly);
var names = paths.Select(p => new FileInfo(p).Name);
var tasks = paths.Select(f => File.ReadAllBytesAsync(f));
var docs = await Task.WhenAll(tasks);

return names.Select((name, index) => KeyValuePair.Create(name, docs[index])).Take(10);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,234 @@
// Copyright 2019-2026 Chris Mohan, Jaben Cargman
// and GotenbergSharpApiClient Contributors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

using Gotenberg.Sharp.API.Client.Domain.ValueObjects;

namespace Gotenberg.Sharp.API.Client.Domain.Builders.Faceted;

/// <summary>
/// Configures LibreOffice-specific conversion options for the /forms/libreoffice/convert route.
/// </summary>
public sealed class LibreOfficeOptionsBuilder
{
private readonly LibreOfficeOptions _options;

internal LibreOfficeOptionsBuilder(LibreOfficeOptions options)
{
_options = options;
}

// Layout

public LibreOfficeOptionsBuilder SetSinglePageSheets(bool value = true)
{
_options.SinglePageSheets = value;
return this;
}

public LibreOfficeOptionsBuilder SetSkipEmptyPages(bool value = true)
{
_options.SkipEmptyPages = value;
return this;
}

public LibreOfficeOptionsBuilder SetExportPlaceholders(bool value = true)
{
_options.ExportPlaceholders = value;
return this;
}

// Image compression

public LibreOfficeOptionsBuilder SetLosslessImageCompression(bool value = true)
{
_options.LosslessImageCompression = value;
return this;
}

public LibreOfficeOptionsBuilder SetQuality(ImageQuality quality)
{
_options.Quality = quality ?? throw new ArgumentNullException(nameof(quality));
return this;
}

public LibreOfficeOptionsBuilder SetQuality(int quality)
{
return SetQuality(ImageQuality.Create(quality));
}

public LibreOfficeOptionsBuilder SetReduceImageResolution(bool value = true)
{
_options.ReduceImageResolution = value;
return this;
}

public LibreOfficeOptionsBuilder SetMaxImageResolution(ImageResolution resolution)
{
_options.MaxImageResolution = resolution ?? throw new ArgumentNullException(nameof(resolution));
return this;
}

public LibreOfficeOptionsBuilder SetMaxImageResolution(int dpi)
{
return SetMaxImageResolution(ImageResolution.Create(dpi));
}

// Notes & slides

public LibreOfficeOptionsBuilder SetExportNotes(bool value = true)
{
_options.ExportNotes = value;
return this;
}

public LibreOfficeOptionsBuilder SetExportNotesPages(bool value = true)
{
_options.ExportNotesPages = value;
return this;
}

public LibreOfficeOptionsBuilder SetExportOnlyNotesPages(bool value = true)
{
_options.ExportOnlyNotesPages = value;
return this;
}

public LibreOfficeOptionsBuilder SetExportNotesInMargin(bool value = true)
{
_options.ExportNotesInMargin = value;
return this;
}

public LibreOfficeOptionsBuilder SetExportHiddenSlides(bool value = true)
{
_options.ExportHiddenSlides = value;
return this;
}

// Links

public LibreOfficeOptionsBuilder SetConvertOooTargetToPdfTarget(bool value = true)
{
_options.ConvertOooTargetToPdfTarget = value;
return this;
}

public LibreOfficeOptionsBuilder SetExportLinksRelativeFsys(bool value = true)
{
_options.ExportLinksRelativeFsys = value;
return this;
}

// Document outline

public LibreOfficeOptionsBuilder SetUpdateIndexes(bool value = true)
{
_options.UpdateIndexes = value;
return this;
}

public LibreOfficeOptionsBuilder SetExportBookmarks(bool value = true)
{
_options.ExportBookmarks = value;
return this;
}

public LibreOfficeOptionsBuilder SetExportBookmarksToPdfDestination(bool value = true)
{
_options.ExportBookmarksToPdfDestination = value;
return this;
}

public LibreOfficeOptionsBuilder SetAddOriginalDocumentAsStream(bool value = true)
{
_options.AddOriginalDocumentAsStream = value;
return this;
}

// Form fields

public LibreOfficeOptionsBuilder SetExportFormFields(bool value = true)
{
_options.ExportFormFields = value;
return this;
}

public LibreOfficeOptionsBuilder SetAllowDuplicateFieldNames(bool value = true)
{
_options.AllowDuplicateFieldNames = value;
return this;
}

// Native watermark

public LibreOfficeOptionsBuilder SetNativeWatermarkText(string text)
{
if (string.IsNullOrWhiteSpace(text))
throw new ArgumentException("Watermark text must not be null or empty.", nameof(text));

_options.NativeWatermarkText = text;
return this;
}

public LibreOfficeOptionsBuilder SetNativeWatermarkColor(int rgbDecimal)
{
_options.NativeWatermarkColor = rgbDecimal;
return this;
}

public LibreOfficeOptionsBuilder SetNativeWatermarkFontHeight(int fontHeight)
{
if (fontHeight < 0)
throw new ArgumentOutOfRangeException(nameof(fontHeight), "Font height must be non-negative.");

_options.NativeWatermarkFontHeight = fontHeight;
return this;
}

public LibreOfficeOptionsBuilder SetNativeWatermarkRotateAngle(int angle)
{
_options.NativeWatermarkRotateAngle = angle;
return this;
}

public LibreOfficeOptionsBuilder SetNativeWatermarkFontName(string fontName)
{
if (string.IsNullOrWhiteSpace(fontName))
throw new ArgumentException("Font name must not be null or empty.", nameof(fontName));

_options.NativeWatermarkFontName = fontName;
return this;
}

public LibreOfficeOptionsBuilder SetNativeTiledWatermarkText(string text)
{
if (string.IsNullOrWhiteSpace(text))
throw new ArgumentException("Tiled watermark text must not be null or empty.", nameof(text));

_options.NativeTiledWatermarkText = text;
return this;
}

// Source file password

public LibreOfficeOptionsBuilder SetPassword(string password)
{
if (string.IsNullOrWhiteSpace(password))
throw new ArgumentException("Password must not be null or empty.", nameof(password));

_options.Password = password;
return this;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,23 @@ public MergeOfficeBuilder SetPageRanges(string pageRanges)
return this;
}

/// <summary>
/// Configures LibreOffice-specific conversion options such as image compression,
/// notes export, bookmarks, form fields, and native watermarks.
/// </summary>
/// <param name="action">Configuration action for LibreOffice options.</param>
/// <returns>The builder instance for method chaining.</returns>
public MergeOfficeBuilder SetLibreOfficeOptions(Action<LibreOfficeOptionsBuilder> action)
{
if (action == null) throw new ArgumentNullException(nameof(action));

this.Request.LibreOfficeOptions ??= new LibreOfficeOptions();

action(new LibreOfficeOptionsBuilder(this.Request.LibreOfficeOptions));

return this;
}

/// <summary>
/// Converts the resulting merged PDF to the specified PDF/A format for long-term archival.
/// </summary>
Expand Down
Loading
Loading