Skip to main content

Of Fonts and Java2D

Posted by javaben on January 25, 2008 at 8:08 AM PST

The other day I googled for information on nice-looking fonts
for Java2D and found nothing; this entry is largely to help future
googlers.

A poorly-rendered typeface can really ruin my day. I'm passionate
about creating beautiful software. Well, for the sake of those who've
seen my code, I should clarify: beautiful user interfaces.

Generally, I'm satisfied that when my attempts fall short of my ideals,
I'm the weak link in the process. After all, I control every pixel
on the screen, so whether they look purty or not is my problem.

Except for the fonts. Ah, the fonts. Translating typefaces into pixels
is a complex problem I'm all too happy to leave to others
to solve. But of course, that's the double-edged sword; I'm stuck with
other people's solutions, be they good, bad, or somewhere
in-between.

I often find myself building user interfaces in Java Swing. Interestingly,
Swing typically renders its own fonts--it doesn't rely on the underlying
operating system. (Apple's JRE lets developers choose between having the OS
or Java2D do the font rendering, but in the future, it appears this choice
will go away in favor of Java2D). This could be a really good thing, if
Java2D rendered better than the OS. Unfortunately, when compared to Windows
and OS X, it doesn't. (It might render better than Linux, but I've never cared about
that OS.)

This characteristic of Java GUIs is still arguably a good thing, because Java
applications render consistently across differently platforms; consistently
subpar rendering to many is better than inconsistent rendering behavior,
which could lead to all kinds of problems when the bounds of strings are different
on different operating systems.

The Problems with Java2D Fonts

I've been blabbing about how Java2D font rendering is worse than that of
Windows and OS X. In what way is it worse? Back in 2004, I identified and documented what I
judged to be the four most serious problems
.
I'll summarize these issues here:

  1. Swing makes it difficult to use anti-aliasing. Back then, you had
    to either create your own UI delegates or subclass components.
    Nowadays, Swing either does the right thing and/or lets you configure
    global anti-aliasing with system properties.
  2. Java2D mis-renders many glyphs. At the time, I listed these examples:
    • Arial 13pt (compare to Windows' 10pt rendering): x, S, X
    • Microsoft Sans Serif 11pt (Windows' 8pt): x, C, M, Q, 8, 9, )
    • Times New Roman 16pt (Windows' 12pt): 8
    • Tahoma 12pt (Windows' 9 pt): D
    • Tahoma 13pt (Windows' 10 pt): q
    • Tahoma 16pt (Windows' 12 pt): a, 0

    Here's one screenshot from the document that illustrates the problem:


    Today, I glanced at the same font in the image with Java 6
    running on Windows XP today:

    Java2D Arial 13pt rendering on Java 6 / WinXP

    We've come a ways: the 'S' looks great, but the 'x' and 'X' are probematic.
    That doesn't bother me too much, however, because of the next point.

  3. Java2D lacks sub-pixel anti-aliasing. Well, not anymore. As Chet explained at
    length some time ago, Java2D now uses sub-pixel anti-aliasing when rendering
    fonts. The Arial 13pt example above now looks like this:

    Java2D Arial 13pt on Java 6 / WinXP w/ sub-pixel AA turned on

    How do you like them apples? In my experience, Java2D glyphs look really nice
    with the new sub-pixel anti-aliasing, and it makes Swing look really
    competitive with Windows XP font rendering with ClearType, as you can see:

    Windows versus Java2D

    In the image above, Windows is on the top and Java2D is on the bottom. I
    prefer the weightier Windows rendering, but the Java2D rendering is nice.

  4. Java2D needs higher-quality font rendering techniques, such as
    better glyph layout. Admittedly, this is a bit of a catch-all, but features
    like ligatures and properly spaced characters make a big difference in
    the quality of type. Unfortunately, I can't see that this has gotten much better.

A Problem of Spacing

To get a feel for the problem of spacing, check out how both OS X and Java2D
(Java 1.6, Windows XP) rendering the same text with Lucida Grande Bold (11 points,
Java2D text attributes set to PLAIN):

Java2D versus OS X with Lucida Grande Bold at 11pts

It's pretty amazing how gorgeous OS X's rendering of the text is; it's as though
a magazine climbed into my LCD. The Java rendering looks pretty rough, due to both
the glyph quality and their spacing.
Check out the difference in character spacing in the word "quick"
versus the word "brown" or how the "ps" in "jumps" is floating a bit too far to
the right; also, note how Java renders the 'e', 'q', and 'w' compared to the Mac.
It's pretty hard to argue that one could prefer the Java rendering, though the
increased intensity of the pure white hue is a potential benefit.

Am I Crazy?

I know there are a large swath of folks who are just happy if they can get their
app to do something and view my rambling on about fonts as silliness. I have
no problem with such.

My point here is that when you want to create gorgeous applications, these
things really do matter, and they matter quite a bit. If you disagree with this
assertion, well, we'll just have to disagree. (I'm reminded of a recent Wall
Street Journal column by Lee Gomes in which he said audiophiles are divided into
two camps: the crazy and the totally insane.)

What To Do?

I've had the opportunity to meet Phil Race, the font guru on the Java2D team,
and I'm satisfied that he's smarter than I'll ever be, that he knows about these
problems, and that he'd fix them if Sun's priorities and resources
permitted such to happen. And who knows but that such fixes are already in the
pipeline? (Well, I guess Phil knows.)

That doesn't relate to my problem: I've got an app that I need to make gorgeous
today. So, what do I do? I don't have time to render fonts myself. That's
Hard Stuff. But, I could lay out the individual glyphs myself and do a better job
than the Sun folks. But, having met Phil, I assume if that problem were non-trivial,
he'd have improved it himself by now. However, by only caring how fonts look in
my
applications, as opposed to the entire world's set of Swing apps, perhaps I can
get some results in this area.

Finding the Best Fonts for Java2D

In a past life, I did lay out glyphs myself, but that code no longer belongs to
me, and I'm not in the mood to write it again. So the easiest solution is simply
to check how Java2D renders fonts at different
sizes and see which ones look best. I created a simple program and rendered some
test output for Java2D using sub-pixel anti-aliasing (HRGB) with all of the fonts
available to the JRE in a default Windows XP installation (along with Lucida Grande
Bold), split into three
large
images.

My favorites are:

  • Arial 11pt Plain (12 and 13 ain't bad either):

  • Franklin Gothic Medium 9pt Plain--what an attractive small typeface! 10 and 11
    are pretty good as well:

  • Georgia 9pt Plain, a seriffed answer to Franklin Gothic's clarity (10-13 are
    also really nice):

  • Lucida Sans Regular 12pt Plain (11 is also nice):

  • Microsoft Sans Serif 12pt Plain

  • Segoe UI 11pt Plain

  • Verdana 9pt and 11pt Plain

Your Favorites?

I was surprised at just how good some of these fonts look. Thanks Phil!
Did I miss some other good ones? Are there other fonts that you've used with good
results in Java2D? What are your "go to" fonts for beautiful type at large sizes?

Update: Whoops. I put together this blog entry in a bit of a hurry whilst flying from Point A to Point B and I included some faulty images (due to a bug I introduced in the program I wrote to display the fonts; the last 2/3 of the fonts weren't sub-pixel AA'd):

  1. The comparison between Lucida Grande Bold Java2D vs. OS X originally showed the Java2D rendering without sub-pixel AA; this was a mistake. I updated it with a sub-pixel AA version, as shown above. Note that the observations about subpar glyph formations and layout still remain valid (as I originally noticed them with properly sub-pixel anti-aliases imagery).
  2. Two of the three large images I linked to were not sub-pixel anti-aliases as claimed. This has been fixed.
  3. Six of the seven fonts displayed at the end of the blog entry were not sub-pixel anti-aliased; this has been fixed.

The observations that drove me to write this blog entry were with properly sub-pixel anti-aliased type; so the content stands. Sorry for the goof-up.

Related Topics >>

Comments

You may be surprise to know

You may be surprise to know that i did not know about it before , actually i came here while working on data related to projects of wonderlic practice test and find this post and web different one , there are certainly many different posts at here and this one also seems to me different one , one may get useful information from this.

Our users complain -- rightfully so -- if the Swing application's font is anything other than the system font, so there's no "pick the best looking font" for us.

On XP, where that system default is typically 11pt Tahoma, things look pretty good. But 12pt Segoe UI on Vista just does not look good with Swing's subpixel AA algorithm. Specifically, most letters, especially those with complete enclosures (there's probably a fancy typesetting name for such things) look too thin.

But this is all captured in Sun bug 6449753.

benloud: thx for the link; that's hot stuff

Just discovered this, it looks like Sun might be considering switching to using ClearType to rasterize glyphs on Windows: http://bugs.sun.com/view_bug.do?bug_id=6656651

BTW what I'd like, related to fonts and text layout is that the "invisible" Unicode character were interpreted by the swing textviews as "invisible"! not '?'. Those invisible chars are mostly useful in text parsing where if for example i want all text to have a consistent 1 space between words, instead of string buffer or array messing, i'd have a O(1) operation and the cost being delegated to rendering (much more episodic a light you'd agree). Also I'd like if the swing components didn't need to layout all of the text when resizing etc. That is good for full text application like browsers but for paginated application like ebook readers its really awful (and requires a icky view/model incest since viewToModel doesn't really work - or i couldn't get it to work).

You are not crazy. I've created a program just to read ebooks consistently, and without antialiasing I'd go mad. (Admittedly because my screen is dying and has a wierd violet hue if i don't use black as foreground.)

Clearly Java2D should be trying to catch up with Apple's font rendering, not Microsoft's. It's noticeably better. It would be funny to see Java2D render nicer than the native OS and that could be a good sales point for using it.

The best would be to use Kirill Grouchnikov's solution to use the OS native text rendering in Java 7, it will achieve the best quality http://www.pushing-pixels.org/?p=226

Mik asks:
>why is there no way to globally turn kerning on for my own apps?

I presume you are asking a "Swing" question, since for Graphics, all settings are the state of that graphics and nothing more, there's not a concept of an "app".

For Swing the answer for kerning would be the same as for some other hints. There are open Swing RFEs to provide a way to set the hints via some Swing provided API, rather than digging into the graphics which isn't supported, except for on own your own custom rendered components. Eg see http://bugs.sun.com/view_bug.do?bug_id=6485977

-phil.

Phil, why is there no way to globally turn kerning on for my own apps?

On Kerning & ligatures :

Kerning and Ligatures are indeed off by default in 1.6, but easily turned on by setting an attribute on the font (no need to use TextLayout).

The reasons for off by default are

  1. performance: yes it is much slower to do the additional processing for these tables. [And GDI on Windows does not do either of these. There isn't even an API to request it]
  2. metrics compatibility: something we've paid a lot of attention to because some people with loud voices have programmed their UIs without the flexibility to accommodate any change in the size of fonts. If we applied kerning or ligatures automatically text would measure differently and UIs would layout differently.

    This sort of concern is the same reason the Swing Ocean L&F is stuck with the Bold font choice made in the mid to late '90s.

Some one observed little difference turning on these options : that is font dependent. The font needs to have the tables and within them entries that affect the specific text being rendered. By no means all fonts do.

-Phil.

benloud: By the way, the font you've rendered in your image is a pixel-perfect match for Java2D's rendering of Arial at 11 points. I think perhaps you've got some wires crossed on your end; Lucida Grande Bold should look very different from Arial.

benloud: Jeepers, you're right about the lack of sub-pixel AA! Ugh. I updated the blog entry and noted the correction at the end. Many of the images were AA'd, but many were not. A bug in the program I used to generate the bitmaps for the entry. When I adjusted the code to split the text into three smaller images instead of one huge one, I neglected to set the rendering hints on the new images. So the first third of the samples were AA'd, the others weren't.

As you'll notice from the AA'd version of Lucida Grande Bold (compared to OS X), you'll see that the comments on the glyphs and the issues with layout are... exactly the same.

RE: OS X "grayscale AA only". Hmm. Dunno what to tell you there. Rendered using Keynote against a black background on a 24-bit color display. If Keynote does something that OS X normally doesn't, I'd be surprised. I'll look into it. My "Foot Smoothing Style" is set to "Automatic" and I was using a laptop to make the screen capture.

I noticed from your screen capture that your LCD rendering looks bad on my display; it looks like we have different pixel ordering. Mine is HRGB; what's yours? I'll take a closer look at your samples and mine on Monday.

As for how I rendered it, nothing fancy:

g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_LCD_HRGB); g2d.setFont(f); g2d.drawString(STRING, x, y);

I'm still not convinced layout is the problem. Take the image under your "A Problem of Spacing" title. The Java version on the top line is rendered with no anti-aliasing at all, so of course it looks rough. Plus, the OSX version on the bottom line appears to be rendered with grayscale AA only, so it ends up looking gray and blurry instead of white. No wonder the 'e', 'q' and 'w' look completely different because they're rendered with different settings. Render both with LCD AA for a better comparison.

I will admit you have a point that the p in jumps should be one pixel to the left. But I'm not sure what you did here (since theres no AA). When i render the same, white on black, exact same font, and size, with LCD AA, it looks just fine to me. I also tried it with no AA and it still looks fine. (proof: http://benloud.com/aa.html) How exactly did you render these?

Also, those large images you've posted, its worth pointing out that none of them have any AA enabled at all. I'm sure they'd look much better with LCD AA enabled, particularly the small sizes.

Argh! You're right. It was Arial. Because I'm on Windows and dont have Lucida Grande. Well spotted!

mikael: I turned on ligatures and kerning and... saw no differences whatsoever. I wrote a program to scan the image output with and without kerning and ligatures. For much of the output, there were no different pixels whatsoever. A few fonts do render differently, but the differences I've seen so are quite minute. For example, Franklin Gothic Medium Italic at 12 pts has one difference with kerning/ligatures: the 'e' in 'over' is placed slightly closer to the 'v'.

I'll have to chew over the data a bit more to draw some conclusions.

kirill: I can't wait to take a look at how this works in my applications. Thanks, man.

Ben, you can follow the links from this entry that detail how SWT native font rasterizing can be used in Swing applications.

They are OFF by default I mean..

> I'm not sure if these are on or off by default;

They are. :( And i guess there is a big performance hit or I can not understand why there is no simple way to turn them on globally. I understand if Sun do not want to turn them n by default (unless we have a COMPATIBILITY API hint hint ;) but if I want to I would like to have them without subclassing every UIDelegate..

But... I guess they do not care about the desktop... (cough).. ;)

benloud: Java 1.6 did indeed introduce kerning and ligatures as optional settings. Cool! You can set these at the font level rather than TextLayout:

attrs = new HashMap(); attrs.put(KERNING, KERNING_ON); attrs.put(LIGATURES, LIGATURES_ON); font.deriveFont(attrs);

I'm not sure if these are on or off by default; I'll have to read up a bit later and re-run my samples. Hopefully these improve some of the layout spacing issues I've noticed.

benloud: Your comment seems to be chiding me into recognizing that rendering fonts is hard and lowering my expectations. Whoops! I thought the general tone of my blog entry was, "Wow, fonts are hard, and at least on Very Smart Person is working on this problem at Sun, and if he's behind the other OS', it's because Sun hasn't given the problem proper priority and resources." I should have done a better job of getting that tone if you didn't pick it up.

Re: Vista vs. OS X. I haven't spent much time w/ Vista, but ClearType on XP is quite good, and many folks compared OS X against XP back in the day and came up preferring one over the other. I personally prefer evenly-spaced characters to clearer glyphs. Stories on this topic (http://www.codinghorror.com/blog/archives/000884.html) quickly descend into opinion wars. Let's not get too caught up here and just point out that both Vista and OS X are much better than Java2D.

Re: Custom glyph layout. The point I *tried* to make here is that I can *control* glyph layout relatively easily, so I could potentially do it better than Java2D does it by default. You state that I'm silly for thinking I can do a better job. Well, I followed up that assertion in my blog with "if it were easy, Phil would have already done it [because he's loads smarter than me]." I then point out that because I only have to worry about my app, and not the entire world's set of apps, perhaps I can do a better job because my problem is so much easier than theirs.

I thought that was enough hedging to avoid snarky comments like "How can you be smarter than them, wise-guy?" but perhaps I should have hedged / re-phrased a bit more.

In any event, given my preference for evenly spaced glyphs, and given how bad some of the spacing can get in Java2D, I think it's quite easy to make improvements in this area if all you care about is how Java2D renders a particular font at a particular size with a subset of characters. I've done it before.

Re: ligatures and kerning. Glad to hear these features are in there, if disabled by default. I'm pretty excited to take a look at see if they've been implemented with any level of quality. Thanks for the tip.

Re: layout. You say "layout... is definitely not the problem." You should take a look at the three large bitmaps with a bunch of other font samples. Layout IS a big problem for many font renderings at many sizes; I personally find the layout of Lucida Grande Bold I compared to OS X as unacceptable for "gorgeous" applications--which is the subject of this blog, not normal "business" apps.

jaredmac: Yeah, the folks stuck having to emulate the underlying OS with Swing--I pity them. That's a thankless task. Fortunately, WinXP emulate is possible, just tedious. I haven't looked into Vista; too bad that there's such an apparent disparity between how Java2D renders Segoe and how Vista does. :-(

mikael: Kirill composited SWT font rendering in Java2D? That's crazy! :-) Seriously, I'll have to look at that; it could be very cool, especially if you control when the text is composited in the drawing process and if you can apply effects to the text in some way.

Re: White on black. The app I'm working on is drawing text on dark backgrounds. Plus, it makes the bitmaps contrast against the white background of this page.

Although much improved, in my opinion Swing (and Gnome) still have a long way to go before they catch up to Micorosft and Apple. Here's my comparison of these four types of font rendering with 3 different fonts: http://markmclaren.com/blog/2007/06/14/swing-font-rendering-still-playing-catch-up/

I agree that font rendering is the weakest part of the otherwise excellent quality Java2D. Its gotten MUCH better in 6. I use Consolas in NetBeans for editing my code and it looks great. There's still room for improvement though, when you compare it to Windows. But I also dont like to complain, because I understand its such a hard problem to solve, and they're doing their best. Say what you will about Microsoft, but their font rendering truly is superb, especially on Vista, but then, they have an entire team of experts who work full time on it. So I think Java2D holds up pretty well considering that. I dont think its any worse than FreeType (though Id be interested to hear others opinion on this, who spend more time using Linux than I do).

I take issue with one thing you say though. You compain about glyph layout. I could not disagree with you more here. First you compare it to OSX, but I dont like their rendering at all. They preserve the metrics as it would appear on the page, but then you get fuzzy glyphs since they dont lie on pixel boundaries. Microsoft on the other hand, adjust the positions slightly, but so that they can be rendered sharply which makes a huge difference to readability, and allows Windows to have such clear text at very small sizes. But if you prefer Apple's way, you can always enable the fractional metrics rendering hint, that will preserve the laybut accuracy but expect the quality to be worse.

But you even say you could layout the glyphs yourself and do a better job than the Sun folks. You dont mean that do you? You must understand how complex that is, to be able to handle all of the worlds writing systems. There are very few people in the world capable of doing that properly. And its not the "Sun folks", Java2D uses the world class ICU font layout engine, the same engine used in OpenOffice.org and many other products, and generally does a far superior job than the Linux alternatives, Pango and the like.

You mention ligatures, but havent shown any examples. Java2D is perfectly capable of handing ligatures (and kerning) just fine in 6, doing it just as well as any other laybut engine, but I believe they're both off by default. You can certainly enable it using the appropriate TextAttribute in a TextLayout. I'm not sure if they're use during normal Swing rendering though, and if not, I dont know how to enable them gloablly. Would be handy to know though. Perhaps Phil can chime in on this.

So yeah, glph rasterization is generally very good with sub-pixel AA, but still not yet quite on par with ClearType (but thats a big ask). But layout, a seperate issue entirely, is definitely not the problem.

Btw, why did you do white on black when 99% of all text is black on white?

Evolution never stops. Vista is released...;)
http://www.pushing-pixels.org/?p=195

jbickers: What a very cool link! Thank you.

This chap's analysis is pretty interesting, especially with regard to comparing ClearType and Apple with a third party renderer, in this case Linux's Freetype.

http://antigrain.com/research/font_rasterization/index.html

It looks like it should be possible to do better than the native OS rendering, and get rendering that scales well.