Change default LCD filter to be normalized and color-balanced.
Update documentation. * src/base/ftlcdfil.c (FT_Library_SetLcdFilter): Update `default_filter'.
This commit is contained in:
parent
98afe3f5c8
commit
01ce1c6a99
@ -1,3 +1,10 @@
|
||||
2015-11-28 Nikolaus Waxweiler <madigens@gmail.com>
|
||||
|
||||
Change default LCD filter to be normalized and color-balanced.
|
||||
|
||||
* src/base/ftlcdfil.c (FT_Library_SetLcdFilter): Update
|
||||
`default_filter'.
|
||||
|
||||
2015-11-28 Werner Lemberg <wl@gnu.org>
|
||||
|
||||
[docmaker] Allow references to section names.
|
||||
|
@ -2828,9 +2828,14 @@ FT_BEGIN_HEADER
|
||||
* @FT_LOAD_TARGET_MONO instead.
|
||||
*
|
||||
* FT_LOAD_TARGET_LIGHT ::
|
||||
* A lighter hinting algorithm for non-monochrome modes. Many
|
||||
* generated glyphs are more fuzzy but better resemble its original
|
||||
* shape. A bit like rendering on Mac OS~X.
|
||||
* A lighter hinting algorithm for gray-level modes. Many generated
|
||||
* glyphs are fuzzier but better resemble their original shape. This
|
||||
* is achieved by snapping glyphs to the pixel grid only vertically
|
||||
* (Y-axis), as is done by Microsoft's ClearType and Adobe's
|
||||
* proprietary font renderer. This preserves inter-glyph spacing in
|
||||
* horizontal text. The snapping is done either by the native font
|
||||
* driver if the driver itself and the font support it or by the
|
||||
* auto-hinter.
|
||||
*
|
||||
* FT_LOAD_TARGET_MONO ::
|
||||
* Strong hinting algorithm that should only be used for monochrome
|
||||
@ -2937,7 +2942,10 @@ FT_BEGIN_HEADER
|
||||
/* field in the @FT_GlyphSlotRec structure gives the format of the */
|
||||
/* returned bitmap. */
|
||||
/* */
|
||||
/* All modes except @FT_RENDER_MODE_MONO use 256 levels of opacity. */
|
||||
/* All modes except @FT_RENDER_MODE_MONO use 256 levels of opacity, */
|
||||
/* indicating pixel coverage. Use linear alpha blending and gamma */
|
||||
/* correction to correctly render non-monochrome glyph bitmaps onto a */
|
||||
/* surface; see @FT_Render_Glyph. */
|
||||
/* */
|
||||
/* <Values> */
|
||||
/* FT_RENDER_MODE_NORMAL :: */
|
||||
@ -3007,6 +3015,82 @@ FT_BEGIN_HEADER
|
||||
/* the glyph image format, finding the relevant renderer, and */
|
||||
/* invoking it. */
|
||||
/* */
|
||||
/* When FreeType outputs a bitmap of a glyph, it really outputs an */
|
||||
/* alpha coverage map. If a pixel is completely covered by a */
|
||||
/* filled-in outline, the bitmap contains 0xFF at that pixel, meaning */
|
||||
/* that 0xFF/0xFF fraction of that pixel is covered, meaning the */
|
||||
/* pixel is 100% black (or 0% bright). If a pixel is only 50% */
|
||||
/* covered (value 0x80), the pixel is made 50% black (50% bright or a */
|
||||
/* middle shade of grey). 0% covered means 0% black (100% bright or */
|
||||
/* white). */
|
||||
/* */
|
||||
/* On high-DPI screens like on smartphones and tablets, the pixels */
|
||||
/* are so small that their chance of being completely covered and */
|
||||
/* therefore completely black are fairly good. On the low-DPI */
|
||||
/* screens, however, the situation is different. The pixels are too */
|
||||
/* large for most of the details of a glyph and shades of gray are */
|
||||
/* the norm rather than the exception. */
|
||||
/* */
|
||||
/* This is relevant because all our screens have a second problem: */
|
||||
/* they are not linear. 1~+~1 is not~2. Twice the value does not */
|
||||
/* result in twice the brightness. When a pixel is only 50% covered, */
|
||||
/* the coverage map says 50% black, and this translates to a pixel */
|
||||
/* value of 128 when you use 8~bits per channel (0-255). However, */
|
||||
/* this does not translate to 50% brightness for that pixel on our */
|
||||
/* sRGB and gamma~2.2 screens. Due to their non-linearity, they */
|
||||
/* dwell longer in the darks and only a pixel value of about 186 */
|
||||
/* results in 50% brightness – 128 ends up too dark on both bright */
|
||||
/* and dark backgrounds. The net result is that dark text looks */
|
||||
/* burnt-out, pixely and blotchy on bright background, bright text */
|
||||
/* too frail on dark backgrounds, and colored text on colored */
|
||||
/* background (for example, red on green) seems to have dark halos or */
|
||||
/* `dirt' around it. The situation is especially ugly for diagonal */
|
||||
/* stems like in `w' glyph shapes where the quality of FreeType's */
|
||||
/* anti-aliasing depends on the correct display of grays. On */
|
||||
/* high-DPI screens where smaller, fully black pixels reign supreme, */
|
||||
/* this doesn't matter, but on our low-DPI screens with all the gray */
|
||||
/* shades, it does. 0% and 100% brightness are the same things in */
|
||||
/* linear and non-linear space, just all the shades in-between */
|
||||
/* aren't. */
|
||||
/* */
|
||||
/* The blending function for placing text over a background is */
|
||||
/* */
|
||||
/* { */
|
||||
/* dst = alpha * src + (1 - alpha) * dst , */
|
||||
/* } */
|
||||
/* */
|
||||
/* which is known as the OVER operator. */
|
||||
/* */
|
||||
/* To correctly composite an antialiased pixel of a glyph onto a */
|
||||
/* surface, */
|
||||
/* */
|
||||
/* 1. take the foreground and background colors (e.g., in sRGB space) */
|
||||
/* and apply gamma to get them in a linear space, */
|
||||
/* */
|
||||
/* 2. use OVER to blend the two linear colors using the glyph pixel */
|
||||
/* as the alpha value (remember, the glyph bitmap is a coverage */
|
||||
/* bitmap), and */
|
||||
/* */
|
||||
/* 3. apply inverse gamma to the blended pixel and write it back to */
|
||||
/* the image. */
|
||||
/* */
|
||||
/* Internal testing at Adobe found that a target inverse gamma of~1.8 */
|
||||
/* for step~3 gives good results across a wide range of displays with */
|
||||
/* an sRGB gamma curve or a similar one. */
|
||||
/* */
|
||||
/* This process can cost performance. There is an approximation that */
|
||||
/* does not need to know about the background color; see */
|
||||
/* https://bel.fi/alankila/lcd/ and */
|
||||
/* https://bel.fi/alankila/lcd/alpcor.html for details. */
|
||||
/* */
|
||||
/* *ATTENTION*: Linear blending is even more important when dealing */
|
||||
/* with subpixel-rendered glyphs to prevent color-fringing! A */
|
||||
/* subpixel-rendered glyph must first be filtered with a filter that */
|
||||
/* gives equal weight to the three color primaries and does not */
|
||||
/* exceed a sum of 0x100, see section @lcd_filtering. Then the */
|
||||
/* only difference to gray linear blending is that subpixel-rendered */
|
||||
/* linear blending is done 3~times per pixel. */
|
||||
/* */
|
||||
/* <InOut> */
|
||||
/* slot :: A handle to the glyph slot containing the image to */
|
||||
/* convert. */
|
||||
|
@ -445,13 +445,26 @@ FT_BEGIN_HEADER
|
||||
* no-stem-darkening[autofit]
|
||||
*
|
||||
* @description:
|
||||
* *Experimental* *only*
|
||||
* *Experimental* *only,* *requires* *linear* *alpha* *blending* *and*
|
||||
* *gamma* *correction*
|
||||
*
|
||||
* The main purpose of emboldening glyphs or `stem darkening' is to
|
||||
* enhance readability at smaller sizes. The smaller the size, the more
|
||||
* emboldening is applied to keep glyphs from `thinning out'. All
|
||||
* glyphs that pass through the autohinter will be emboldened unless
|
||||
* this property is set to TRUE.
|
||||
* Stem darkening emboldens glyphs at smaller sizes to make them more
|
||||
* readable on common low-DPI screens when using linear alpha blending
|
||||
* and gamma correction, see @FT_Render_Glyph. When not using linear
|
||||
* alpha blending and gamma correction, glyphs will appear heavy and
|
||||
* fuzzy!
|
||||
*
|
||||
* Gamma correction essentially lightens fonts since shades of grey are
|
||||
* shifted to higher pixel values (=~higher brightness) to match the
|
||||
* original intention to the reality of our screens. The side-effect is
|
||||
* that glyphs `thin out'. Mac OS~X and Adobe's proprietary font
|
||||
* rendering library implement a counter-measure: stem darkening at
|
||||
* smaller sizes where shades of gray dominate. By emboldening a glyph
|
||||
* slightly in relation to its pixel size, individual pixels get higher
|
||||
* coverage of filled-in outlines and are therefore `blacker'. This
|
||||
* counteracts the `thinning out' of glyphs, making text remain readable
|
||||
* at smaller sizes. All glyphs that pass through the auto-hinter will
|
||||
* be emboldened unless this property is set to TRUE.
|
||||
*
|
||||
* See the description of the CFF driver for algorithmic details. Total
|
||||
* consistency with the CFF driver is currently not achieved because the
|
||||
@ -460,18 +473,6 @@ FT_BEGIN_HEADER
|
||||
* The smaller the size (especially 9ppem and down), the higher the loss
|
||||
* of emboldening versus the CFF driver.
|
||||
*
|
||||
* *ATTENTION*: This feature has been developed with linear alpha
|
||||
* blending and gamma correction of glyphs in mind: A rendering library
|
||||
* must apply linear alpha blending while compositing glyph bitmaps onto
|
||||
* a surface and then apply gamma correction to the glyph pixels to get
|
||||
* from linear space to display space (unless the display works in
|
||||
* linear space). Internal testing at Adobe found that a gamma
|
||||
* correction value of 1.8 gives good results across a wide range of
|
||||
* displays with a sRGB gamma curve or a similar one.
|
||||
*
|
||||
* If this is not possible, it might be better to disable stem
|
||||
* darkening. Currently, this can only be done globally.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
|
@ -41,56 +41,76 @@ FT_BEGIN_HEADER
|
||||
* LCD Filtering
|
||||
*
|
||||
* @abstract:
|
||||
* Reduce color fringes of LCD-optimized bitmaps.
|
||||
* Reduce color fringes of subpixel-rendered bitmaps.
|
||||
*
|
||||
* @description:
|
||||
* The @FT_Library_SetLcdFilter API can be used to specify a low-pass
|
||||
* filter, which is then applied to LCD-optimized bitmaps generated
|
||||
* through @FT_Render_Glyph. This is useful to reduce color fringes
|
||||
* that would occur with unfiltered rendering.
|
||||
* Subpixel rendering exploits the color-striped structure of LCD
|
||||
* pixels, increasing the available resolution in the direction of the
|
||||
* stripe (usually horizontal RGB) by a factor of~3. Since these
|
||||
* subpixels are color pixels, using them unfiltered creates severe
|
||||
* color fringes. Use the @FT_Library_SetLcdFilter API to specify a
|
||||
* low-pass filter, which is then applied to subpixel-rendered bitmaps
|
||||
* generated through @FT_Render_Glyph.
|
||||
*
|
||||
* Note that no filter is active by default, and that this function is
|
||||
* *not* implemented in default builds of the library. You need to
|
||||
* #define FT_CONFIG_OPTION_SUBPIXEL_RENDERING in your `ftoption.h' file
|
||||
* in order to activate it.
|
||||
*
|
||||
* FreeType generates alpha coverage maps, which are linear by nature.
|
||||
* For instance, the value 0x80 in bitmap representation means that
|
||||
* (within numerical precision) 0x80/0xFF fraction of that pixel is
|
||||
* covered by the glyph's outline. The blending function for placing
|
||||
* text over a background is
|
||||
* A filter should have two properties:
|
||||
*
|
||||
* {
|
||||
* dst = alpha * src + (1 - alpha) * dst ,
|
||||
* }
|
||||
* 1) It should be normalized, meaning the sum of the 5~components
|
||||
* should be 256 (0x100). It is possible to go above or under this
|
||||
* target sum, however: going under means tossing out contrast, going
|
||||
* over means invoking clamping and thereby non-linearities that
|
||||
* increase contrast somewhat at the expense of greater distortion
|
||||
* and color-fringing. Contrast is better enhanced through stem
|
||||
* darkening.
|
||||
*
|
||||
* which is known as OVER. However, when calculating the output of the
|
||||
* OVER operator, the source colors should first be transformed to a
|
||||
* linear color space, then alpha blended in that space, and transformed
|
||||
* back to the output color space.
|
||||
* 2) It should be color-balanced, meaning a filter `{~a, b, c, b, a~}'
|
||||
* where a~+ b~=~c. It distributes the computed coverage for one
|
||||
* subpixel to all subpixels equally, sacrificing some won resolution
|
||||
* but drastically reducing color-fringing. Positioning improvements
|
||||
* remain! Note that color-fringing can only really be minimized
|
||||
* when using a color-balanced filter and alpha-blending the glyph
|
||||
* onto a surface in linear space; see @FT_Render_Glyph.
|
||||
*
|
||||
* When linear light blending is used, the default FIR5 filtering
|
||||
* weights (as given by FT_LCD_FILTER_DEFAULT) are no longer optimal, as
|
||||
* they have been designed for black on white rendering while lacking
|
||||
* gamma correction. To preserve color neutrality, weights for a FIR5
|
||||
* filter should be chosen according to two free parameters `a' and `c',
|
||||
* and the FIR weights should be
|
||||
* Regarding the form, a filter can be a `boxy' filter or a `beveled'
|
||||
* filter. Boxy filters are sharper but are less forgiving of non-ideal
|
||||
* gamma curves of a screen (viewing angles!), beveled filters are
|
||||
* fuzzier but more tolerant.
|
||||
*
|
||||
* {
|
||||
* [a - c, a + c, 2 * a, a + c, a - c] .
|
||||
* }
|
||||
* Examples:
|
||||
*
|
||||
* This formula generates equal weights for all the color primaries
|
||||
* across the filter kernel, which makes it colorless. One suggested
|
||||
* set of weights is
|
||||
* - [0x10 0x40 0x70 0x40 0x10] is beveled and neither balanced nor
|
||||
* normalized.
|
||||
*
|
||||
* {
|
||||
* [0x10, 0x50, 0x60, 0x50, 0x10] ,
|
||||
* }
|
||||
* - [0x1A 0x33 0x4D 0x33 0x1A] is beveled and balanced but not
|
||||
* normalized.
|
||||
*
|
||||
* where `a' has value 0x30 and `c' value 0x20. The weights in filter
|
||||
* may have a sum larger than 0x100, which increases coloration slightly
|
||||
* but also improves contrast.
|
||||
* - [0x19 0x33 0x66 0x4c 0x19] is beveled and normalized but not
|
||||
* balanced.
|
||||
*
|
||||
* - [0x00 0x4c 0x66 0x4c 0x00] is boxily beveled and normalized but not
|
||||
* balanced.
|
||||
*
|
||||
* - [0x00 0x55 0x56 0x55 0x00] is boxy, normalized, and almost
|
||||
* balanced.
|
||||
*
|
||||
* - [0x08 0x4D 0x56 0x4D 0x08] is beveled, normalized and, almost
|
||||
* balanced.
|
||||
*
|
||||
* It is important to understand that linear alpha blending and gamma
|
||||
* correction is critical for correctly rendering glyphs onto surfaces
|
||||
* without artifacts and even more critical when subpixel rendering is
|
||||
* involved.
|
||||
*
|
||||
* Each of the 3~alpha values (subpixels) is independently used to blend
|
||||
* one color channel. That is, red alpha blends the red channel of the
|
||||
* text color with the red channel of the background pixel. The
|
||||
* distribution of density values by the color-balanced filter assumes
|
||||
* alpha blending is done in linear space; only then color artifacts
|
||||
* cancel out.
|
||||
*/
|
||||
|
||||
|
||||
@ -111,10 +131,21 @@ FT_BEGIN_HEADER
|
||||
* The default filter reduces color fringes considerably, at the cost
|
||||
* of a slight blurriness in the output.
|
||||
*
|
||||
* It is a beveled, normalized, and color-balanced five-tap filter
|
||||
* that is more forgiving to screens with non-ideal gamma curves and
|
||||
* viewing angles. Note that while color-fringing is reduced, it can
|
||||
* only be minimized by using linear alpha blending and gamma
|
||||
* correction to render glyphs onto surfaces.
|
||||
*
|
||||
* FT_LCD_FILTER_LIGHT ::
|
||||
* The light filter is a variant that produces less blurriness at the
|
||||
* cost of slightly more color fringes than the default one. It might
|
||||
* be better, depending on taste, your monitor, or your personal vision.
|
||||
* The light filter is a variant that is sharper at the cost of
|
||||
* slightly more color fringes than the default one.
|
||||
*
|
||||
* It is a boxy, normalized, and color-balanced three-tap filter that
|
||||
* is less forgiving to screens with non-ideal gamma curves and
|
||||
* viewing angles. This filter works best when the rendering system
|
||||
* uses linear alpha blending and gamma correction to render glyphs
|
||||
* onto surfaces.
|
||||
*
|
||||
* FT_LCD_FILTER_LEGACY ::
|
||||
* This filter corresponds to the original libXft color filter. It
|
||||
|
@ -305,12 +305,10 @@
|
||||
FT_Library_SetLcdFilter( FT_Library library,
|
||||
FT_LcdFilter filter )
|
||||
{
|
||||
static const FT_Byte default_filter[5] =
|
||||
{ 0x08, 0x4d, 0x56, 0x4d, 0x08 };
|
||||
static const FT_Byte light_filter[5] =
|
||||
{ 0x00, 0x55, 0x56, 0x55, 0x00 };
|
||||
/* the values here sum up to a value larger than 256, */
|
||||
/* providing a cheap gamma correction */
|
||||
static const FT_Byte default_filter[5] =
|
||||
{ 0x10, 0x40, 0x70, 0x40, 0x10 };
|
||||
|
||||
|
||||
if ( !library )
|
||||
|
Loading…
Reference in New Issue
Block a user