This patch modifies freetype to look for a “FT_FITLER_PARAMS” environment variable, and then dynamically generate a FIR filter matrix from those parameters.
Patch file here. It applies against freetype 2.3.7 from the ubuntu repository (though it should apply just fine to upstream 2.3.7. FT_FITLER_PARAMS should have two floating point numbers separated by a space. Each number should be between 0.0 and 1.0. Internally, the default filter used has the weights [ 0x10, 0x40, 0x70, 0x40, 0x10 ]. You can imagine a filter as being a 5×1 matrix, each cell containing a “weight” for which all add up to a normalized value (in this case 255).
Instead of dealing with byte values, my patch accepts float values. So instead of thinking about how to distribute 255 across five slots, you think about how to distribute a total of 1.0 across five slots. Along this line of thinking, the first value in FT_FILTER_PARAMS is the value of the “peak” slot. You can think of the filters as having only three meaningful positions [edge, mid, peak, mid, edge]. So the first value specifies the peak, and the second value specifies the fraction of the remaining weight that is given to the “mid” slot vs. the “edge” slot.
In practice, I find that for the two screens that I have, a value of FT_FILTER_PARAMS=”0.39 0.61″ works pretty well. That results in the matrix [30, 47, 99, 47 33] If you look at Windows and its “ClearType Tuner” tool, it only has one value to configure. I’m not really even sure what that value controls, but you could imagine in the freetype scheme being able to generate the entire filter matrix based on one parameter, if you could characterize the optimal relationship between the peak, mid, and edge values. Unfortunately, I’m not signal theorist, so I have to do it experimentally. And the above values are what look best to my eyes so far.
Interestingly, the more that you raise the “peak” value, the thinner the letter forms become. The more that you raise the second parameter (i.e., you give more weight to the “mid” slots over the “edge” slots) the more contrast you get, but the more you’re likely to introduce fringing. You can do quite a bit of experimenting if you relaunch a small program like leafpad over and over again with different values.
Ideally, these values you could set per-font through fontconfig. But that’s a lot more code that I don’t have time to write. Also, in the end, I still prefer both OSX and Vista font rendering over whatever I can achieve with this patch. Perhaps I just haven’t found the right matrix yet, but I also think it has to do with the lack of gamma-correct blending when rendering the text. A comment in the original code notes that the values in the original matrix actually add up to more than 255, providing a sort of cheap gamma correction. From my limited understanding of gamma correction, however, this seems like the wrong place to embed such an adjustment.
And finally here’s a 32bit Ubuntu package that you can install onto an Ubuntu system to get the patched freetype library. As usual, no guarantees, and don’t come running to me if this makes your computer explode due to its awesomeness.
BTW, writing a patch like this makes me never want to write something similar again. I put a fair amount of time into this, and all I got was a hacky solution. The real integrated way of doing this spans many projects: cairo, xft, freetype, fontconfig. They are all essential to the desktop experience, and yet they are maintained by different peopled with different interests, which means probably multiple battles with different upstreams and multiple headaches. I saw how much trouble David Turner had getting his subpixel support into all the various pieces, and I don’t wish to go through the same exercise. Hacking on code in your spare time is fun. Fighting the fight with the upstream projects doesn’t sound like fun. I suppose you could pay me to do it, but it would have to be a non-trivial amount. Yay open source.

1 Comment

Leave a comment

Your email address will not be published. Required fields are marked *