Getting Started
This page makes a one-page PDF that says "Hola, mundo!". You make it twice: first by drawing on
the page with XGraphics, then by describing a document and letting PinataLayout lay it out.
Overview explains when to use each way.
You need the .NET 8 SDK or later. The steps use the PdfPinata.Skia backend.
Create the project
-
Create a console application:
dotnet new console -o HelloPdfcd HelloPdf -
Add the Skia backend. It brings in the core
PdfPinatapackage:dotnet add package PdfPinata.Skia -
If you work on Linux, add the SkiaSharp native library. Use the SkiaSharp version that
dotnet list package --include-transitiveshows:dotnet add package SkiaSharp.NativeAssets.Linux.NoDependencies --version 4.152.1
Installation explains the backends and the native libraries.
Register the backend
Replace the contents of Program.cs with these lines. They must run before you create any font or
image:
using PdfPinata.Drawing;
using PdfPinata.Fonts;
using PdfPinata.Pdf;
using PdfPinata.Skia;
using PdfPinata.Utils;
using PinataLayout.DocumentObjectModel.Shapes;
GlobalFontSettings.FontResolver = new SkiaFontResolver();
ImageSource.ImageSourceImpl = new SkiaImageSource();
SkiaFontResolver finds the fonts installed on the machine. SkiaImageSource is not needed for
this page, because the page has no images, but most applications need it soon.
Draw a page with XGraphics
-
Create the document and fill in its properties. A PDF reader shows these under "document properties". Add these lines below the registration:
src/SampleApp/Demos/HelloWorldDemo.csvar document = new PdfDocument();// What a reader shows under "document properties". Producer is not set here: the// library writes its own and the property is read only.document.Info.Title = "Hola, mundo!";document.Info.Author = "PdfPinata";document.Info.Subject = "The smallest document worth saving";document.Info.Keywords = "pdfpinata; demo; metadata";document.Info.Creator = "PdfPinata SampleApp";// A fixed date rather than DateTime.Now, so that running the demo twice produces// two files that differ only in the document identifier.document.Info.CreationDate = new DateTime(2026, 1, 1, 9, 0, 0, DateTimeKind.Utc); -
Add a page, get an
XGraphicsfor it, and draw the string:src/SampleApp/Demos/HelloWorldDemo.csvar page = document.AddPage();var gfx = XGraphics.FromPdfPage(page);var width = page.Width.Point;var height = page.Height.Point;// The rectangle overload plus a format centres the string in the box. The point// overload would put the text's baseline at the point instead.var title = new XFont("Liberation Sans", 30, XFontStyle.Bold);gfx.DrawString("Hola, mundo!", title, XBrushes.Black,new XRect(0, 0, width, height * 0.4), XStringFormats.Center);The demo uses "Liberation Sans", a font that the demo app carries with it. Change the family name to a font that is installed on your machine, for example "Arial" on Windows.
-
Save the document. Add this line at the end of
Program.cs:document.Save("HelloWorld.pdf"); -
Run the application:
dotnet run -
Open
HelloWorld.pdf. It is in the project folder.
XGraphics measures in points, 1/72 inch, from the top-left corner of the page. page.Width.Point
gives the page width in points.
A new page gets its size from the region settings of the machine: A4 where the region uses metric units, and US Letter where it does not. If the size matters, set it on the page before you draw. See Pages and orientation.
Lay out the same page with PinataLayout
With PinataLayout you do not draw at coordinates. You add sections and paragraphs, and the renderer places them on pages.
-
Add the PinataLayout renderer to the project:
dotnet add package PinataLayout.Rendering -
Replace the contents of
Program.cswith this program:using PdfPinata.Fonts;using PdfPinata.Skia;using PdfPinata.Utils;using PinataLayout.DocumentObjectModel;using PinataLayout.DocumentObjectModel.Shapes;using PinataLayout.Rendering;GlobalFontSettings.FontResolver = new SkiaFontResolver();ImageSource.ImageSourceImpl = new SkiaImageSource();Document document = new Document();document.Info.Title = "Hola, mundo!";Section section = document.AddSection();Paragraph paragraph = section.AddParagraph("Hola, mundo!");paragraph.Format.Font.Size = 30;paragraph.Format.Font.Bold = true;PdfDocumentRenderer renderer = new PdfDocumentRenderer(true) { Document = document };renderer.RenderDocument();renderer.PdfDocument.Save("HelloLayout.pdf"); -
Run the application and open
HelloLayout.pdf.
A Document holds one or more sections. By default each section starts on a new page, and each
has its own page setup, headers and footers. PinataLayout pages are A4 unless you change the page
setup. PdfDocumentRenderer lays out the document and writes the pages into
renderer.PdfDocument, which is an ordinary PdfDocument. You can draw on its pages with
XGraphics before you save it.
The true argument writes text as Unicode, so any character that the font contains can appear.
Every demo passes true.
Things to know
- Register the backend first.
new XFont(...)andnew Document()both throw anInvalidOperationExceptionif no font resolver is registered. After the first font exists, you cannot change the resolver. - An unknown font family does not cause an error. If
SkiaFontResolvercannot find the family you ask for, it uses another installed font. The PDF looks wrong, but nothing tells you. On a server or in a container, few fonts or none are installed. Read Fonts before you deploy. - PinataLayout's default font is Arial. The
Normalstyle uses the font resolver's default family, which is "Arial" for the Skia and ImageSharp resolvers. To use another family for the whole document, setdocument.Styles[StyleNames.Normal].Font.Name. DrawStringplaces text differently with a rectangle and with a point. With anXRectandXStringFormats.Center, the string is centred in the rectangle. With anXPointand no format, the point is where the text's baseline starts, not its top.- Namespaces are
PdfPinata.*andPinataLayout.*. Code from PDFsharp or MigraDoc examples usesPdfSharp.*andMigraDoc.*. Change theusinglines. See Migrating. - PinataLayout tags its output by default. The PDF carries a structure tree for accessibility.
A tagged document cannot be resized with
PdfPage.Resize. To turn tagging off, setrenderer.TagContent = false.
Where next
- Text and Shapes, pens and brushes for more about drawing.
- Documents, sections and styles and Paragraphs and text layout for more about PinataLayout.
- Fonts to control which font files your documents use.
See it in action
The HelloWorld demo draws the page from this guide and prints every document property on the page as well.
The full HelloWorld demo
var document = new PdfDocument();
// What a reader shows under "document properties". Producer is not set here: the
// library writes its own and the property is read only.
document.Info.Title = "Hola, mundo!";
document.Info.Author = "PdfPinata";
document.Info.Subject = "The smallest document worth saving";
document.Info.Keywords = "pdfpinata; demo; metadata";
document.Info.Creator = "PdfPinata SampleApp";
// A fixed date rather than DateTime.Now, so that running the demo twice produces
// two files that differ only in the document identifier.
document.Info.CreationDate = new DateTime(2026, 1, 1, 9, 0, 0, DateTimeKind.Utc);
var page = document.AddPage();
var gfx = XGraphics.FromPdfPage(page);
var width = page.Width.Point;
var height = page.Height.Point;
// The rectangle overload plus a format centres the string in the box. The point
// overload would put the text's baseline at the point instead.
var title = new XFont("Liberation Sans", 30, XFontStyle.Bold);
gfx.DrawString("Hola, mundo!", title, XBrushes.Black,
new XRect(0, 0, width, height * 0.4), XStringFormats.Center);
// The same metadata again, on the page, so it can be read without a properties
// dialog - and so a round trip through a reader can be checked against it.
var label = new XFont("Liberation Sans", 10, XFontStyle.Bold);
var value = new XFont("Liberation Sans", 10);
(string Label, string Value)[] rows =
{
("Title", document.Info.Title),
("Author", document.Info.Author),
("Subject", document.Info.Subject),
("Keywords", document.Info.Keywords),
("Creator", document.Info.Creator),
("CreationDate", document.Info.CreationDate.ToString("u"))
};
var y = height * 0.45;
foreach (var row in rows)
{
gfx.DrawString(row.Label, label, XBrushes.Black, new XPoint(80, y));
gfx.DrawString(row.Value, value, XBrushes.DimGray, new XPoint(190, y));
y += 18;
}
gfx.DrawLine(XPens.LightGray, 80, height * 0.45 - 16, width - 80, height * 0.45 - 16);