PdfPinata.HarfBuzz
0.3.0
dotnet add package PdfPinata.HarfBuzz --version 0.3.0
NuGet\Install-Package PdfPinata.HarfBuzz -Version 0.3.0
<PackageReference Include="PdfPinata.HarfBuzz" Version="0.3.0" />
<PackageVersion Include="PdfPinata.HarfBuzz" Version="0.3.0" />
<PackageReference Include="PdfPinata.HarfBuzz" />
paket add PdfPinata.HarfBuzz --version 0.3.0
#r "nuget: PdfPinata.HarfBuzz, 0.3.0"
#:package PdfPinata.HarfBuzz@0.3.0
#addin nuget:?package=PdfPinata.HarfBuzz&version=0.3.0
#tool nuget:?package=PdfPinata.HarfBuzz&version=0.3.0
<p align="center"> <img src="assets/logo.jpg" alt="PdfPinata logo" width="400"> </p>
PdfPinata
PdfPinata is a .NET library for creating, drawing, and manipulating PDF documents.
It provides a PDF document model and drawing API for working with pages, text, fonts, images, shapes, and existing PDF files. It can be used directly for low-level PDF drawing, or together with PinataLayout for higher-level document layouts such as paragraphs, tables, headers, footers, and flowing content.
Typical uses include:
- generating invoices, reports, statements, and other PDFs
- drawing text, images, lines, shapes, and graphics onto pages
- loading and modifying existing PDF documents
- embedding and subsetting fonts
- rendering multilingual and right-to-left text
- building reusable document layouts with PinataLayout
- generating PDFs on Windows, Linux, macOS, and Unity
PdfPinata forked PdfSharpCore, itself based on PdfSharp.Xamarin, which is based on Migradoc's PdfSharp The fork continues that API while separating font and image handling into interchangeable backends and extending text support.
The core PdfPinata package has no imaging or font-rendering dependency of its own. Choose a backend package and register it once when your application starts.
Documentation: has installation steps, a getting-started guide, a page for each feature, and a gallery of every demo with the PDF it makes.
Badges
Packages
Rendering backends
| Package | Backend | License | Notes |
|---|---|---|---|
PdfPinata.Skia |
SkiaSharp | MIT | Recommended backend. Requires native assets for the target platform. |
PdfPinata.ImageSharp |
SixLabors.ImageSharp / Fonts | Apache-2.0 | Fully managed. Uses the final Apache-2.0 ImageSharp 2.1.x / Fonts 1.x releases. |
Register the backend before creating fonts or loading images:
using PinataLayout.DocumentObjectModel.Shapes;
using PdfPinata.Fonts;
using PdfPinata.Skia;
using PdfPinata.Utils;
GlobalFontSettings.FontResolver = new SkiaFontResolver();
ImageSource.ImageSourceImpl = new SkiaImageSource();
If a font or image API is used before its backend has been registered, PdfPinata throws a InvalidOperationException.
Text shaping
Complex text shaping is available through the optional PdfPinata.HarfBuzz package.
| Package | Backend | License | Notes |
|---|---|---|---|
PdfPinata.HarfBuzz |
HarfBuzzSharp | MIT | Optional. Works with either rendering backend. Requires native assets. |
Without HarfBuzz, PdfPinata maps Unicode characters directly to glyphs using the font's cmap. This is sufficient for basic Latin text, but does not provide features such as kerning, ligatures, or contextual Arabic letter forms.
Registering HarfBuzz enables the font's OpenType GSUB and GPOS shaping rules:
using PdfPinata.Fonts;
using PdfPinata.HarfBuzz;
GlobalFontSettings.TextShaper = new HarfBuzzTextShaper();
Text shaping affects measured text width and therefore can change line wrapping. Register it before creating layouts whose output needs to remain stable.
HarfBuzz is kept separate from the rendering backend so shaping can be used with either SkiaSharp or ImageSharp.
Applications must reference the appropriate native assets:
<PackageReference Include="HarfBuzzSharp.NativeAssets.Win32" Version="14.2.1.2" />
<PackageReference Include="HarfBuzzSharp.NativeAssets.Linux" Version="14.2.1.2" />
<PackageReference Include="HarfBuzzSharp.NativeAssets.macOS" Version="14.2.1.2" />
International text
Bidirectional text
Unicode bidirectional text handling is built into PdfPinata and does not require HarfBuzz.
DrawString and MeasureString apply the Unicode Bidirectional Algorithm, separating text into directional and script runs before measuring or drawing them.
This means right-to-left text is presented in reading order even when text shaping is not installed. HarfBuzz is still required where characters need contextual shaping, such as joined Arabic forms.
Strings containing only characters below U+02B0 use a fast path and skip bidirectional processing.
Font fallback
PdfPinata can use another font when the selected font does not contain a required glyph.
Configure fallback families in preference order:
GlobalFontSettings.FontFallback =
new FontFallbackList("Noto Sans Arabic", "Noto Sans Devanagari");
Fallback is optional. Without it, missing glyphs are rendered using the font's .notdef glyph.
Font families are configured explicitly rather than automatically scanning every installed font. Applications that require different behaviour can implement IFontFallback.
Right-to-left paragraphs
XTextFormatter and PinataLayout can lay out complete right-to-left paragraphs, including justified text.
Direction can either be detected from the first strong character or specified explicitly:
formatter.TextDirection = BidiParagraphDirection.RightToLeft;
paragraph.Format.TextDirection = BidiParagraphDirection.RightToLeft;
Bidirectional tab-stop layout in PinataLayout is currently left unchanged because the expected placement of mirrored tab stops is application-dependent.
See docs/specs/text-shaping-and-bidi.md for more detail.
Fonts
The font resolver supplied by each backend discovers:
.ttf.otf.ttc.otc
Each face in a TrueType or OpenType collection is exposed separately.
Fonts used by a document are always embedded in the PDF.
Font subsetting
TrueType fonts are subsetted so the PDF contains only the glyphs actually used by the document.
OpenType fonts containing PostScript/CFF outlines are currently embedded in full. Large CJK CFF fonts can therefore add several megabytes to a PDF.
Synthetic bold and italic
If a requested family does not contain a real bold or italic face, PdfPinata can simulate it by stroking or skewing the glyphs.
This is useful as a fallback, but a genuine bold or italic font produces better output. Applications where typography matters should ship the required font faces.
SkiaSharp native assets
SkiaSharp uses native libraries. Applications using PdfPinata.Skia must reference the native asset package for each target platform.
PdfPinata intentionally does not choose these packages automatically because Linux applications may require different variants.
For example:
<PackageReference Include="SkiaSharp.NativeAssets.Win32" Version="4.150.1" />
<PackageReference Include="SkiaSharp.NativeAssets.Linux.NoDependencies" Version="4.150.1" />
<PackageReference Include="SkiaSharp.NativeAssets.macOS" Version="4.150.1" />
Use SkiaSharp.NativeAssets.Linux instead of SkiaSharp.NativeAssets.Linux.NoDependencies when libfontconfig1 is available in the target Linux environment.
PdfPinata.ImageSharp is fully managed and does not require native rendering assets.
ImageSharp version support
PdfPinata.ImageSharp requires SixLabors.ImageSharp 2.1.x.
ImageSharp 3.0 moved from Apache-2.0 to the Six Labors Split License. PdfPinata therefore remains on the final Apache-2.0 ImageSharp release rather than automatically introducing the newer licence into applications using PdfPinata.
ImageSharp 3.x is also not binary compatible with ImageSharp 2.1.x. APIs used by the backend changed between the releases, so loading ImageSharp 3.x with a backend compiled against 2.1.x can result in runtime failures.
The dependency is therefore declared as:
[2.1.13,3.0.0)
This normally exposes the conflict during package restore instead of at runtime.
If ImageSharp 3.x arrives transitively, NuGet reports NU1107.
If the application directly references ImageSharp 3.x, NuGet's direct-dependency-wins rule can instead produce NU1608. Applications using the ImageSharp backend should treat that warning as an error:
<WarningsAsErrors>$(WarningsAsErrors);NU1608</WarningsAsErrors>
If an incompatible version is loaded anyway, PdfPinata reports a InvalidOperationException including the detected ImageSharp version.
SixLabors.Fonts is referenced at 1.0.1 for the same licensing reason, but the API used by ImageSharpFontResolver remains compatible with Fonts 2.x. Resolving a newer Fonts version is therefore a licensing choice rather than a known runtime incompatibility.
Applications that require ImageSharp 3.x or later should use PdfPinata.Skia. The Skia backend has no ImageSharp dependency, so ImageSharp 3.x can be used independently in the same application.
Target frameworks
All PdfPinata packages target:
netstandard2.1
net8.0
net10.0
netstandard2.1 is retained primarily for Unity, whose scripting runtime supports the .NET Standard 2.1 API surface but cannot consume net8.0 or net10.0 assemblies directly.
Supporting netstandard2.1 requires small compatibility shims for APIs introduced in later .NET versions. Missing types, such as trimming annotations and IsExternalInit, are generated by the PolySharp source generator. Missing members, such as throw helpers and span overloads, live in src/Polyfills/. Both are internal, apply to the netstandard legs only, and add no package dependency.
Table of Contents
- Documentation
- Packages
- International text
- Fonts
- Target frameworks
- Example
- Running the demos
- Running the tests
- Contributing
- License
Example
This example creates a PDF containing Hello World! using the Skia backend:
using PdfPinata.Drawing;
using PdfPinata.Fonts;
using PdfPinata.Pdf;
using PdfPinata.Utils;
GlobalFontSettings.FontResolver = new SkiaFontResolver();
var document = new PdfDocument();
var page = document.AddPage();
var gfx = XGraphics.FromPdfPage(page);
var font = new XFont("Arial", 20, XFontStyle.Bold);
var textColor = XBrushes.Black;
var layout = new XRect(20, 20, page.Width, page.Height);
var format = XStringFormats.Center;
gfx.DrawString("Hello World!", font, textColor, layout, format);
document.Save("helloworld.pdf");
Running the demos
SampleApp contains examples covering the main PdfPinata features.
dotnet run --project src/SampleApp -- list
dotnet run --project src/SampleApp -- run
dotnet run --project src/SampleApp -- run --example Fonts Text
dotnet run --project src/SampleApp -- run --no-code
list names every demo and what it shows. The demo gallery on the documentation site shows each one's first page, with the PDF it makes, its source, and the guide that explains it.
Each example writes:
output/<Name>.pdf
The sample application includes its own Liberation Sans, Liberation Serif, and Source Code Pro fonts so generated PDFs remain consistent across platforms, including machines with no suitable fonts installed.
See docs/specs/demonstration-app.md for the complete demo specification.
Running the tests
Run the test suite with:
dotnet test src/PdfPinata.slnx
No additional setup is required on Windows. Ghostscript used by the PDF visual comparison tests is supplied through Ghostscript.NativeAssets.
On Linux and macOS, ImageMagick uses the system Ghostscript installation, so install it through the operating system package manager when running visual tests:
apt-get install ghostscript
or:
brew install ghostscript
Some XTextFormatterTest visual tests compare generated output with reference images rendered on Linux.
Font rasterisation varies between operating systems and installed fonts, so these tests are skipped on platforms where the reference output cannot be compared reliably. CI runs them on Linux and is the reference environment for rendering changes.
Contributing
Feedback, bug reports, pull requests, and other contributions are welcome. See Contributing.
License
PdfPinata is released under the MIT License. See LICENSE.md.
PdfPinata can optionally use projects distributed under other licences.
ImageSharp and SixLabors.Fonts
PdfPinata.ImageSharp uses the Apache-2.0 licensed releases of:
- SixLabors.ImageSharp
- SixLabors.Fonts
Later versions of those projects use the Six Labors Split License. See the ImageSharp licence for details.
| 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 is compatible. 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 | netcoreapp3.0 was computed. netcoreapp3.1 was computed. |
| .NET Standard | netstandard2.1 is compatible. |
| MonoAndroid | monoandroid was computed. |
| MonoMac | monomac was computed. |
| MonoTouch | monotouch was computed. |
| Tizen | 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.1
- HarfBuzzSharp (>= 14.2.1.201)
- PdfPinata (>= 0.3.0)
-
net10.0
- HarfBuzzSharp (>= 14.2.1.201)
- PdfPinata (>= 0.3.0)
-
net8.0
- HarfBuzzSharp (>= 14.2.1.201)
- PdfPinata (>= 0.3.0)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.