LibreOfficeKit 1.0.6
dotnet add package LibreOfficeKit --version 1.0.6
NuGet\Install-Package LibreOfficeKit -Version 1.0.6
<PackageReference Include="LibreOfficeKit" Version="1.0.6" />
<PackageVersion Include="LibreOfficeKit" Version="1.0.6" />
<PackageReference Include="LibreOfficeKit" />
paket add LibreOfficeKit --version 1.0.6
#r "nuget: LibreOfficeKit, 1.0.6"
#:package LibreOfficeKit@1.0.6
#addin nuget:?package=LibreOfficeKit&version=1.0.6
#tool nuget:?package=LibreOfficeKit&version=1.0.6
LibreOfficeKit
A .NET library and console application for document-to-PDF conversion using LibreOfficeKit, featuring a multi-process worker pool for safe concurrent conversions.
NuGet
Using it on Windows
At the moment this package does not work with Excel and Powerpoint files on Windows, I have raised a ticket for this --> https://bugs.documentfoundation.org/show_bug.cgi?id=172283
Update: It seems to be a problem with LibreOffice versions newer than 25.2.6.2, so if you install this version it will work
Documentation
Full API reference documentation (generated by DocFX) is published automatically to GitHub Pages on every push to main:
https://sicos1977.github.io/LibreOfficeKit
Architecture
LibreOfficeKit (LOK) is not thread-safe — only one instance per process is allowed. To enable concurrent conversions, this project uses a process pool architecture:
- The host process (
Converter) manages a pool of isolated worker processes. - Each worker connects via a named pipe, initializes its own LOK instance, and processes one request at a time.
- The host dispatches conversion requests to free workers and queues requests when all workers are busy.
- Workers are health-monitored via periodic pings and recycled if they crash or hang.
Solution Structure
| Project | Type | Target | Description |
|---|---|---|---|
LibreOfficeKit |
Class Library | .NET Standard 2.0 | Core library: Converter, WorkerProcess, IPC, LOK bindings, Enums |
LibreOfficeKitWorker |
Console App | .NET 10 | Worker entry point and optional standalone demo |
LibreOfficeTest |
Test Project | .NET 10 | MSTest integration tests |
LibreOfficeKitWorker (Console App)
| File | Description |
|---|---|
Program.cs |
Worker entry point; also supports a standalone demo/test mode |
Features
- Hot standby: Pre-spawned workers for immediate conversion
- On-demand scaling: Scale up to
maxInstancesas needed - Idle timeout: Excess workers shut down automatically after an idle period
- Health monitoring: Background pings detect crashed or hung workers
- Request queuing: Requests queue when all workers are busy
- Conversion timeout: Optional per-call timeout with
TimeoutException - Stream support: Convert from/to
Stream(uses temp files internally) - PDF options: Full control over PDF export quality, compliance, security and layout via
PdfOptions - Enum-based API: Type-safe save formats and document types
- Proper disposal:
IDisposableandIAsyncDisposablefor clean shutdown
Usage
Basic conversion (file paths)
using LibreOfficeKit;
await using var converter = new Converter(
maxInstances: 4,
minHotStandby: 2,
idleTimeout: TimeSpan.FromMinutes(5));
await converter.ConvertToPdfAsync("input.docx", "output.pdf");
With a timeout
await converter.ConvertToPdfAsync(
"input.docx",
"output.pdf",
timeout: TimeSpan.FromSeconds(30));
With PDF options
using LibreOfficeKit;
var options = new PdfOptions
{
Quality = 95,
ReduceImageResolution = true,
MaxImageResolutionDpi = 150,
UseTaggedPdf = true,
ExportBookmarks = true,
PageRange = "1-10"
};
await converter.ConvertToPdfAsync("input.docx", "output.pdf", pdfOptions: options);
Using a preset
await converter.ConvertToPdfAsync(
"input.docx",
"output.pdf",
pdfOptions: PdfOptions.Archive); // PDF/A-2b archival preset
Stream conversion
await using var input = File.OpenRead("input.docx");
await using var output = File.Create("output.pdf");
await converter.ConvertToPdfAsync(input, output, pdfOptions: PdfOptions.Screen);
Exception Handling
The library uses specific exception types to distinguish between different failure scenarios during document loading
and conversion. All custom exceptions are in the LibreOfficeKit.Exceptions namespace.
Exception Types
| Exception | When thrown |
|---|---|
TimeoutException |
The conversion or worker operation exceeded the specified timeout |
DocumentPasswordProtectedException |
The document is password-protected and cannot be opened without credentials |
FileTypeNotSupportedException |
The file type is not supported by LibreOffice for loading or conversion |
ConversionFailedException |
The conversion failed for any other reason |
Exception Flow
Exceptions originate in the worker process and are propagated to the calling code through the IPC layer:
Worker Process: Document.Load / Document.SaveAs
↓
Worker: Catches specific exception (e.g., DocumentPasswordProtectedException)
↓
Worker: Sends ConvertResponse with ExceptionType field
↓
Converter: Reads ExceptionType and re-throws the original exception type
↓
Your Code: Can catch specific exception types
Usage Example
using LibreOfficeKit;
using LibreOfficeKit.Exceptions;
await using var converter = new Converter(maxInstances: 4);
try
{
await converter.ConvertToPdfAsync("input.docx", "output.pdf");
}
catch (FilePasswordProtectedException ex)
{
// File requires a password
Console.WriteLine($"File is password-protected: {ex.Message}");
}
catch (FileTypeNotSupportedException ex)
{
// File type not supported by LibreOffice
Console.WriteLine($"File type not supported: {ex.Message}");
}
catch (TimeoutException ex)
{
// Conversion took too long
Console.WriteLine($"Conversion timed out: {ex.Message}");
}
catch (ConversionFailedException ex)
{
// Other conversion failure
Console.WriteLine($"Conversion failed: {ex.Message}");
}
Detection Logic
The library analyzes error messages returned by LibreOffice to determine the exception type:
- Password-protected: Error contains
"password","encrypted", or"protected" - Unsupported file type: Error contains
"format","not supported","unknown", or"filter" - Timeout: Operation exceeds the specified
timeoutparameter - Other failures: Any other error during loading or conversion
Timeout Behavior
When a timeout is specified, the library enforces it at multiple stages:
- Worker acquisition: Waiting for an available worker
- Worker spawn: Starting a new worker process
- Document loading: Loading the input document in the worker
- PDF conversion: Converting and saving the PDF
- IPC communication: Sending requests and reading responses
If any stage exceeds the remaining time budget, a TimeoutException is thrown immediately.
PdfOptions Reference
PdfOptions controls how LibreOffice exports the PDF. Pass an instance as the pdfOptions parameter of
ConvertToPdfAsync.
Image quality
| Property | Type | Default | Description |
|---|---|---|---|
UseLosslessCompression |
bool |
false |
Use lossless (PNG) compression for images instead of JPEG |
Quality |
int |
90 |
JPEG compression quality (1–100). Higher = better quality, larger file |
ReduceImageResolution |
bool |
true |
Down-sample images that exceed MaxImageResolutionDpi |
MaxImageResolutionDpi |
int |
300 |
Maximum DPI for embedded images when ReduceImageResolution is true |
Content & accessibility
| Property | Type | Default | Description |
|---|---|---|---|
ExportBookmarks |
bool |
true |
Include document headings as PDF bookmarks/outlines |
ExportNotes |
bool |
false |
Include document comments/annotations |
ExportFormFields |
bool |
true |
Export form fields as interactive PDF widgets |
UseTaggedPdf |
bool |
false |
Create a tagged PDF (required for PDF/UA accessibility) |
SinglePageSheets |
bool |
false |
Fit each spreadsheet sheet onto a single PDF page |
Compliance & version
| Property | Type | Default | Description |
|---|---|---|---|
PdfACompliance |
PdfACompliance |
None |
PDF/A archival standard (None, Level1b, Level2b, Level3b) |
PdfVersion |
PdfVersion? |
null (LOK default) |
Target PDF version (PDF14, PDF15, PDF16, PDF17, PdfA1b, PdfA2b, PdfUA1) |
When
PdfVersionis set it takes precedence overPdfACompliance.
Layout
| Property | Type | Default | Description |
|---|---|---|---|
PageRange |
string? |
null (all) |
Page range to export, e.g. "1-5" or "2,4" |
Watermark |
string? |
null |
Watermark text printed on every page |
InitialView |
InitialView |
Default |
Which panel is shown when the PDF is opened (Default, Bookmarks, Thumbnails) |
Security
| Property | Type | Default | Description |
|---|---|---|---|
EncryptionPassword |
string? |
null |
Password required to open the PDF (simple encryption) |
Security |
PdfSecurityOptions? |
null |
Full security settings: passwords, printing and change permissions |
PdfSecurityOptions properties:
| Property | Type | Description |
|---|---|---|
EncryptFile |
bool |
Enable encryption |
DocumentOpenPassword |
string? |
Password to open the document |
RestrictPermissions |
bool |
Enable permission restrictions |
PermissionPassword |
string? |
Password required to change permissions |
Printing |
PdfPrintPermission? |
Print permission level (NotPermitted, LowResolution, HighResolution) |
Changes |
PdfChangePermission? |
Change permission level (NotPermitted, OnlyComments, OnlyFormFields, …) |
EnableCopyingOfContent |
bool? |
Allow copying text/images |
EnableTextAccessForAccessibilityTools |
bool? |
Allow screen readers |
Advanced compression overrides
Set Compression (PdfCompressionOptions) to override image compression settings per image type rather than
using the top-level UseLosslessCompression/Quality properties.
| Property | Type | Description |
|---|---|---|
UseLosslessCompression |
bool? |
Override lossless flag |
Quality |
int? |
Override JPEG quality (1–100) |
ReduceImageResolution |
bool? |
Override resolution reduction flag |
MaxImageResolution |
int? |
Override maximum DPI |
Built-in presets
| Preset | Description |
|---|---|
PdfOptions.HighQuality |
Lossless compression, full resolution, tagged PDF — for archiving |
PdfOptions.Screen |
JPEG 85%, 150 DPI — small file size optimised for on-screen use |
PdfOptions.Print |
JPEG 90%, 300 DPI — balanced quality for printing |
PdfOptions.Archive |
JPEG 90%, 300 DPI, tagged, PDF/A-2b — long-term archival |
Advanced Features
Optional Features (LibreOffice 6.0+)
LibreOfficeKit supports optional features that modify callback behavior and rendering. These are primarily useful for interactive viewers and collaborative editing scenarios.
Available Features:
| Feature | Description |
|---|---|
DocumentPassword |
Enable password prompts for encrypted documents |
DocumentPasswordToModify |
Enable password prompts for write-protected documents |
PartInInvalidationCallback |
Include part number in tile invalidation callbacks |
NoTiledAnnotations |
Disable annotation rendering (performance optimization) |
RangeHeaders |
Enable range-based spreadsheet header queries |
ViewIdInVisibleCursorInvalidationCallback |
Include view ID in cursor callbacks (multi-user) |
Example - Optimize for Conversion:
using LibreOfficeKit;
using LibreOfficeKit.Enums;
// Direct LOK instance (for advanced scenarios)
var instance = Instance.Create(@"C:\Program Files\LibreOffice\program");
// Disable annotation rendering for faster conversion
instance.SetOptionalFeatures(OptionalFeatures.NoTiledAnnotations);
var doc = instance.DocumentLoad(Instance.PathToFileUrl(@"C:\input.docx"));
doc.SaveAs(Instance.PathToFileUrl(@"C:\output.pdf"), "pdf");
doc.Dispose();
instance.Dispose();
Example - Password-Protected Documents:
var instance = Instance.Create(installPath);
// Enable password features
instance.SetOptionalFeatures(
OptionalFeatures.DocumentPassword |
OptionalFeatures.DocumentPasswordToModify);
// Pre-register password for a specific document
var fileUrl = Instance.PathToFileUrl(@"C:\encrypted.docx");
instance.SetDocumentPassword(fileUrl, "myPassword123");
// Load will now use the password automatically
var doc = instance.DocumentLoad(fileUrl);
doc.SaveAs(outputUrl, "pdf");
📖 See OPTIONAL_FEATURES.md for detailed documentation.
Direct LibreOfficeKit Instance
For advanced scenarios where you need direct control over LibreOfficeKit (without the worker pool), use Instance directly:
using LibreOfficeKit;
var installPath = Instance.FindInstallPath()
?? @"C:\Program Files\LibreOffice\program";
using var instance = Instance.Create(installPath);
var inputUrl = Instance.PathToFileUrl(@"C:\input.docx");
var outputUrl = Instance.PathToFileUrl(@"C:\output.pdf");
using var doc = instance.DocumentLoad(inputUrl);
doc.SaveAs(outputUrl, "pdf");
⚠️ Note: Only one Instance can be active per process. Use Converter for concurrent conversions.
Prerequisites
- .NET 10 SDK
- LibreOffice installed
Documentation
The full API reference is published automatically to GitHub Pages on every push to main:
https://sicos1977.github.io/LibreOfficeKit
Build
dotnet build LibreOfficeKit.sln
NuGet Package
How it works
The LibreOfficeKit NuGet package bundles the LibreOfficeKitWorker worker executable for all supported
platforms. The worker is a self-contained, trimmed single-file binary — no .NET installation is required on the
target machine.
When the package is installed in a consuming project, the MSBuild targets file (build/LibreOfficeKit.targets)
that ships inside the package automatically copies the correct worker executable for the current platform to the
project's output directory at build time. No manual steps are needed.
Package contents
build/
LibreOfficeKit.targets ← MSBuild targets, auto-copies the right worker exe
runtimes/
win-x64/native/
LibreOfficeKitWorker.exe ← Self-contained worker for Windows x64
linux-x64/native/
LibreOfficeKitWorker ← Self-contained worker for Linux x64
osx-x64/native/
LibreOfficeKitWorker ← Self-contained worker for macOS Intel
osx-arm64/native/
LibreOfficeKitWorker ← Self-contained worker for macOS Apple Silicon
lib/
net10.0/LibreOfficeKit.dll
netstandard2.0/LibreOfficeKit.dll
Building the package locally
Building the package requires the cross-platform publish tools included with .NET 10.
dotnet pack LibreOfficeKit/LibreOfficeKit.csproj -c Release
During packing, MSBuild automatically publishes LibreOfficeKitWorker for all four runtime identifiers
(win-x64, linux-x64, osx-x64, osx-arm64) before assembling the package. The resulting files are staged
in LibreOfficeKit/_WorkerPublish/ (excluded from source control via .gitignore) and then embedded in the
.nupkg.
The output is written to:
LibreOfficeKit/bin/Release/LibreOfficeKit.<version>.nupkg
LibreOfficeKit/bin/Release/LibreOfficeKit.<version>.snupkg ← debug symbols
Versioning
The package version is set via the <Version> property in LibreOfficeKit/LibreOfficeKit.csproj.
Update it before packing a new release:
<Version>1.2.0</Version>
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net5.0 was computed. net5.0-windows was computed. net6.0 was computed. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 was computed. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 was computed. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
| .NET Core | netcoreapp2.0 was computed. netcoreapp2.1 was computed. netcoreapp2.2 was computed. netcoreapp3.0 was computed. netcoreapp3.1 was computed. |
| .NET Standard | netstandard2.0 is compatible. netstandard2.1 was computed. |
| .NET Framework | net461 was computed. net462 was computed. net463 was computed. net47 was computed. net471 was computed. net472 was computed. net48 was computed. net481 was computed. |
| MonoAndroid | monoandroid was computed. |
| MonoMac | monomac was computed. |
| MonoTouch | monotouch was computed. |
| Tizen | tizen40 was computed. tizen60 was computed. |
| Xamarin.iOS | xamarinios was computed. |
| Xamarin.Mac | xamarinmac was computed. |
| Xamarin.TVOS | xamarintvos was computed. |
| Xamarin.WatchOS | xamarinwatchos was computed. |
-
.NETStandard 2.0
- Microsoft.Extensions.Logging.Abstractions (>= 10.0.8)
- System.Text.Json (>= 10.0.8)
-
net10.0
- Microsoft.Extensions.Logging.Abstractions (>= 10.0.8)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
- Renamed LibreOfficeKit.Console.exe to LibreOfficeKitWorker.exe