Migrating from PDFsharp, PdfSharpCore and MigraDoc
PdfPinata is a fork of PdfSharpCore, which is a port of empira's PDFsharp. PinataLayout is the same
library that was called MigraDocCore in PdfSharpCore, and MigraDoc before that. Class and member names
are mostly unchanged, so most code moves across with new package references, new using directives
and one or two lines of start-up code.
This page lists what you have to change, then the behaviour changes you are likely to notice. For a first project from scratch, read Installation instead.
Change the package references
| Old package | New package |
|---|---|
PdfSharpCore | PdfPinata, plus a backend: PdfPinata.Skia or PdfPinata.ImageSharp |
PdfSharpCore.Charting | PdfPinata.Charting |
MigraDocCore.DocumentObjectModel | PinataLayout.DocumentObjectModel |
MigraDocCore.Rendering | PinataLayout.Rendering |
The other packages have no counterpart in PdfSharpCore: PdfPinata.HarfBuzz (text shaping),
PdfPinata.Signing (digital signatures) and PdfPinata.EInvoice (Factur-X and ZUGFeRD). All nine
packages have the same version number, so upgrade them together.
Change the namespaces
Every namespace follows its package. Replace the first segment:
| Old namespace | New namespace |
|---|---|
PdfSharpCore, PdfSharpCore.Drawing, PdfSharpCore.Pdf, ... | PdfPinata, PdfPinata.Drawing, PdfPinata.Pdf, ... |
PdfSharpCore.Utils | PdfPinata.Utils |
MigraDocCore.DocumentObjectModel, and the namespaces under it | PinataLayout.DocumentObjectModel, and the namespaces under it |
MigraDocCore.Rendering | PinataLayout.Rendering |
MigraDocCore.DocumentObjectModel.MigraDoc.DocumentObjectModel.Shapes | PinataLayout.DocumentObjectModel.Shapes |
The last row holds ImageSource, which you use to register an image backend. It lives in the
PinataLayout.DocumentObjectModel.Shapes namespace but ships in the core PdfPinata package, so you
need that using even in code that does not use PinataLayout.
PdfPinata 0.1.0 still had the doubled segment, as
PinataLayout.DocumentObjectModel.MigraDoc.DocumentObjectModel.Shapes. If you are upgrading from
0.1.0, change that using to PinataLayout.DocumentObjectModel.Shapes.
If your code came from empira's PDFsharp and MigraDoc rather than from PdfSharpCore, the same pattern
applies: PdfSharp.Drawing becomes PdfPinata.Drawing, MigraDoc.DocumentObjectModel becomes
PinataLayout.DocumentObjectModel, and MigraDoc.Rendering becomes PinataLayout.Rendering.
PdfSharpCore was ported from an earlier PDFsharp release, so code written for later PDFsharp releases
can use members that this library does not have.
Register a backend at start-up
The core PdfPinata package has no imaging or font library of its own. PdfSharpCore depended on
ImageSharp and SixLabors.Fonts and chose an image source for you; PdfPinata does not. You must
register a backend once, before you create a font or load an image. With the Skia backend:
using PinataLayout.DocumentObjectModel.Shapes;
using PdfPinata.Fonts;
using PdfPinata.Skia;
using PdfPinata.Utils;
GlobalFontSettings.FontResolver = new SkiaFontResolver();
ImageSource.ImageSourceImpl = new SkiaImageSource();
GlobalFontSettings.GlyphOutlineProvider = new SkiaGlyphOutlineProvider();
The ImageSharp backend has ImageSharpFontResolver, ImageSharpImageSource<TPixel> and
ImageSharpGlyphOutlineProvider, all in PdfPinata.Utils. ImageSharpImageSource<TPixel> has the
same name and type parameter as in PdfSharpCore.
- If you read
GlobalFontSettings.FontResolverbefore it is set, it throws anInvalidOperationExceptionthat names the backend packages. - The font resolver cannot change once a font has been created. Register it first thing, before any
other code makes an
XFontor a PinataLayoutDocument. PlatformFontResolveris gone. It never returned a font.- The glyph outline provider is needed only for
XGraphicsPath.AddStringand for placing drop caps exactly. See Fonts.
Open existing documents with the right mode
PdfDocumentOpenMode.InformationOnly is gone. It never did what its name said: the whole file was
always read, and the document could not be changed. Use PdfDocumentOpenMode.ReadOnly, which does
the same.
The open mode is now enforced. A document opened ReadOnly or Import used to let you add pages,
change settings and call Save, and the changes were quietly not written. Now these calls throw
InvalidOperationException:
AddPage,InsertPage,ImportPageand the other page methods onPdfDocumentandPdfDocument.Pages, includingRemoveandRemoveAtSave- the
Version,PageLayout,PageModeandLanguagesetters
The message names the mode you used and the modes the operation needs:
This document was opened with PdfDocumentOpenMode.ReadOnly and adding a page needs a document
opened with PdfDocumentOpenMode.Modify or PdfDocumentOpenMode.Append.
If you see it, change the mode you pass to PdfReader.Open: Modify to change a document, Append
to add a revision with an incremental save. Close is not affected. See
Opening documents.
Behaviour you will notice
Fonts are always embedded. There is no setting to turn embedding off. PdfDocumentRenderer has
two constructors, PdfDocumentRenderer() and PdfDocumentRenderer(bool unicode); the old overload
that took a PdfFontEmbedding value does not exist.
XGraphics.DrawString draws one line. A tab becomes a space, and every other control character,
including \n and \r, is dropped. MeasureString still splits on line feeds. For text over several
lines, use XTextFormatter or PinataLayout. See Text layout.
Right-to-left text is put in reading order for you. Hebrew and Arabic runs are reordered by the
Unicode bidirectional algorithm without any extra package. If your code reversed such strings by
hand, remove that code, or the text will come out backwards. Joined Arabic letter forms need
PdfPinata.HarfBuzz. See International text.
PinataLayout tags its output. PdfDocumentRenderer.TagContent is true by default, so every
rendered PDF carries a structure tree for screen readers. PdfPage.Resize refuses a tagged document;
set TagContent = false if you resize pages after rendering. See
Accessibility.
A page with content cannot be resized by setting its size. The PdfPage.Size, Width and
Height setters throw InvalidOperationException on a page that already has content. They used to
write a new media box, which cropped the page and kept its bottom part. Call page.Resize(size)
to scale the content into the new size. See
Page resizing and bleed.
PageFormat.B5 is ISO B5. It was the JIS sheet, 182 × 257 mm. It is now 176 × 250 mm, so a
section set to it reflows. To keep the old sheet, use PageFormat.JISB5.
PageSize.Executive is 7.25 × 10.5 inches. It was 7.5 × 10 inches.
A stray heading row throws. A table row with HeadingFormat = true that is not part of the run of
heading rows at the top of the table throws InvalidOperationException during layout. It used to be
ignored, so the heading did not repeat. Mark every row from the first down to the last heading row.
Trimmed pages are bigger. A page with TrimMargins set now gets room outside the bleed for crop
marks, 5 mm on each edge by default, and the marks are drawn. Set page.MarkMargins.All = 0 to get
the page boxes earlier versions wrote.
Opaque pages carry no transparency group. A page gets a /Group entry only when something on it
uses transparency. Opening and saving a document no longer adds one to every page.
Changed and removed members
These affect you only if you call or implement them:
XImage.AsBitmap()is nowXImage.GetPixels(), which returns aPixelBufferof BGRA pixels instead of BMP file bytes.IImageSource.SaveAsPdfBitmap(MemoryStream)is nowPixelBuffer GetPixels(). Change your implementation if you wrote your own image source.IXGraphicsRenderer.DrawStringtakes anXPenbefore theXBrush. Passnullfor the pen to keep the old behaviour.PdfDocumentOptions.EnableCcittCompressionForBilevelImagesis gone. It never had an effect; delete the assignment.XGraphicsPath.AddStringnow adds the glyph outlines to the path. It used to leave the path empty. It needs a glyph outline provider, as described above.XGraphics.MeasureString(text, font, format)now measures with the format you pass. It used to ignore it.
Things to know
- Keep the packages on one version. All nine packages are released together with the same version number. Upgrade them together.
- The ImageSharp backend needs ImageSharp 2.1. It does not work with ImageSharp 3. If your application needs ImageSharp 3 for other work, use the Skia backend. See Platforms and deployment.
- The Skia backend needs native assets. Reference the
SkiaSharp.NativeAssetspackage for each platform you run on; PdfPinata does not choose them for you. - Register backends in one place. The font resolver is global to the process and cannot change after first use, so set it in your start-up code, not in a library or a test.