<p>Sean Barrett, the author of the stb libraries, <a href="http://nothings.org/gamedev/rasterize/" rel="noreferrer">wrote an article on how stb_truetype's rasterization works</a>. It's quite readable.</p>

<p>The article describes two methods of antialiasing, both based on scanline rasterization. In scanline rasterization, you iterate through the lines (rows) of pixels and keep track of which edges from the glyph outline are intersecting the scanline (considered as a mathematical zero-thickness line); then you can identify which pixel-centers are inside the outline by tracking enter/exit intersection points along that line.</p>

<p>You can do horizontal antialiasing by calculating partial pixel coverage, using the position of the intersection points relative to the pixel grid. For example, if you have an entering point at $x = 4.6$ on the current scanline, then pixel index 4 would be set to 60% empty and 40% covered. This sounds somewhat like what you tried to do. However, this doesn't help with vertical antialiasing since the scanline is still considered as a mathematical line with zero thickness. So, the article recommends to just supersample along the vertical axis: that is, process multiple "scanlines" spaced out vertically within each pixel row, and average the results together.</p>

<p>The second method performs both horizontal and vertical antialiasing at once, by evaluating the area of intersection of the glyph outline with each pixel square. It's still based on scanline rasterization, but now treats the scanline as a 1-pixel-tall rectangle and tracks all edges that touch the rectangle. To evaluate pixel coverage, the trapezoidal rule is used to calculate a signed area for each glyph edge—positive or negative depending on the edge's orientation—and these are summed up to give the total coverage area within the pixel square. (There are a lot more implementation details covered in the article, plus you can <a href="https://github.com/nothings/stb/blob/master/stb_truetype.h" rel="noreferrer">read the source</a>.) This is somewhat faster and more accurate than the supersampling method, though more difficult to implement.</p>

<p>Finally, it's important to consider whether you want gamma correction when rendering text (as with rendering anything else). Theoretically, the antialiased coverage values shouldn't be used directly as pixel values; they should be treated as an alpha, and used for linear-color-space blending between the background color and text color, followed by conversion to output gamma. However, in practice almost no one seems to do this; we're accustomed to seeing non-gamma-correct text, and screen fonts are designed to look good rendered this way. (Print fonts are another story.) On the other hand, if the text is animated, or rotated or not aligned with the pixel grid for any reason, gamma correction will help it look more consistent regardless of its placement relative to the pixel grid.</p>

<p>So, the choice of whether to apply gamma correction comes down to personal preference and the needs of the application. Either way, you may see artifacts such as the font appearing to get heavier or lighter depending on <a href="https://twitter.com/rygorous/status/512371399542202368" rel="noreferrer">color</a> and <a href="https://www.freetype.org/freetype2/docs/text-rendering-general.html#back-to-stem-darkening" rel="noreferrer">font size</a>.</p>

CC BY-SA 3.0
2016-08-01T03:38:26.250Z
This is great, thank you! I have looked at the source of stb_truetype, but my knowledge in computer graphics isn't thorough enough to really know what was happening on a theoretical level. I was not aware of the article he posted on it though, so that's a great help and will help clarify the process he uses, I'm sure. I'm glad to hear that maybe I was on the right track with the pixel coverage method, but I just wasn't taking into account the vertical part. :)
Chris
CC BY-SA 3.0
2017-11-30T06:21:48.943Z
I've just asked [Algorithms to “anti-alias” (or somehow improve) binary 1-bit drawings and fonts](https://computergraphics.stackexchange.com/q/5934/5846), any thoughts?
uhoh
CC BY-SA 3.0
2016-07-31T21:56:45.207Z
2016-07-31T23:13:44.507Z
2016-07-31T23:13:44.507Z
Nathan Reed
<p>This is how anti-aliasing works:</p>
<ol>
<li>render the outline in bilevel rendering at four times the size</li>
<li>take the averages of each 4×4 block</li>
<li>blend them with correct gamma between the foreground and background</li>
</ol>

CC BY-SA 4.0
2020-06-23T20:27:45.763Z
Welcome to CGSE. The question wasn't about how anti-aliasing works but which techniques are used/most suitable for font rendering.
wychmaster
CC BY-SA 4.0
2020-06-23T18:21:18.097Z
2020-06-23T18:21:18.097Z
user13594
<p>I'm writing my own TrueType font rasterizer as an exercise to improve my knowledge in computer graphics (along with a basic vector graphics engine). At this stage, I have implemented most of the TTF file parsing, decoding glyph outlines, scaling, and scan converting the outlines into a bitmap. 
(I'm not doing any font hinting/grid fitting for the time being).</p>

<p>When it comes to anti-aliasing the glyph bitmaps, what process or method is typically used (or best)? So far I have tried two methods. Bilinear filtering and setting the alpha value at the edges according to the pixel coverage of the outline. </p>

<p>Bilinear sampling is too blurry to be effective in font rendering, and using pixel coverage is not continuous enough. Here are some images as reference of a lowercase Arial 'c' being rendered at 24 points: </p>

<p>Raw bitmap with no anti-aliasing:</p>

<p><a href="https://i.sstatic.net/w7CQD.png" rel="noreferrer"><img src="https://i.sstatic.net/w7CQD.png" alt="Raw glyph with no anti-aliasing"></a></p>

<p><a href="https://i.sstatic.net/T6m7H.png" rel="noreferrer"><img src="https://i.sstatic.net/T6m7H.png" alt="enter image description here"></a></p>

<p>Bilinear filtering:</p>

<p><a href="https://i.sstatic.net/1EteV.png" rel="noreferrer"><img src="https://i.sstatic.net/1EteV.png" alt="Bilinear filtering"></a></p>

<p><a href="https://i.sstatic.net/7uACN.png" rel="noreferrer"><img src="https://i.sstatic.net/7uACN.png" alt="enter image description here"></a></p>

<p>Here is the same character rendered at the same size with a library (stb): </p>

<p><a href="https://i.sstatic.net/kgEYF.png" rel="noreferrer"><img src="https://i.sstatic.net/kgEYF.png" alt="enter image description here"></a></p>

<p><a href="https://i.sstatic.net/8tAM0.png" rel="noreferrer"><img src="https://i.sstatic.net/8tAM0.png" alt="enter image description here"></a></p>

<p>And finally, here it is rendered as it would appear on OS X (using CoreText I presume):</p>

<p><a href="https://i.sstatic.net/UOgSC.png" rel="noreferrer"><img src="https://i.sstatic.net/UOgSC.png" alt="enter image description here"></a></p>

<p><a href="https://i.sstatic.net/qs03k.png" rel="noreferrer"><img src="https://i.sstatic.net/qs03k.png" alt="enter image description here"></a></p>

<p>I'd be happy with whatever method is used by the stb library for my purposes.</p>

CC BY-SA 3.0
2016-07-30T21:48:56.747Z
The final image appears to be using subpixel rendering (note the coloured fringes to the left and right are different colours). Do you want to use this approach (which requires knowing the pixel geometry of the particular screen you are rendering to) or do you just want the best approach for pixel rendering, ignoring subpixels (which can be displayed on any screen)?
trichoplax is on Codidact now
CC BY-SA 3.0
2016-07-30T22:11:29.727Z
@trichoplax I think for right now I'd be happy with the best approach for pixel rendering, ignoring subpixels (which sounds more complicated). One step at a time. :)
Chris
CC BY-SA 3.0
2016-07-30T22:30:51.197Z
That sounds like a good approach - I just wanted to have it stated explicitly so answerers don't get distracted into explaining the last image.
trichoplax is on Codidact now
CC BY-SA 3.0
2016-07-30T22:39:33.053Z
Can you explain what you mean by bilinear filtering in this context? I don't understand how that concept applies to rasterizing the glyph shapes. Also, when you tried "setting the alpha value at the edges according to the pixel coverage of the outline", how did you accomplish that? Supersampled rasterization?
Nathan Reed
CC BY-SA 3.0
2016-07-31T00:07:49.193Z
@NathanReed Sure. For bilinear filtering, I sweep over the raw bitmap and for each pixel, look at the three pixels surrounding it (the one to the right, the one below, and the one diagonally down and to the right) and average them together to come up with the final intensity value. Pixels off the edge of the bitmap are treated as 0.
Chris
CC BY-SA 3.0
2016-07-31T00:12:09.983Z
@NathanReed For the pixel coverage, I use the intersection point and the pixel coordinate to determine how much of the pixel is "covered". i.e. Let's say we're at pixel position (4, 2). The intersection at this location with the curve or line is (4.6, 2.3). `xf = 4.6 - 4`, `yf = 2.3 - 2`, so pixel coverage is then: `coverage = (xf + yf) / 2.0;` This might be a naive approach, but it was worth a try. :)
Chris
CC BY-SA 3.0
2016-07-31T18:05:05.643Z
Every os has its own way of dealing with this. Windows uses hinting while OSX does not for example.
joojaa
CC BY-SA 3.0
2016-07-31T19:36:09.697Z
@joojaa Hinting has to do with adjusting the glyph outlines when scaled down to a small size to best maintain the font's characteristics while ensuring readability. Hinting doesn't have anything to do with anti-aliasing or font smoothing directly does it? Because that's handled during scan conversion.
Chris
<antialiasing><font-rendering>
What kind of anti-aliasing is used in font rasterization?
Chris
# What kind of anti-aliasing is used in font rasterization?

(Asked by: username_0 on 2016-07-30)

I'm writing my own TrueType font rasterizer as an exercise to improve my knowledge in computer graphics (along with a basic vector graphics engine). At this stage, I have implemented most of the TTF file parsing, decoding glyph outlines, scaling, and scan converting the outlines into a bitmap.
(I'm not doing any font hinting/grid fitting for the time being).

When it comes to anti-aliasing the glyph bitmaps, what process or method is typically used (or best)? So far I have tried two methods. Bilinear filtering and setting the alpha value at the edges according to the pixel coverage of the outline.

Bilinear sampling is too blurry to be effective in font rendering, and using pixel coverage is not continuous enough. Here are some images as reference of a lowercase Arial 'c' being rendered at 24 points:

Raw bitmap with no anti-aliasing:

[![Raw glyph with no anti-aliasing](https://i.sstatic.net/w7CQD.png)](https://i.sstatic.net/w7CQD.png)

[![enter image description here](https://i.sstatic.net/T6m7H.png)](https://i.sstatic.net/T6m7H.png)

Bilinear filtering:

[![Bilinear filtering](https://i.sstatic.net/1EteV.png)](https://i.sstatic.net/1EteV.png)

[![enter image description here](https://i.sstatic.net/7uACN.png)](https://i.sstatic.net/7uACN.png)

Here is the same character rendered at the same size with a library (stb):

[![enter image description here](https://i.sstatic.net/kgEYF.png)](https://i.sstatic.net/kgEYF.png)

[![enter image description here](https://i.sstatic.net/8tAM0.png)](https://i.sstatic.net/8tAM0.png)

And finally, here it is rendered as it would appear on OS X (using CoreText I presume):

[![enter image description here](https://i.sstatic.net/UOgSC.png)](https://i.sstatic.net/UOgSC.png)

[![enter image description here](https://i.sstatic.net/qs03k.png)](https://i.sstatic.net/qs03k.png)

I'd be happy with whatever method is used by the stb library for my purposes.

**Tags:** antialiasing, font-rendering

> **Comments:**
> **username_1**: The final image appears to be using subpixel rendering (note the coloured fringes to the left and right are different colours). Do you want to use this approach (which requires knowing the pixel geometry of the particular screen you are rendering to) or do you just want the best approach for pixel rendering, ignoring subpixels (which can be displayed on any screen)?  
> **username_0**: @username_1 I think for right now I'd be happy with the best approach for pixel rendering, ignoring subpixels (which sounds more complicated). One step at a time. :)  
> **username_1**: That sounds like a good approach - I just wanted to have it stated explicitly so answerers don't get distracted into explaining the last image.  
> **username_2**: Can you explain what you mean by bilinear filtering in this context? I don't understand how that concept applies to rasterizing the glyph shapes. Also, when you tried "setting the alpha value at the edges according to the pixel coverage of the outline", how did you accomplish that? Supersampled rasterization?  
> **username_0**: @username_2 Sure. For bilinear filtering, I sweep over the raw bitmap and for each pixel, look at the three pixels surrounding it (the one to the right, the one below, and the one diagonally down and to the right) and average them together to come up with the final intensity value. Pixels off the edge of the bitmap are treated as 0.  
> **username_0**: @username_2 For the pixel coverage, I use the intersection point and the pixel coordinate to determine how much of the pixel is "covered". i.e. Let's say we're at pixel position (4, 2). The intersection at this location with the curve or line is (4.6, 2.3). `xf = 4.6 - 4`, `yf = 2.3 - 2`, so pixel coverage is then: `coverage = (xf + yf) / 2.0;` This might be a naive approach, but it was worth a try. :)  
> **username_3**: Every os has its own way of dealing with this. Windows uses hinting while OSX does not for example.  
> **username_0**: @username_3 Hinting has to do with adjusting the glyph outlines when scaled down to a small size to best maintain the font's characteristics while ensuring readability. Hinting doesn't have anything to do with anti-aliasing or font smoothing directly does it? Because that's handled during scan conversion.  

---

## 2 answers

### Answer by username_2 on 2016-07-31. Score: 8 | Accepted answer

Sean Barrett, the author of the stb libraries, [wrote an article on how stb\_truetype's rasterization works](http://nothings.org/gamedev/rasterize/). It's quite readable.

The article describes two methods of antialiasing, both based on scanline rasterization. In scanline rasterization, you iterate through the lines (rows) of pixels and keep track of which edges from the glyph outline are intersecting the scanline (considered as a mathematical zero-thickness line); then you can identify which pixel-centers are inside the outline by tracking enter/exit intersection points along that line.

You can do horizontal antialiasing by calculating partial pixel coverage, using the position of the intersection points relative to the pixel grid. For example, if you have an entering point at $x = 4.6$ on the current scanline, then pixel index 4 would be set to 60% empty and 40% covered. This sounds somewhat like what you tried to do. However, this doesn't help with vertical antialiasing since the scanline is still considered as a mathematical line with zero thickness. So, the article recommends to just supersample along the vertical axis: that is, process multiple "scanlines" spaced out vertically within each pixel row, and average the results together.

The second method performs both horizontal and vertical antialiasing at once, by evaluating the area of intersection of the glyph outline with each pixel square. It's still based on scanline rasterization, but now treats the scanline as a 1-pixel-tall rectangle and tracks all edges that touch the rectangle. To evaluate pixel coverage, the trapezoidal rule is used to calculate a signed area for each glyph edge—positive or negative depending on the edge's orientation—and these are summed up to give the total coverage area within the pixel square. (There are a lot more implementation details covered in the article, plus you can [read the source](https://github.com/nothings/stb/blob/master/stb_truetype.h).) This is somewhat faster and more accurate than the supersampling method, though more difficult to implement.

Finally, it's important to consider whether you want gamma correction when rendering text (as with rendering anything else). Theoretically, the antialiased coverage values shouldn't be used directly as pixel values; they should be treated as an alpha, and used for linear-color-space blending between the background color and text color, followed by conversion to output gamma. However, in practice almost no one seems to do this; we're accustomed to seeing non-gamma-correct text, and screen fonts are designed to look good rendered this way. (Print fonts are another story.) On the other hand, if the text is animated, or rotated or not aligned with the pixel grid for any reason, gamma correction will help it look more consistent regardless of its placement relative to the pixel grid.

So, the choice of whether to apply gamma correction comes down to personal preference and the needs of the application. Either way, you may see artifacts such as the font appearing to get heavier or lighter depending on [color](https://twitter.com/rygorous/status/512371399542202368) and [font size](https://www.freetype.org/freetype2/docs/text-rendering-general.html#back-to-stem-darkening).

> **Comments:**
> **username_0**: This is great, thank you! I have looked at the source of stb_truetype, but my knowledge in computer graphics isn't thorough enough to really know what was happening on a theoretical level. I was not aware of the article he posted on it though, so that's a great help and will help clarify the process he uses, I'm sure. I'm glad to hear that maybe I was on the right track with the pixel coverage method, but I just wasn't taking into account the vertical part. :)  
> **username_4**: I've just asked [Algorithms to “anti-alias” (or somehow improve) binary 1-bit drawings and fonts](https://computergraphics.stackexchange.com/q/5934/5846), any thoughts?  

---

### Answer by username_5 on 2020-06-23. Score: -1

This is how anti-aliasing works:

1. render the outline in bilevel rendering at four times the size
2. take the averages of each 4×4 block
3. blend them with correct gamma between the foreground and background

> **Comments:**
> **username_6**: Welcome to CGSE. The question wasn't about how anti-aliasing works but which techniques are used/most suitable for font rendering.  

---

