Creating documents
Minimal example
using MiPdf;
using MiPdf.Fonts;
using MiPdf.Graphics;
using var doc = PdfDocument.Create();
doc.Info.Title = "Hello";
var page = doc.AddPage(PageSize.A4);
using (var canvas = page.GetCanvas())
{
canvas.DrawText("Hello, PDF!", PdfStandardFont.HelveticaBold, 24, 72, 760);
}
doc.Save("hello.pdf");
Coordinates are PDF user space: points (1/72 inch), origin at the bottom-left corner of the page.
PageSize contains the ISO sizes A0–A6, B4 and B5, the North American sizes Letter, Legal, Tabloid, Ledger and
Executive, Landscape(...) (width and height swapped) and FromMillimeters(...).
Fonts
| Font type | Usage | Characters |
|---|---|---|
PdfStandardFont.Helvetica, TimesRoman, Courier (+ Bold/Italic variants), Symbol, ZapfDingbats |
not embedded, smallest files | WinAnsi (Western European incl. umlauts, €) |
PdfTrueTypeFont.FromFile("arial.ttf") |
embedded as subset (Type0/Identity-H) | full Unicode (Latin, Greek, Cyrillic, CJK, ...) |
var arial = PdfTrueTypeFont.FromFile(@"C:\Windows\Fonts\arial.ttf");
canvas.DrawText("Zażółć gęślą jaźń · Ελληνικά", arial, 12, 72, 700);
double width = arial.GetTextWidth("measure me", 12); // points
Font objects are independent of documents and can be reused (e.g. as static fields). Each document
embeds only the glyphs it actually uses. .ttc collections: FromFile(path, collectionIndex).
CFF-based OpenType fonts (.otf) are embedded completely. Fonts whose license forbids embedding are
rejected unless ignoreLicenseRestrictions: true is passed.
Not supported yet: complex script shaping (Arabic, Indic), ligatures, right-to-left text.
Canvas (page.GetCanvas())
The canvas collects drawing operations and appends them to the page when disposed.
page.GetCanvas(background: true) draws below the existing content.
| Area | Methods |
|---|---|
| State | SaveState, RestoreState, Translate, Scale, Rotate(deg, cx, cy), Transform |
| Style | SetFillColor, SetStrokeColor (PdfColor.Rgb/Cmyk/Gray/FromHex), SetLineWidth, SetDashPattern, SetLineCap, SetLineJoin, SetOpacity |
| Paths | MoveTo, LineTo, CurveTo, Rectangle, RoundedRectangle, Ellipse, Circle, ClosePath, Stroke, Fill, FillAndStroke, Clip |
| Shortcuts | DrawLine, DrawRectangle, DrawText (left/center/right), DrawImage, DrawXObject |
| Text (low level) | BeginText, SetFont, SetTextPosition, ShowText, SetCharacterSpacing, SetTextRenderingMode, EndText |
| Raw | WriteRaw("...") writes content stream operators directly |
Images
var logo = PdfImage.FromFile("logo.png"); // PNG (incl. transparency) or JPEG
canvas.DrawImage(logo, 72, 700, 120, 40); // exact rectangle
canvas.DrawImage(logo, new PdfRectangle(72, 600, 300, 700)); // fit into box, keep aspect ratio
JPEGs are embedded unchanged. PNGs are decoded; alpha channels become soft masks. An image used on many pages is embedded only once.
Reusable content (form XObjects)
var stamp = new PdfFormXObject(doc, new PdfRectangle(0, 0, 200, 50));
using (var c = stamp.GetCanvas()) c.DrawRectangle(0, 0, 200, 50, PdfColor.Red);
foreach (var p in doc.Pages)
using (var c = p.GetCanvas()) c.DrawXObject(stamp, 300, 50);
Flow layout (MiPdf.Layout)
LayoutDocument places paragraphs, tables and images from top to bottom and creates pages as needed.
using var pdf = PdfDocument.Create();
using (var layout = new LayoutDocument(pdf, PageSize.A4, new Thickness(50)))
{
layout.Footer = ctx => ctx.Canvas.DrawText($"Page {ctx.PageNumber} of {ctx.TotalPages}",
PdfStandardFont.Helvetica, 8, ctx.ContentArea.Right, 30, alignment: TextAlignment.Right);
layout.Add(new Paragraph("Invoice", PdfStandardFont.HelveticaBold, 20) { SpacingAfter = 10 });
var text = new Paragraph { Alignment = TextAlignment.Justify };
text.Add("Normal text, ");
text.Add(new TextRun("bold and underlined", PdfStandardFont.HelveticaBold) { Underline = true });
text.Add(", and a\nhard line break.");
layout.Add(text);
var table = new Table(1, 4, 1) { AlternateRowBackground = PdfColor.Gray(0.95) };
table.AddHeaderCell("Pos"); table.AddHeaderCell("Description"); table.AddHeaderCell("Amount");
table.AddCell("1"); table.AddCell("Consulting"); table.AddCell(new Cell("100.00") { TextAlignment = TextAlignment.Right });
table.AddCell(new Cell("Total", colSpan: 2)); table.AddCell("100.00");
layout.Add(table);
layout.Add(new ImageElement(PdfImage.FromFile("logo.png"), width: 150));
layout.Add(new PageBreak());
}
pdf.Save("invoice.pdf");
| Element | Features |
|---|---|
Paragraph |
runs with individual font/size/color/underline/strikethrough, alignment incl. justify, line spacing, indents, spacing before/after; kerning (TrueType/OpenType, default on), soft hyphens and hyphenation; splits across pages line by line |
Table |
relative column widths, header rows repeated on each page, column and row spans, rows taller than a page are split across pages (SplitRowsAcrossPages), padding, borders, backgrounds, zebra rows, vertical alignment, nested elements in cells |
ListElement |
bullet, dash, decimal, a), A., i., I. or custom labels, nested lists, any content per item, continues across pages |
BarcodeElement |
QR, Data Matrix, Code 128, EAN, ... (see barcodes) |
ImageElement |
natural size (96 dpi), fixed width/height, alignment; scaled down if larger than the page |
HorizontalLine, Spacer, PageBreak |
TextLayout.BreakLines(text, font, size, width) and TextLayout.MeasureHeight(...) are available for
custom layouts. Headers/footers are rendered when the layout is closed, so TotalPages is known.
Lists
var list = new ListElement(ListStyle.Decimal) { Font = font, FontSize = 11 };
list.AddItem("First item");
list.AddItem("Second item").Add(new ListElement(ListStyle.LowerAlpha) { Font = font }.AddItems("a", "b"));
list.AddItem(new Paragraph("Paragraph"), new ImageElement(image, 100)); // any content
layout.Add(list);
Styles: Bullet, Dash, Decimal (1.), LowerAlpha (a.), UpperAlpha (A.), LowerRoman (i.), UpperRoman (I.) and
None. Other labels come from LabelFormatter, e.g. n => $"{(char)('a' + n - 1)})" for "a)".
Row spans and long rows
table.AddCell(new Cell("Group A", rowSpan: 3) { VerticalAlignment = VerticalAlignment.Middle });
table.AddCell(new Cell("spanning two columns", colSpan: 2));
Rows connected by row spans stay on one page. A row that does not fit on the current page moves to the next page; a row taller than a whole page is split (content continues in the same cells, the header row is repeated).
Kerning and hyphenation
- Kerning (GPOS or
kerntable) is applied for TrueType/OpenType fonts (Paragraph.Kerning, default true;canvas.DrawText(..., kerning: true),font.GetTextWidth(text, size, kerning: true)). The standard 14 fonts have no kerning data. - Soft hyphens (U+00AD) in the text are used as break points; hard hyphens are break points as well.
- Automatic hyphenation with TeX patterns (Liang's algorithm). The pattern files are not bundled – get them from the
hyph-utf8 project (e.g.
hyph-de-1996.tex, MIT licensed):
TextLayout.DefaultHyphenator = PatternHyphenator.FromTex(File.ReadAllText("hyph-de-1996.tex"));
// or per paragraph: paragraph.Hyphenator = ...
Image formats
PdfImage.FromBytes accepts JPEG (embedded unchanged), PNG (all color types, transparency), BMP (1/4/8/16/24/32 bit,
RLE, bit fields with alpha) and GIF (first frame, transparency, interlacing).
PDF/A (long-term archiving)
var doc = PdfDocument.Create();
doc.Info.Title = "Annual report 2026";
doc.Conformance = PdfAConformance.PdfA2B; // or PdfA1B, PdfA2U, PdfA3B, PdfA3U, PdfA4, PdfA4F
// ... content with embedded fonts (PdfTrueTypeFont); the standard 14 fonts are not embedded
var issues = doc.CheckPdfA(PdfAConformance.PdfA2B); // basic checks; use veraPDF for a full validation
doc.Save("report.pdf");
Saving writes the XMP metadata with the PDF/A identification and an sRGB output intent, and sets the PDF version the part requires:
| Level | Based on | Notes |
|---|---|---|
PdfA1B |
PDF 1.4 | no transparency, no object streams |
PdfA2B, PdfA2U |
PDF 1.7 | U: all text mappable to Unicode (always the case with PdfTrueTypeFont) |
PdfA3B, PdfA3U |
PDF 1.7 | like PDF/A-2, arbitrary attachments allowed (ZUGFeRD / Factur-X) |
PdfA4 |
PDF 2.0 | attachments must be PDF/A files |
PdfA4F |
PDF 2.0 | arbitrary attachments, at least one required |
PDF/A-4 does not allow the document information dictionary: miPDFlib writes title, author and dates only into the
XMP metadata, and doc.Info of an opened PDF/A-4 (or other PDF 2.0) document reads them from there. Changes to
doc.Info of an opened PDF/A document are written into its XMP metadata on saving, so the document stays conforming
without setting Conformance again. PDF/A-4 can be combined with PDF/UA-2 (see accessibility),
PDF/A-1 to -3 with PDF/UA-1.