HowTo: use Text Rendering using GDI and/or Direct2D in Xojo 2018r3

With Xojo 2018r3, Labels have been changed to use GDI-rendering - making them look much better on non HiDPI Monitors.
But way more important: we can now leverage two Text rendering methods: Direct2D and GDI.

In the PreRelease channel, this has been explained - now that Xojo 2018r3 is public, I’d like to copy-and-paste the most important information here.
There are a couple of things to remember and watch out for, which I believe are not explained in the Docs…

Good news :slight_smile:
With 2018r3b1, we can pretty much do everything exactly the way we need it (to look and render)!

After playing with 2018r3 (and getting some info from the engineers) let’s explain this in a bit more detail, since the implementation of rendering mechanism has changed in 2018r3:

  • GUI Controls (Paint Events): GDI-compatible text renderer
  • non alpha-supported Picture New Picture(1,1,32): GDI-compatible text renderer
  • alpha-supported Picture New Picture(1,1): Direct2D rendering (text gets aliased improperly with GDI)
  • Printing Graphics: Direct2D rendering (no quality issues there with Direct2D, but a lot of quality benefits)

So this is the new “automatic/default” rendering mechanism/choice. And I have to say: Well done - this fits best for 95% of situations!
In fact: I’m more than happy that Printing uses Direct2D!
It requires a bit of refactoring of code for Apps for TargetWindows – but the result is the best!
And everything GUI-related (custom Controls) render perfectly on non HiDPI Monitors thanks to GDI. And as much important: the Texts in GUI render consistent (no more Listboxes or Custom Controls that render text differently).

Pitfalls: The tiny but big difference
Check your code for New Picture(1,1,32) (GDI) and New Picture(1,1) (Direct2D)

  • Text will be rendered differently
  • StringWidth, StringHeight will be different (for the same Font/Size)

Printing and Print Preview
Again: Great choice to use Direct2D for Printing. Why?
Let’s assume an app that works like this:

  • is creating a dynamic report
  • needs to calculate a lot of StringWidth/Height in order to layout a report
  • this is done once (before showing it as PrintPreview or sending it to the printer) -> with NO Graphics Object (so it doesn’t have a GDI or Direct2D Context!)
  • you calculate everything in your ‘LayoutDPI (300)’
  • the whole report is being created as a Group2D with a lot of Object2D’s
  • PrintPreview: the created report (Group2D) is drawn in a Canvas (GuiDPI: 72) -> Group2D.Scale = 1/LayoutDPI*GuiDPI
  • Printing: the created report (Group2D) is drawn to the Printer Graphics (Printing DPI: 1200) -> Group2D.Scale = 1/LayoutDPI*PrintingDPI
    Now, with GDI, this doesn’t work perfect. Once you scale, a Line/Rectangle (which has been calculated in LayoutDPI to be the same Width as some Text) will be different.
    Not so with Direct2D: all is aligned perfectly, even if scaled for Preview or Print.

Refactoring required for Report-Creation, PrintPreview and Printing:

  • if you calculate StringWidth/Height in report-creation using LayoutDPI: use a Direct2D Context by using a New Picture(1,1) (and set .ScaleX/Y if required). Be aware NOT to use New Picture(1,1,32)
  • if you want to draw the Print Preview: draw using Direct2D. So that the Preview is being rendered (and Strings have proportionally the same width/height) as the actual print. How to do that? DON’T use Canvas.Paint: g.DrawObject(myReportAsGroup2D). Create a New Picture(width,height) (Direct2D) and Canvas.Paint: previewPict.Graphics.DrawObject(myReportAsGroup2D). Only then Canvas.Paint: g.DrawPicture(myPreviewPictureRenderedInDirect2D)
  • drawing to Printer Graphics: just draw the Group2D as usual (and setting the .Scale for printing)
    Since we’re printing with Object2D’s, this works very well for us. But you have to check your code…! I hope the above information helps you to know what to be aware of.
    Let’s assume you just .DrawString in both Preview and Print: this will render differently! Make sure your Print-Preview is going the “work around” way by drawing to a alpha-supported Picture (using Direct2D) first, only then to the Canvas. And do any StringWidth/Height calculations like this.

To end this long post… a big thanks to Xojo and thumbs-up for 2018r3. This is a big improvement for the Windows Framework!

All nice info Jurg, thanks.

Its just a shame that 20 canvas now suffer the same problems that 20 labels did, the problems have just been shifted.