It is Clear[Type] how the quality is being managed

by Michael S. Kaplan, published on 2006/10/22 03:02 -04:00, original URI: http://blogs.msdn.com/b/michkap/archive/2006/10/22/854820.aspx


Lots of people have pointed out both before and after I did in When a user sets something. please assume they meant it how unfortunate it is that so many different applications and processes turn on ClearType whether the user wants it on or not.

Well, just as I previously talked about how the design of IsNLSDefinedString was actually a a bit of an exercise in social engineering, the unfortunate fact is the documentation about ClearType and its pointers to the fdwQuality parameter in the CreateFont function and the lfQuality member of the LOGFONT structure make it really easy to decide what you want the behavior to be:

Value Meaning
ANTIALIASED_QUALITY Windows NT 4.0 and later: Font is antialiased, or smoothed, if the font supports it and the size of the font is not too small or too large.

Windows 95 with Plus!, Windows 98/Me: The display must greater than 8-bit color, it must be a single plane device, it cannot be a palette display, and it cannot be in a multiple display monitor setup. In addition, you must select a TrueType font into a screen DC prior to using it in a DIBSection, otherwise antialiasing does not happen.
CLEARTYPE_QUALITY Windows XP: If set, text is rendered (when possible) using ClearType antialiasing method. See Remarks for more information.
DEFAULT_QUALITY Appearance of the font does not matter.
DRAFT_QUALITY Appearance of the font is less important than when the PROOF_QUALITY value is used. For GDI raster fonts, scaling is enabled, which means that more font sizes are available, but the quality may be lower. Bold, italic, underline, and strikeout fonts are synthesized, if necessary.
NONANTIALIASED_QUALITY Windows 95 with Plus!, Windows 98/Me, Windows NT 4.0 and later: Font is never antialiased, that is, font smoothing is not done.
PROOF_QUALITY Character quality of the font is more important than exact matching of the logical-font attributes. For GDI raster fonts, scaling is disabled and the font closest in size is chosen. Although the chosen font size may not be mapped exactly when PROOF_QUALITY is used, the quality of the font is high and there is no distortion of appearance. Bold, italic, underline, and strikeout fonts are synthesized, if necessary.

Looking at wingdi.h, the values behind these constants are:

#define DEFAULT_QUALITY 0
#define DRAFT_QUALITY 1
#define PROOF_QUALITY 2
#if(WINVER >= 0x0400)
#define NONANTIALIASED_QUALITY 3
#define ANTIALIASED_QUALITY 4
#endif /* WINVER >= 0x0400 */

#if (_WIN32_WINNT >= _WIN32_WINNT_WINXP)
#define CLEARTYPE_QUALITY 5
#define CLEARTYPE_NATURAL_QUALITY 6
#endif

Yes, there is that extra CLEARTYPE_NATURAL_QUALITY constant which is defined in the header file and documented all over creation except on MSDN right now. Good luck trying to determine what it means. :-)

The method that anyone who wants to ignore the user setting will use is to jut pass a different value in the fonts that are created....

And what about managed code?

Well, the truth is that GDI+ does not define any of this stuff in its font creation, as code like this shows:

using System;
using System.Drawing;
using System.Runtime.InteropServices;

namespace FontStuff {
  class test {

    private unsafe struct LOGFONT {
      public int lfHeight;
      public int lfWidth;
      public int lfEscapement;
      public int lfOrientation;
      public int lfWeight;
      public byte lfItalic;
      public byte lfUnderline;
      public byte lfStrikeOut;
      public byte lfCharSet;
      public byte lfOutPrecision;
      public byte lfClipPrecision;
      public QUALITY lfQuality;
      public byte lfPitchAndFamily;
      public fixed char lfFaceName[32];
    };

    private enum QUALITY : byte {
      DEFAULT_QUALITY = 0,
      DRAFT_QUALITY = 1,
      PROOF_QUALITY = 2,
      NONANTIALIASED_QUALITY = 3,
      ANTIALIASED_QUALITY = 4,
      CLEARTYPE_QUALITY = 5,
      CLEARTYPE_NATURAL_QUALITY = 6
    }

    [DllImport("gdi32.dll", CharSet=CharSet.Unicode, ExactSpelling=true, CallingConvention=CallingConvention.StdCall)]
    private static extern int GetObjectW(IntPtr hgdiobj, int cbBuffer, out LOGFONT lpvObject); 

    [DllImport("gdi32.dll", CharSet=CharSet.Unicode, ExactSpelling=true, CallingConvention=CallingConvention.StdCall)]
    private static extern IntPtr CreateFontIndirectW(ref LOGFONT lplf);

    [DllImport("gdi32.dll", ExactSpelling=true, CallingConvention=CallingConvention.StdCall)]
    private static extern bool DeleteObject(IntPtr hObject);

    [STAThread]
    static void Main(string[] args) {
      if(args.Length != 1) {
        Console.WriteLine("You have to give a font name.");
      } else {
        Font fnt = new Font(args[0], 9);
        IntPtr hFont = fnt.ToHfont();
        LOGFONT lf = new LOGFONT();
        if(GetObjectW(hFont, Marshal.SizeOf(lf), out lf) != 0) {
          Console.WriteLine("The GDI+ lfQuality of '{0}' is {1}.", args[0], lf.lfQuality);

          lf.lfQuality = QUALITY.CLEARTYPE_QUALITY;
          IntPtr hFont2 = CreateFontIndirectW(ref lf);
          if(hFont2 != IntPtr.Zero) {
            Font fnt2 = Font.FromHfont(hFont2);
            IntPtr hFont3 = fnt.ToHfont();
            LOGFONT lf2 = new LOGFONT();
            if(GetObjectW(hFont3, Marshal.SizeOf(lf2), out lf2) != 0) {
              Console.WriteLine("The modified GDI+ lfQuality of '{0}' is {1}.", args[0], lf2.lfQuality);
            }
          }
          DeleteObject(hFont2);
        }
      }
    }
  }
}

It will pretty much always return DEFAULT_QUALITY for any font created from GDI+ even if it is created with a ClearType-enabled font on the Win32 side. And the same thing will happen with any font that heads through GDI+. This makes it much harder to actually translate ClearType usage across the managed/unmanaged boundary of GDI/GDI+.

To get ClearType support within GDI+, as the MSDN help topic Antialiasing with Text indicates, you have to set the Graphics.TextRenderingHint property to one of the members of the TextRenderingHint enumeration.

The docs are not entirely clear on the point though, because even though they say things like

The quality ranges from text (fastest performance, but lowest quality) to antialiased text (better quality, but slower performance) to ClearType text (best quality on an LCD display).

the actual values behind the enumeration are not given, and the members are listed alphabetically rather than by any kind of range order. The actual ordered list, values 0 to 5, would be:

Now this list does not seem to be in any kind of range order either, for what its worth. :-)

Though by making it a setting to make for each Graphics object rather than each font, it is perhaps a bit less common to actually change the value from what the system wants. It is a subtle difference, but in the end you are hopefully much more likely to see (for example) WinForms applications follow the system settings. Thank goodness for small favors.

Now Avalon (WPF) does this an entirely different way, and I will have to talk about that another day....

 

This post brought to you by (U+239a, a.k.a. CLEAR SCREEN SYMBOL)


# Robert on 23 Oct 2006 2:05 AM:

CLEARTYPE_NATURAL_QUALITY: My guess was that text output functions would use native ClearType metrics rather than adjust glyphs to fit the metrics of ANTIALIASED_QUALITY/NONANTIALIASED_QUALITY. For example, 8pt Tahoma 's' on 96dpi is one pixel wider with CLEARTYPE_NATURAL_QUALITY enabled. But I may be entirely wrong...

# Mike Dimmick on 23 Oct 2006 5:37 AM:

I had an experience with Vista's scaling options on my new laptop over the weekend. The laptop has a 15.4" panel in 16:10 at 1680x1050 pixels, which makes it about 13.06" across and therefore about 128ppi. So I used the DPI control panel to set 120dpi - and received the same nasty font shapes and bad scaling that happened in Windows XP.

I thought Vista was supposed to fix this? I went back into the DPI Settings dialog and tried custom settings, and spotted the 'Use Windows XP Scaling' checkbox, which was checked. I unchecked it.

I can see why it was checked by default. With this checkbox checked, Vista applies ClearType _before_ passing the texture to the video card to be scaled. Result, really, really blurry text. Horrible.

I went back to 96 dpi. It might be that I'm more familiar with those character shapes, but it looks a lot better.

Then I wiped Vista (build 5744) off, because I'm not going to upgrade. I really just wanted to see how well the new computer performed compared to the old one (very well, although I had to run the experience score calculator a second time because I didn't believe the desktop graphics score of 2.2 - this went up to 3.1 the second time round).

With Vista it's very much, "you had me and you lost me." Through the betas I had problems with eVC 3.0 and 4.0 (still essential for my work) but hoped that these would get a compatibility shim. The announcement that VS2003 and SQL Server 2000 would not be supported was a blow, and you probably lost me at that point, but the licensing announcements have switched me to advising friends not to bother. I'm really sorry for you guys with the hard work that you've put in, because your management and marketing seems to have blown it at the last minute.

# Michael S. Kaplan on 23 Oct 2006 10:20 AM:

Hi Mike,

Peter Constable has gotten me interested in the whole "Natural DPI" thing -- where you use a custom setting and get the ruler to make the inch look exactly like an inch. It made everything look pretty good (XP scaling off, of course!)....

It's too bad you didn't leave it installed just a little bit longer, in my opinion. You know, at least long enough to be able to look at some of the cool international features? :-)

But I understand what you are saying, and I hope you end up with an opportunity to reconsider at some point, because there are some really cool things there....

# Mike Dimmick on 23 Oct 2006 6:59 PM:

I'm just trying custom scaling on XP and IE7 is a little broken! You may not be aware that they're turning off ClearType (even if ClearType is ON in the Desktop control panel, grrr) anywhere that one of the DirectX Transforms is enabled, which gives you poor aliased type in the left-hand pane and bottom bar on the microsoft.com homepage, and numerous places on msdn.microsoft.com due to the use of gradient fills. Anyway, on turning on 144dpi (150%), the formerly aliased text seems to be rendered at 96dpi then scaled up using some filtering technique, because it's extremely blurry. It's the same at 120dpi, actually!

The fact that this was not spotted in beta suggests that I'm not the only one who sticks with 96dpi regardless of the monitor's actual ppi.

The icons on the buttons in the Favorites Center are also way too small. I'm not sure if that's better or worse than being hideously scaled like the icons in the shutdown dialog.

I'd post this on Connect, but the IE7 team have just shut down their feedback site for the time being. Presumably this is to review all the bugs and suggestions that weren't implemented in IE7 final.

Another problem I have is that I'd like to be able to use my old monitor - 19" LCD at 1280x1024, approx 86ppi - as a second monitor, but I can only select one global DPI value. Whichever DPI setting I choose will be a compromise.

# Dean Harding on 25 Oct 2006 1:58 AM:

Mike: I'm not sure what you mean by the text scaling issues. If you have that "Use XP-style scaling" UN-checked, then things certainly look pretty horrible most of the time (unless you manually go in to each application an uncheck the "apply scaling" in it's compatibly dialog). But if you check the XP-style scaling, then things look pretty good, in my opinion.

Well, mostly. Bitmaps don't scale very well, unfortunately. But I would definitely agree that most Microsofties probably don't run at anything other than the default 96DPI, because there are some pretty brain dead bugs in a few Microsoft apps (and of course, Win Forms has pretty atrocious support for non-96DPI display built right in, but at least that's fixed for WPF). At list Microsoft apps are better than most other software out there, though!

Non-96DPI support is something that's pretty near-and-dear to my heart, having run my laptop at a higher DPI for a couple of years now. MOST things are getting better, but you do sometimes run into a backwards step (like when upgrading from MSN messenger, which did high DPI nicely, to Windows Live Messenger, which does not).

I also agree that not being able to set DPI separately for each screen is a bit annoying (like not being able to set ClearType separately for each display, but lets not go there :).

# Michael S. Kaplan on 25 Oct 2006 2:14 AM:

On my Latitude D820:

Everything looks about the same size on the screen as it did at 96 DPI but everything looks sharper and crisper....

# Dean Harding on 25 Oct 2006 2:57 AM:

I'm about the same, except I turn XP scaling ON. The problem with having it off is that most apps are scaled by simply scaling their bitmap which makes everything blurry. The other problem I had with it was that some dialogs which tried to pop up in the centre of the screen ended up being moved down and to the right... (plus a couple of other "minor" bugs)

Though, to be honest, I only tried it in Vista beta 2, never in any of the RC versions, so maybe it improved?

# Yuhong Bao on 28 Oct 2006 2:40 PM:

"The announcement that VS2003 and SQL Server 2000 would not be supported was a blow, and you probably lost me at that point, but the licensing announcements have switched me to advising friends not to bother. I'm really sorry for you guys with the hard work that you've put in, because your management and marketing seems to have blown it at the last minute."

Maybe, but if I were forced to choose between supporting VB 6 and VS 2003 when VS 2005 is supported, I would choose VB 6. Because it is MUCH easier to upgrade from VB .NET 2003 to VB 2005 than upgrading from VB 6 to VB 2005.

# shyam on 11 Nov 2007 2:48 AM:

i want to create a keyboard usercontrol in vb 6 what can i do

# Michael S. Kaplan on 11 Nov 2007 7:16 AM:

Maybe ask over in the Suggestion Box, for starters? The question has nothing to do with this post whatsoever....


referenced by

2006/10/25 It is a challenge to make ClearType irrelevant

go to newer or older post, or back to index or month or day