PDFsharp includes an XTextFormatter class that allows to draw text with line breaks.
A frequently requested feature: how to measure the height of the text before drawing it? I decided to add this measuring functionality. I found it was more difficult than I expected.
The unexpected problems were of a technical kind: the class XTextFormatter uses internal members of the XFont class. Therefore you cannot use my new class XTextFormatterEx with the NuGet packages from PDFsharp.
As of now (July 17, 2015) there is one way to use my XTextFormatterEx: download the source package of PDFsharp 1,32 and copy XTextFormatterEx.cs into the folder where XTextFormatter.cs is: PDFsharpcodePdfSharpPdfSharp.Drawing.Layout
In your Visual Studio solution you have to add references to the PDFsharp projects using Add => Existing Project. Do not forget to include the file XTextFormatterEx.cs in the project “PdfSharp”.
Sounds complicated? Sorry, it is complicated. I was hoping that it would be possible to include the class XTextFormatterEx.cs in the application project and use it with either the NuGet package, the pre-compiled DLLs, or the source package. But the references to internal members of the XFont class rule out two of these three ways. Maybe all three methods will work with future versions of PDFsharp.
And now for the good news: let’s talk about the new features.
A normal call to the XTextFormatter class looks like this:
tf.DrawString(text, font, XBrushes.Black, rect, XStringFormats.TopLeft);
If the rectangle is too small, the text will be truncated. But you cannot find out how much text was drawn and how much was truncated.
And now we look at the new methods:
XTextFormatterEx tf = new XTextFormatterEx(gfx); int lastCharIndex; double neededHeight; // Draw the text in a box with the optimal height // (magic: we know that one page is enough). XRect rect = new XRect(40, 100, 250, double.MaxValue); //tf.Alignment = ParagraphAlignment.Left; tf.PrepareDrawString(text, font, rect, out lastCharIndex, out neededHeight); rect = new XRect(40, 100, 250, neededHeight); gfx.DrawRectangle(XBrushes.SeaShell, rect); tf.DrawString(XBrushes.Black, XStringFormats.TopLeft);
When calling PrepareDrawString you specify the text and provide a rectangle with the available space (a height of double.MaxValue won’t be a good idea for real world applications).
“lastCharIndex” returns the index of the last character that can be drawn in the rectangle. This will be -1 if the complete text was drawn.
“neededHeight” will return the space that is needed for the text.
This will be a negative value if no text can be drawn. If the rectangle is too small even for a single line, this will be the height of the first line; in this case “neededHeight” will be larger than the height of the original rectangle. If the text will be truncated, this will be the height needed for the truncated string.
To draw the text, you can and should use a new variation of DrawString that only takes a brush and an XStringFormat as parameters. This will draw the text that was most recently prepared. This is more efficient than using the DrawString method that also takes the text and the font as this version will layout the text again.
You can download the complete XTextFormatterEx class as a ZIP file (about 5 kiB in size).
Please note that this post from 2015 applies to PDFsharp 1.32.
With PDFsharp 1.50 and later you need a slightly modified version, XTextFormatterEx2, that no longer needs “internals” from PDFsharp.
XTextFormatterEx2 for PDFsharp 1.50 and later.