Not taking the hintNot taking the hint

The best thing about making applications—instead of just application libraries—is that you find out how well your ideas really work. Some ideas that are beautiful in words, in diagrams, and even in code, don’t live up to expectations when they begin serving Web requests.

Take my precious RenderedLabel. I love the idea of it, and in my tests of its first incarnation (the graffiti example, mostly) it worked without a hitch. Later, adding it to the recipe book, I realized it needed to support static URLs so I added that. Then there’s the subtle case where the rendered image is requested before any page containing it has been been requested (after a server bounce), which we solve in Databinder 1.1’s examples by loading the images in the application’s init(). Slightly less fun, but it’s pretty bomb-proof.

The latest unexpected problem with RenderedLabel wasn’t put to bed so easily, and in some sense makes it useless. I’ve discovered in deployment that many fonts I want to use with RenderedLabel render poorly on a Linux server. (I’d done all the development on a Mac.) The whole point is to have nice, reliable font rendering. Oops.

The text rendering path in Java is anything but obvious. One thing I’d deduced (and the reason I was blind-sided) was that Java doesn’t just pass the work on to the underlying OS. If that were true, Java 6 wouldn’t have to try so hard to match native rendering (and still come up short). So why the difference between Mac and Linux? Oh, right. The Mac JVM is made by Apple, for better and for worse, and it—apparently—does render natively. Or something like natively.

I installed a backported Java 6 to Ubuntu Edgy, hoping that its updated rendering (now supporting subpixel LCD stuff, which is useless for my purposes) had caught up with Ubuntu’s at least. The typeface I’m concerned with at the moment, Bank Gothic, looks good enough in Ubuntu (using autohinter), but pretty dumb in Java 5. It looks exactly as dumb, I soon learned, in Java 6.

The problem is hinting, the attempt to improve upon low-resolution type appearance by overriding a purely mathematical rendering of its vectors. Adobe invented this technique for Type 1, Apple reinvented it for TrueType, Microsoft licensed it for Window 3.1, and it still influences many people’s opinion of when screen fonts look “right” (those prone to calling less-hinted renderings smudged). Java, chasing this unmoving target from 1991, has never quite caught it.

At this point Java may as well give up. Seriously. As pixel densities increase, the best rendering is converging with, finally, an unbiased rendering of the glyph. And with larger headlines, we’re already there. (If you need to beef up the strokes on a character that’s twenty pixels high, you’ve got other problems.) So! What we really want for RenderedLabel, always intended for headlines, is to disable that horrible hinter.

I’ve found one convoluted way to do it: using Batik. Yes, the SVG toolkit. I’ve been thinking about using it for a while since it supports manual kerning, as some day Databinder would like to. For now, I’m using it only to make an end-run around Java’s crappy hinter. Using Batik (somehow) results in exactly the same output on Mac OS X and Ubuntu, and it’s loads better than the crazy stems of different sizes I was getting before. See for yourself.

How it works
Standard Java

How it works
Batik

The Batik-dependent code lives in a new databinder-draw subproject, which is not going in as a regular module yet because it depends on a Batik snapshot. (The relevant API has changed from Batik’s current version, and I only want to write this once, etc.) If you want to use it you need to get both Databinder and Batik via Subversion, compile Batik and install it into Maven, and compile and install databinder-draw. Obviously no one is going to do all that, but if you’re curious about the Batik rigging you can peep it in BatikRenderedLabel.

And yes, the weblog software is coming along just fine thank you.

Add a comment