[cairo] Sub-pixel Font Filtering in 1.10

Bill Spitzak spitzak at gmail.com
Fri Jan 15 15:44:59 PST 2010

It appears the complaint is really that hinted fonts produce "sharp" 
3-subpixel wide features, which the FIR filter then blurs. All the 
argument then is that such filtering must be disabled when hinting happens.

Notice that these are entirely my own ideas and proposals, I have not 
seen this anywhere else. Feel free to use them if they actually work and 
you can quote this email if they are really useful as prior art.


I think however an adaptive filter could be used. This is slow but would 
only be applied during rasterization, not when rendering the resulting 
glyphs. This is an inter-pixel filter. Notice that this is entirely my 
own idea and not based on any other papers or text I have seen:

3 equal horizontally adjacent sub-pixels will display correctly, so they 
could remain unchanged. However the overall image must not change total 
intensity, the distributed contribution of all pixels to the result must 
be (approximately) one.

Where A,B,C are three intensities, the pattern AABBBCC indicates that 
the BBB subpixels can be left unchanged. Produce a bitmask that is true 
for all such subpixels. Note that the intensities A,B,C may equal one 
another, and that the pixels CC and AA could themselves be part of 
another match.

Then filtering is applied. If the mask is true for a subpixel, it is 
copied unchanged to the output, as though it's filter is 0,0,1,0,0. If 
the mask is false for a row of 5 pixels then the normal FIR filter is 
used for the central filter, lets call this A,B,C,B,A. All other 
combinations are more complicated.

Since a masked subpixel contributed all it's value to itself, it must 
not contribute to other pixels. So if the FIR filter for another pixel 
includes one of these pixels, it must be modified to be zero at that 
point, with the missing factor added somewhere else. There are only a 
few possible bit arrangements that will be encountered due to 0's being 
in rows of at least 4 and 1's being in rows of at least 3. I also know 
that the two 0 pixels next to a 1 are equal to each other. This results 
in only 4 different filters:

     Mask    Filter for central pixel
     xx1xx   0,0,1,0,0
     00000   A,B,C,B,A
     000x1   A,B,C+A+B,0,0
     1x000   0,0,C+A+B,B,A


The eye is much more sensitive to the green pixel than the other colors, 
this is why the fringing often appears magenta: it actually is equally 
wrong in both green and magenta but your eye sees the green as the solid 
area and the magenta as the fringe.

The factor is more than 2x but I like the simplicity of this, also it 
seems that factors of 4 in dimensions are easier to handle than 3:

Render the pixel at 4x the horizontal sampling rate.

For each set of 4 samples ABCD that will map to an RGB result, calculate 
the RGB as this:

	R = 3A/4
	G = 3(B+C)/4
	B = 3D/4

Then do normal subpixel filtering or the above step to the result as above.

This may not work well with hinting as boundaries that land in the 
"middle" of the green subpixel are useless.

More information about the cairo mailing list