PdfSharpCore Documentation
repository·master·Indexed 22 days ago
https://github.com/ststeiger/pdfsharpcoreA .NET Standard library for generating PDF documents, providing a port of PdfSharp and MigraDoc with modern image and font support via SixLabors.ImageSharp and SixLabors.Fonts. It includes PdfSharpCore for low-level PDF creation and MigraDocCore for high-level document modeling with support for paragraphs, tables, charts, and automated layout.
What's inside PdfSharpCore
- MigraDocCore is a .NET library designed for modeling and rendering documents. It serves as a high-level document object model (DOM) for creating complex document structures.
What is PdfSharpCore
masterPdfSharpCore is a .NET library written in C# used for creating and modifying Adobe PDF documents programmatically. It can be used from any .NET language.Overview of PdfSharpCore
masterPdfSharpCore is a .NET Standard port of PdfSharp.Xamarin. It includes a port of MigraDoc (from version 1.32). It provides PDF generation capabilities with integrated support for images viaSixLabors.ImageSharpand fonts viaSixLabors.Fonts.Language and Character Support (Arabic, Hebrew, CJK)
masterPdfSharpCore currently has limited support for complex languages:
- Right-to-left (RTL) languages: Not natively supported. Hebrew can be approximated by reversing strings and left-aligning paragraphs. Arabic requires manual handling of glyph shapes (beginning, end, middle, isolated) by reversing strings and selecting specific Unicode characters.
- CJK (Chinese, Japanese, Korean): Japanese characters can be displayed if a compatible font is selected, but they will be rendered left-to-right rather than top-to-bottom.
- Note: Always ensure the selected font contains the required character sets.
Apply transformations and state management with XGraphics
masterWhen drawing complex shapes (like clock hands), use coordinate transformations to simplify math:
- TranslateTransform: Moves the origin of the coordinate system (e.g., to the center of the page).
- ScaleTransform: Scales the coordinate system.
- RotateTransform: Rotates the coordinate system around the current origin.
- State Management: Always use
gfx.Save()before applying transformations andgfx.Restore(gs)after drawing to ensure subsequent drawing operations are not affected by the previous transformations.
void DrawHourHand(XGraphics gfx, XPen pen, XBrush brush) { XGraphicsState gs = gfx.Save(); gfx.RotateTransform(360 * Time.Hour / 12 + 30 * Time.Minute / 60); gfx.DrawPolygon( pen, brush, new XPoint[]{new XPoint(0, 150), new XPoint(100, 0), new XPoint(0, -600), new XPoint(-100, 0)}, XFillMode.Winding); gfx.Restore(gs); }Use XGraphicsPath for complex drawing and clipping
masterThe
XGraphicsPathclass allows you to build complex shapes by combining lines, arcs, and curves. Once a path is constructed, you can:- Stroke/Fill: Use
gfx.DrawPath(pen, path)orgfx.DrawPath(pen, brush, path). - Convert Text to Path: Use
path.AddString(...)to turn text into a geometric path, which can then be stroked or filled like any other shape. - Clipping: Use
gfx.IntersectClip(path)to restrict all subsequent drawing operations to the area defined by the path.
- Stroke/Fill: Use
Work directly with underlying PDF objects
masterWhen specialized
PdfSharpCoreclasses do not support a specific PDF feature, you can manipulate the underlying PDF structure directly using low-level objects likePdfDictionary,PdfArray,PdfName, andPdfReference.This approach requires knowledge of the PDF specification (e.g., Adobe's PDF Reference). By using these objects, you can implement features like custom actions, advanced metadata, or specific document behaviors that are not yet part of the high-level API.
Key concepts for direct object manipulation:
- Indirect References: Instead of adding a high-level object (like a
PdfPage) directly to a collection, usePdfInternals.GetReference(object)to create aPdfReference. This ensures the object is treated as an indirect object in the PDF structure. - Object Table: Use
document.Internals.AddObject(object)to add a manually constructed object to the document's object table. - Catalog Access: Use
document.Internals.Catalogto access the document's root dictionary to add top-level keys like/OpenAction.
// Example: Adding an OpenAction to a document PdfDocument document = PdfReader.Open(filename); // 1. Create a dictionary for the action PdfDictionary dict = new PdfDictionary(document); dict.Elements["/S"] = new PdfName("/GoTo"); // 2. Create an array for the destination PdfArray array = new PdfArray(document); dict.Elements["/D"] = array; // 3. Add elements to the array (e.g., a reference to page 3, a fit command, and a coordinate) PdfReference iref = PdfInternals.GetReference(document.Pages[2]); array.Elements.Add(iref); array.Elements.Add(new PdfName("/FitV")); array.Elements.Add(new PdfInteger(-32768)); // 4. Register the dictionary in the document's object table document.Internals.AddObject(dict); // 5. Link the action to the document catalog document.Internals.Catalog.Elements["/OpenAction"] = PdfInternals.GetReference(dict);- Indirect References: Instead of adding a high-level object (like a
Implement a LayoutHelper for automatic pagination
masterBecause
PdfSharpCoreis a low-level drawing library, it does not handle automatic page breaks. You can implement aLayoutHelperpattern to manage vertical positioning and triggerAddPage()calls when the current position exceeds a defined bottom margin.A
LayoutHelpershould track:- The
PdfDocumentinstance. - The
_currentPosition(vertical Y coordinate). - The
_topPositionand_bottomMarginfor the current page. - The current
XGraphicsandPdfPageobjects.
When requesting a line position via a method like
GetLinePosition(requestedHeight), the helper checks if_currentPosition + requestedHeightexceeds the_bottomMargin. If it does, it calls aCreatePage()method to reset the position and refresh the graphics context.public class LayoutHelper { private readonly PdfDocument _document; private readonly XUnit _topPosition; private readonly XUnit _bottomMargin; private XUnit _currentPosition; public LayoutHelper(PdfDocument document, XUnit topPosition, XUnit bottomMargin) { _document = document; _topPosition = topPosition; _bottomMargin = bottomMargin; // Set a value outside the page - a new page will be created on the first request. _currentPosition = bottomMargin + 10000; } public XUnit GetLinePosition(XUnit requestedHeight, XUnit requiredHeight = -1f) { XUnit required = requiredHeight == -1f ? requestedHeight : requiredHeight; if (_currentPosition + required > _bottomMargin) CreatePage(); XUnit result = _currentPosition; _currentPosition += requestedHeight; return result; } public XGraphics Gfx { get; private set; } public PdfPage Page { get; private set; } void CreatePage() { Page = _document.AddPage(); Page.Size = PageSize.A4; Gfx = XGraphics.FromPdfPage(Page); _currentPosition = _topPosition; } }- The
Choose between PdfSharpCore and MigraDocCore
masterDecide which library to use based on your document creation requirements:
- Use PdfSharpCore if you need low-level control over PDF creation. It allows you to control every pixel and every line drawn, making it ideal for precise graphics or custom drawing routines.
- Use MigraDocCore if you need to create complex documents using a high-level object model. It provides a word-processor-like experience with features such as paragraphs, tables, and styles, and uses PdfSharpCore internally to render the final PDF.
Implement a custom IFontResolver for embedded fonts
masterWhen running in environments like web services or servers where specific fonts are not installed on the OS, you must implement the
IFontResolverinterface. This allows you to bundle font files (e.g.,.ttf) directly with your application.To implement a custom resolver, you must provide logic for two methods:
ResolveTypeface(string familyName, bool isBold, bool isItalic): Determines which font file corresponds to a requested typeface. It returns aFontResolverInfoobject.GetFont(string faceName): Retrieves the actual font data as abyte[]using thefaceNameprovided by the first method.
Create and use XForm objects as templates
masterAn
XFormobject acts as a reusable template that can be drawn multiple times anywhere in a PDF document. When you create anXForm, it is bound to its targetdocument, allowing it to share fonts and other resources with that document.To use an
XForm:- Instantiate
XFormwith a targetdocumentand dimensions usingXUnit. - Create an
XGraphicsobject specifically for the form usingXGraphics.FromForm(form). - Draw content (text, graphics, images, or even other forms) onto the
XGraphicsobject. - Dispose of the
XGraphicsobject when finished. - Draw the completed form onto a PDF page using
gfx.DrawImage(form, ...).
- Instantiate
Configure Page Setup, Headers, and Footers
masterMigraDocCore allows fine-grained control over page layouts within a
Section.- Page Setup: Use
section.PageSetupto setStartingNumberand toggleOddAndEvenPagesHeaderFooter. - Headers/Footers: Access
section.Headers.Primary,section.Headers.EvenPage, orsection.Headers.OddPage. - Cloning Objects: When adding the same object (like a page number paragraph) to multiple headers or footers, you must use
.Clone()to avoid exceptions, as an object cannot belong to more than one parent. - Page Fields: Use
paragraph.AddPageField()to insert dynamic page numbers.
- Page Setup: Use