[smooth] Harmony LCD rendering.

This is a new technology for LCD-optimized rendering. It capitalizes
on the fact that each color channel grid is shifted by a third of a
pixel.  Therefore it is logical to render 3 separate monochrome
bitmaps shifting the outline by 1/3 pixel, and then combine them.
Importantly, the resulting output does not require additional LCD
filtering.

* src/smooth/ftsmooth.c (ft_smooth_render_generic)
[!FT_CONFIG_OPTION_SUBPIXEL_RENDERING]: Implement new LCD-optimized
rendering.

* include/freetype/ftlcdfil.h, include/freetype/freetype.h,
include/freetype/config/ftoption.h, devel/ftoption.h: Updated
documentation.
This commit is contained in:
Alexei Podtelezhnikov 2017-03-09 00:08:38 -05:00
parent 5710ef989d
commit 410f3799b6
6 changed files with 150 additions and 77 deletions

View File

@ -1,3 +1,22 @@
2017-08-08 Alexei Podtelezhnikov <apodtele@gmail.com>
[smooth] Harmony LCD rendering.
This is a new technology for LCD-optimized rendering. It capitalizes
on the fact that each color channel grid is shifted by a third of a
pixel. Therefore it is logical to render 3 separate monochrome
bitmaps shifting the outline by 1/3 pixel, and then combine them.
Importantly, the resulting output does not require additional LCD
filtering.
* src/smooth/ftsmooth.c (ft_smooth_render_generic)
[!FT_CONFIG_OPTION_SUBPIXEL_RENDERING]: Implement new LCD-optimized
rendering.
* include/freetype/ftlcdfil.h, include/freetype/freetype.h,
include/freetype/config/ftoption.h, devel/ftoption.h: Updated
documentation.
2017-08-08 Alexei Podtelezhnikov <apodtele@gmail.com>
* src/smooth/ftsmooth.c (ft_smooth_render_generic): Clean up.

View File

@ -107,22 +107,19 @@ FT_BEGIN_HEADER
/*************************************************************************/
/* */
/* Uncomment the line below if you want to activate sub-pixel rendering */
/* (a.k.a. LCD rendering, or ClearType) in this build of the library. */
/* Uncomment the line below if you want to activate LCD rendering */
/* technology similar to ClearType in this build of the library. This */
/* technology triples the resolution in the direction color subpixels. */
/* To mitigate color fringes inherent to this technology, you also need */
/* to explicitly set up LCD filtering. */
/* */
/* Note that this feature is covered by several Microsoft patents */
/* and should not be activated in any default build of the library. */
/* When this macro is not defined, FreeType offers alternative LCD */
/* rendering technology that produces excellent output without LCD */
/* filtering. */
/* */
/* This macro has no impact on the FreeType API, only on its */
/* _implementation_. For example, using FT_RENDER_MODE_LCD when calling */
/* FT_Render_Glyph still generates a bitmap that is 3 times wider than */
/* the original size in case this macro isn't defined; however, each */
/* triplet of subpixels has R=G=B. */
/* */
/* This is done to allow FreeType clients to run unmodified, forcing */
/* them to display normal gray-level anti-aliased glyphs. */
/* */
#define FT_CONFIG_OPTION_SUBPIXEL_RENDERING
/* #define FT_CONFIG_OPTION_SUBPIXEL_RENDERING */
/*************************************************************************/

View File

@ -107,20 +107,17 @@ FT_BEGIN_HEADER
/*************************************************************************/
/* */
/* Uncomment the line below if you want to activate sub-pixel rendering */
/* (a.k.a. LCD rendering, or ClearType) in this build of the library. */
/* Uncomment the line below if you want to activate LCD rendering */
/* technology similar to ClearType in this build of the library. This */
/* technology triples the resolution in the direction color subpixels. */
/* To mitigate color fringes inherent to this technology, you also need */
/* to explicitly set up LCD filtering. */
/* */
/* Note that this feature is covered by several Microsoft patents */
/* and should not be activated in any default build of the library. */
/* */
/* This macro has no impact on the FreeType API, only on its */
/* _implementation_. For example, using FT_RENDER_MODE_LCD when calling */
/* FT_Render_Glyph still generates a bitmap that is 3 times wider than */
/* the original size in case this macro isn't defined; however, each */
/* triplet of subpixels has R=G=B. */
/* */
/* This is done to allow FreeType clients to run unmodified, forcing */
/* them to display normal gray-level anti-aliased glyphs. */
/* When this macro is not defined, FreeType offers alternative LCD */
/* rendering technology that produces excellent output without LCD */
/* filtering. */
/* */
/* #define FT_CONFIG_OPTION_SUBPIXEL_RENDERING */

View File

@ -3131,11 +3131,13 @@ FT_BEGIN_HEADER
/* glyph outline in pixels and use the @FT_PIXEL_MODE_LCD_V mode. */
/* */
/* <Note> */
/* The LCD-optimized glyph bitmaps produced by `FT_Render_Glyph' can */
/* be filtered to reduce color-fringes by using */
/* @FT_Library_SetLcdFilter (not active in the default builds). It */
/* is up to the caller to either call `FT_Library_SetLcdFilter' (if */
/* available) or do the filtering itself. */
/* Should you define FT_CONFIG_OPTION_SUBPIXEL_RENDERING in your */
/* `ftoption.h', which enables patented ClearType-style rendering, */
/* the LCD-optimized glyph bitmaps should be filtered to reduce color */
/* fringes inherent to this technology. You can either set up LCD */
/* filtering with @FT_Library_SetLcdFilter or @FT_Face_Properties, */
/* or do the filtering yourself. The default FreeType LCD rendering */
/* technology does not require filtering. */
/* */
/* The selected render mode only affects vector glyphs of a font. */
/* Embedded bitmaps often have a different pixel mode like */

View File

@ -44,9 +44,16 @@ FT_BEGIN_HEADER
* Reduce color fringes of subpixel-rendered bitmaps.
*
* @description:
* 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
* Should you #define FT_CONFIG_OPTION_SUBPIXEL_RENDERING in your
* `ftoption.h', which enables patented ClearType-style rendering,
* the LCD-optimized glyph bitmaps should be filtered to reduce color
* fringes inherent to this technology. The default FreeType LCD
* rendering uses different technology, and API described below,
* although available, does nothing.
*
* ClearType-style LCD 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
@ -54,12 +61,6 @@ FT_BEGIN_HEADER
* the higher resolution to reduce color fringes, making the glyph image
* slightly blurrier. Positional improvements will remain.
*
* 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 and explicitly call @FT_Library_SetLcdFilter
* to enable it.
*
* A filter should have two properties:
*
* 1) It should be normalized, meaning the sum of the 5~components

View File

@ -190,7 +190,23 @@
/* taking into account the origin shift */
FT_Outline_Get_CBox( outline, &cbox );
#ifdef FT_CONFIG_OPTION_SUBPIXEL_RENDERING
#ifndef FT_CONFIG_OPTION_SUBPIXEL_RENDERING
/* add minimal padding for LCD rendering */
if ( hmul )
{
cbox.xMax += 21;
cbox.xMin -= 21;
}
if ( vmul )
{
cbox.yMax += 21;
cbox.yMin -= 21;
}
#else /* FT_CONFIG_OPTION_SUBPIXEL_RENDERING */
/* add minimal padding for LCD filter depending on specific weights */
if ( lcd_filter_func )
{
@ -210,7 +226,8 @@
: lcd_weights[1] ? 22 : 0;
}
}
#endif
#endif /* FT_CONFIG_OPTION_SUBPIXEL_RENDERING */
cbox.xMin = FT_PIX_FLOOR( cbox.xMin + x_shift );
cbox.yMin = FT_PIX_FLOOR( cbox.yMin + y_shift );
@ -339,57 +356,97 @@
#else /* !FT_CONFIG_OPTION_SUBPIXEL_RENDERING */
/* render outline into bitmap */
error = render->raster_render( render->raster, &params );
if ( error )
goto Exit;
/* expand it horizontally */
if ( hmul )
if ( hmul ) /* lcd */
{
FT_Byte* line = bitmap->buffer;
FT_UInt hh;
FT_Byte* line;
FT_Byte* temp;
FT_Int i, j;
/* Render 3 separate monochrome bitmaps, shifting the outline */
/* by 1/3 pixel. */
width /= 3;
for ( hh = height; hh > 0; hh--, line += pitch )
FT_Outline_Translate( outline, 21, 0 );
error = render->raster_render( render->raster, &params );
if ( error )
goto Exit;
FT_Outline_Translate( outline, -21, 0 );
bitmap->buffer += width;
error = render->raster_render( render->raster, &params );
if ( error )
goto Exit;
FT_Outline_Translate( outline, -21, 0 );
bitmap->buffer += width;
error = render->raster_render( render->raster, &params );
if ( error )
goto Exit;
FT_Outline_Translate( outline, 21, 0 );
bitmap->buffer -= 2 * width;
/* XXX: Rearrange the bytes according to FT_PIXEL_MODE_LCD. */
/* XXX: It is more efficient to render every third byte above. */
if ( FT_ALLOC( temp, (FT_ULong)pitch ) )
goto Exit;
for ( i = 0; i < height; i++ )
{
FT_UInt xx;
FT_Byte* end = line + width;
for ( xx = width / 3; xx > 0; xx-- )
line = bitmap->buffer + i * pitch;
for ( j = 0; j < width; j++ )
{
FT_UInt pixel = line[xx-1];
end[-3] = (FT_Byte)pixel;
end[-2] = (FT_Byte)pixel;
end[-1] = (FT_Byte)pixel;
end -= 3;
temp[3 * j ] = line[j];
temp[3 * j + 1] = line[j + width];
temp[3 * j + 2] = line[j + width + width];
}
FT_MEM_COPY( line, temp, pitch );
}
FT_FREE( temp );
}
/* expand it vertically */
if ( vmul )
else if ( vmul ) /* lcd_v */
{
FT_Byte* read = bitmap->buffer + ( height - height / 3 ) * pitch;
FT_Byte* write = bitmap->buffer;
FT_UInt hh;
/* Render 3 separate monochrome bitmaps, shifting the outline */
/* by 1/3 pixel. Triple the pitch to render on each third row. */
bitmap->pitch *= 3;
bitmap->rows /= 3;
FT_Outline_Translate( outline, 0, 21 );
bitmap->buffer += 2 * pitch;
for ( hh = height / 3; hh > 0; hh-- )
{
ft_memcpy( write, read, pitch );
write += pitch;
error = render->raster_render( render->raster, &params );
if ( error )
goto Exit;
ft_memcpy( write, read, pitch );
write += pitch;
FT_Outline_Translate( outline, 0, -21 );
bitmap->buffer -= pitch;
ft_memcpy( write, read, pitch );
write += pitch;
read += pitch;
}
error = render->raster_render( render->raster, &params );
if ( error )
goto Exit;
FT_Outline_Translate( outline, 0, -21 );
bitmap->buffer -= pitch;
error = render->raster_render( render->raster, &params );
if ( error )
goto Exit;
FT_Outline_Translate( outline, 0, 21 );
bitmap->pitch /= 3;
bitmap->rows *= 3;
}
else /* grayscale */
{
error = render->raster_render( render->raster, &params );
if ( error )
goto Exit;
}
#endif /* !FT_CONFIG_OPTION_SUBPIXEL_RENDERING */