[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.
ADAPTIVE FILTER PROPOSAL:
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
4X SAMPLING:
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