This article covers the use of the RGB subpixel antialiasing technique used in various software packages including Adobe Reader, Mac OS X's Quartz font rasterizer, XRender, Microsoft ClearType, applied to the improvement of quality of non-text images. It includes a testbed and some sample code in C and PHP.
Regardless of who invented the principles of "RGB subpixel sampling" or whatever you want to call it, I find it an excellent way to improve font clarity on my iBook. In fact, I can instantly tell when an application isn't using it.
My browser of choice, Camino, has a small bug whereby the font smoother sometimes switches back to greyscale mode. The worst part is that it doesn't always happen across the whole window, but when a rectangle is redrawn (eg. while scrolling). I think it mainly occurs when there's DHTML magic going on, and I suspect I know why: when the text is part of a layer that may be composited on top of other content, the RGB font smoother is not really able to be used, unless the entire layer stack is prebuffered. This is due to the lack of sensible subpixel transparency when compositing. [Update: Pierre Igot describes a similar problem with Apple's Pages, and Michael Fortin explains why, and it turns out I was probably right.]
Anyway, I digress. I far prefer subpixel antialiased fonts, but there's no mainstream package I know of that will apply the same technique to images. Neither Mac OS X or Windows apply the technique to their vector graphics APIs; Photoshop and Illustrator don't support it; Adobe (Acrobat) Reader seems to support it to a degree, but not in a useful way; and I found various other packages that aren't particularly clear whether they support it or not, including Cairo and Libart.
The algorithm itself is fairly straightforward. Since writing the code I describe below, I've found the following pages that describe it very well, so I won't bother doing it again:
Neither offer sample code, though.
There are two main problems with this technique, though: lossy compression, and transparency.
Lossy compression breaks any results, leaving us with large images when JPEG would be more appropriate. Since the antialiasing manifests as a colour fringe, the lossy JPEG algorithm munges the detail completely. Worst still, the "extra" colour in the image can "stain" the normal JPEG artifacts.
As far as transparency is concerned, there is no good algorithm: using normal single-channel alpha, the colour fringe is inappropriate on an arbitrary background. When programming the sample code, I just could not find a good way of handling it.
The problem lies in composition: a single alpha channel for transparency is not enough to composite the separate subpixels, and the color fringing is assumed to be on a given colour background (usually white). If the image is only to be used on, say, a light grey background then it's passable, but still not "correct". This is particularly hard to deal with when a transparency is necessary, for example on a gradient background.
On the last major project I worked on (Lonres.com), I applied the technique to the site's icons to give them a much clearer appearance. It helped a great deal towards making the site's tiny icons legible (at least for LCD users!) Images are also improved, in my opinion, although there's a downside: JPEGging the image will remove the benefits, so the photos must stay losslessly compressed (PNG or GIF). Still, small thumbnail photos can be improved a great deal using this technique.
To see the results, I've put together a testbed page. On showing this to the collective masses of Underscore, I got a range of different responses, varying from praise to disgust, so it's definitely a subjective thing. Anyway, the code I wrote for that project is available via Subversion. It compiles for me on my Mac OS X 10.4.6 installation with a recent copy of ImageMagick. The most likely cause of failure is lack of a new enough version: it must support the new MagickWand API. If that's not enough, please don't ask me for help compiling it... this is programmer-level stuff, so don't expect for it to work unless you've got experience in compiling UNIX software.
UPDATE, April 2007: I've added a PHP port of the code which uses GD directly, rather than ImageMagick. It's relatively slow, but useful for generating graphics for title image replacement. I've used it on GoDaddy's economy account, and also on Dreamhost.
For this project, I'm pretty relaxed about the licencing. For kicks, I've put it under the Apache License 2.0. Use it for whatever you want, and don't blame me if it goes wrong. I would, however, ask you to let me know if you make any improvements to it, and let me have a copy of the changes if possible.
I am an LCD filtering maniac as well. And so I find this completely awesome.
What do the options of lcdresample mean, though? -b does nothing and -n is used in the code for mode 0 but is not in the usage string.
On the whole, I love the results! I found one other script that used Gimp, but gimp has horrible resampling and the filtering was naive.
In your code vertical lines are fine. I think that in y-direction there could be a bit more antialias:
http://www.alice-dsl.net/~towolf/img/lcdresample.png
[ Imagemagick Mitchell filter for comparison:
http://www.alice-dsl.net/~towolf/img/Mitchell.png ]
Also I don’t understand the code properly. How does this relate to the 5-tap FIR filter that Freetype uses?
http://git.savannah.gnu.org/cgit/freetype/freetype2.git/tree/src/base/ftlcdfil.c
Are you using the same mechanisms? Can I convert the weights that FreeType uses (light_filter and default_filter) to the weights you include?
I find FreeType more smooth in both x and y. Changing the strength -s does not make it much more smooth in the sense that lines become not only sharper (they do!) but also less jaggy.
compare with this image: http://www.alice-dsl.net/~towolf/cairo/displaytext-fir5.png
But your tool is already very useful. Did you submit this upstream? To Imagemagick of to Cairo? I would love to see Cairo support this in it’s renderer.
Hi!
I just reinvented this... in ImageMagick, using only already defined operations.
If you want the command to do it, check my forum post:
http://www.imagemagick.org/discourse-server/viewtopic.php?f=22&t=19120
The thing is, it's very easy to do already. No need for any new algorithm, just use normal image operations like resampling and matrices.
I'm sure this can be done in OpenGL or DirectX rather quickly.
Rodrigo: well done! That's an excellent approach!