forked from minhngoc25a/freetype2
[sdf] Use 8 bits for final SDF output instead of 16bits.
Since 8-bits is enough to represent SDF data we no longer require 16-bits for this purpose. Also, we now normalize the output data to use the entire 8-bit range efficiently. For example: if we use 3.5 format with a spread of 1 we basically only use the starting 5-bits. By normalizing we can use the entire 8-bit range. * include/freetype/freetype.h (FT_Render_Mode): Updated description for `FT_RENDER_MODE_SDF` regarding this change. * include/freetype/ftimage.h (FT_Pixel_Mode): Removed `FT_PIXEL_MODE_GRAY16` since no longer required. * include/freetype/fttypes.h (FT_F6Dot10): Removed since no longer required. * src/sdf/ftsdfrend.c (ft_sdf_render, ft_bsdf_render): Allocate 8-bit bitmap instead of 16-bit buffer. * src/sdf/ftsdfcommon.h (map_fixed_to_sdf): Added function to convert 16.16 distance value to our desired format. * src/sdf/ftsdf.c (sdf_generate_with_overlaps, sdf_generate_bounding_box): Use the new `map_fixed_to_sdf` function and also use 8-bit output buffer. * src/sdf/ftbsdf.c (finalize_sdf): Output to a 8-bit buffer instead of 16-bit buffer.
This commit is contained in:
parent
2a6665a4c0
commit
2b1d556269
32
ChangeLog
32
ChangeLog
|
@ -1,3 +1,35 @@
|
|||
2021-06-08 Anuj Verma <anujv@iitbhilai.ac.in>
|
||||
|
||||
[sdf] Use 8 bits for final SDF output instead of 16bits.
|
||||
|
||||
Since 8-bits is enough to represent SDF data we no longer require
|
||||
16-bits for this purpose. Also, we now normalize the output data
|
||||
to use the entire 8-bit range efficiently. For example: if we use
|
||||
3.5 format with a spread of 1 we basically only use the starting
|
||||
5-bits. By normalizing we can use the entire 8-bit range.
|
||||
|
||||
* include/freetype/freetype.h (FT_Render_Mode): Updated description
|
||||
for `FT_RENDER_MODE_SDF` regarding this change.
|
||||
|
||||
* include/freetype/ftimage.h (FT_Pixel_Mode): Removed
|
||||
`FT_PIXEL_MODE_GRAY16` since no longer required.
|
||||
|
||||
* include/freetype/fttypes.h (FT_F6Dot10): Removed since no longer
|
||||
required.
|
||||
|
||||
* src/sdf/ftsdfrend.c (ft_sdf_render, ft_bsdf_render): Allocate 8-bit
|
||||
bitmap instead of 16-bit buffer.
|
||||
|
||||
* src/sdf/ftsdfcommon.h (map_fixed_to_sdf): Added function to convert
|
||||
16.16 distance value to our desired format.
|
||||
|
||||
* src/sdf/ftsdf.c (sdf_generate_with_overlaps,
|
||||
sdf_generate_bounding_box): Use the new `map_fixed_to_sdf` function
|
||||
and also use 8-bit output buffer.
|
||||
|
||||
* src/sdf/ftbsdf.c (finalize_sdf): Output to a 8-bit buffer instead
|
||||
of 16-bit buffer.
|
||||
|
||||
2021-06-02 Ben Wagner <bungeman@chromium.org>
|
||||
Werner Lemberg <wl@gnu.org>
|
||||
|
||||
|
|
|
@ -3302,19 +3302,46 @@ FT_BEGIN_HEADER
|
|||
* pixels and use the @FT_PIXEL_MODE_LCD_V mode.
|
||||
*
|
||||
* FT_RENDER_MODE_SDF ::
|
||||
* This mode corresponds to 16-bit signed distance fields (SDF)
|
||||
* This mode corresponds to 8-bit signed distance fields (SDF)
|
||||
* bitmaps. Each pixel in a SDF bitmap contains information about the
|
||||
* nearest edge of the glyph outline. The distances are calculated
|
||||
* from the center of the pixel and are positive if they are filled by
|
||||
* the outline (i.e., inside the outline) and negative otherwise. The
|
||||
* output bitmap buffer is represented as 6.10 fixed-point values; use
|
||||
* @FT_F6Dot10 and convert accordingly.
|
||||
* the outline (i.e., inside the outline) and negative otherwise. Check
|
||||
* the note below on how to convert the output values to usable data.
|
||||
*
|
||||
* @note:
|
||||
* The selected render mode only affects vector glyphs of a font.
|
||||
* Embedded bitmaps often have a different pixel mode like
|
||||
* @FT_PIXEL_MODE_MONO. You can use @FT_Bitmap_Convert to transform them
|
||||
* into 8-bit pixmaps.
|
||||
*
|
||||
* For @FT_RENDER_MODE_SDF output bitmap buffer contains normalized
|
||||
* distance values that are packed into unsigned 8-bit buffer. To get
|
||||
* pixel values in floating point representation use the following
|
||||
* conversion:
|
||||
*
|
||||
* ```
|
||||
* <load glyph and render using @FT_RENDER_MODE_SDF, then use the
|
||||
* output buffer as follows>
|
||||
*
|
||||
* ...
|
||||
* FT_Byte buffer = glyph->bitmap->buffer;
|
||||
*
|
||||
* for pixel in buffer
|
||||
* {
|
||||
* <`sd` is the signed distance and spread is the current `spread`,
|
||||
* the default spread is 2 and can be changed>
|
||||
*
|
||||
* float sd = (float)pixel - 128.0f;
|
||||
*
|
||||
* <convert the to pixel values>
|
||||
*
|
||||
* sd = ( sd / 128.0f ) * spread;
|
||||
*
|
||||
* <store `sd` in a buffer or use as required>
|
||||
* }
|
||||
*
|
||||
* ```
|
||||
*/
|
||||
typedef enum FT_Render_Mode_
|
||||
{
|
||||
|
|
|
@ -157,13 +157,6 @@ FT_BEGIN_HEADER
|
|||
* in font files according to the OpenType specification. We haven't
|
||||
* found a single font using this format, however.
|
||||
*
|
||||
* FT_PIXEL_MODE_GRAY16 ::
|
||||
* A 16-bit per pixel bitmap used to represent signed distances in a
|
||||
* signed distance field bitmap as needed by @FT_RENDER_MODE_SDF.
|
||||
* Values are represented in a 6.10 fixed-point format; this means
|
||||
* that you have to divide by 1024 to get the actual data generated by
|
||||
* the SDF rasterizers.
|
||||
*
|
||||
* FT_PIXEL_MODE_LCD ::
|
||||
* An 8-bit bitmap, representing RGB or BGR decimated glyph images used
|
||||
* for display on LCD displays; the bitmap is three times wider than
|
||||
|
@ -194,7 +187,6 @@ FT_BEGIN_HEADER
|
|||
FT_PIXEL_MODE_LCD,
|
||||
FT_PIXEL_MODE_LCD_V,
|
||||
FT_PIXEL_MODE_BGRA,
|
||||
FT_PIXEL_MODE_GRAY16,
|
||||
|
||||
FT_PIXEL_MODE_MAX /* do not remove */
|
||||
|
||||
|
|
|
@ -78,7 +78,6 @@ FT_BEGIN_HEADER
|
|||
* FT_FWord
|
||||
* FT_UFWord
|
||||
* FT_F2Dot14
|
||||
* FT_F6Dot10
|
||||
* FT_UnitVector
|
||||
* FT_F26Dot6
|
||||
* FT_Data
|
||||
|
@ -265,17 +264,6 @@ FT_BEGIN_HEADER
|
|||
typedef signed short FT_F2Dot14;
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
*
|
||||
* @type:
|
||||
* FT_F6Dot10
|
||||
*
|
||||
* @description:
|
||||
* A signed 6.10 fixed-point type used for signed distance values.
|
||||
*/
|
||||
typedef signed short FT_F6Dot10;
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
*
|
||||
* @type:
|
||||
|
|
|
@ -1092,12 +1092,12 @@
|
|||
finalize_sdf( BSDF_Worker* worker,
|
||||
const FT_Bitmap* target )
|
||||
{
|
||||
FT_Error error = FT_Err_Ok;
|
||||
FT_Error error = FT_Err_Ok;
|
||||
|
||||
FT_Int w, r;
|
||||
FT_Int i, j;
|
||||
FT_6D10* t_buffer;
|
||||
FT_16D16 spread;
|
||||
FT_Int w, r;
|
||||
FT_Int i, j;
|
||||
FT_SDFFormat* t_buffer;
|
||||
FT_16D16 spread;
|
||||
|
||||
|
||||
if ( !worker || !target )
|
||||
|
@ -1108,7 +1108,7 @@
|
|||
|
||||
w = (int)target->width;
|
||||
r = (int)target->rows;
|
||||
t_buffer = (FT_6D10*)target->buffer;
|
||||
t_buffer = (FT_SDFFormat*)target->buffer;
|
||||
|
||||
if ( w != worker->width ||
|
||||
r != worker->rows )
|
||||
|
@ -1128,10 +1128,10 @@
|
|||
{
|
||||
for ( i = 0; i < w; i++ )
|
||||
{
|
||||
FT_Int index;
|
||||
FT_16D16 dist;
|
||||
FT_6D10 final_dist;
|
||||
FT_Char sign;
|
||||
FT_Int index;
|
||||
FT_16D16 dist;
|
||||
FT_SDFFormat final_dist;
|
||||
FT_Char sign;
|
||||
|
||||
|
||||
index = j * w + i;
|
||||
|
@ -1144,10 +1144,6 @@
|
|||
dist = square_root( dist );
|
||||
#endif
|
||||
|
||||
/* convert from 16.16 to 6.10 */
|
||||
dist /= 64;
|
||||
final_dist = (FT_6D10)(dist & 0x0000FFFF);
|
||||
|
||||
/* We assume that if the pixel is inside a contour */
|
||||
/* its coverage value must be > 127. */
|
||||
sign = worker->distance_map[index].alpha < 127 ? -1 : 1;
|
||||
|
@ -1156,7 +1152,10 @@
|
|||
if ( worker->params.flip_sign )
|
||||
sign = -sign;
|
||||
|
||||
t_buffer[index] = final_dist * sign;
|
||||
/* concatenate from 16.16 to appropriate format */
|
||||
final_dist = map_fixed_to_sdf( dist * sign, spread );
|
||||
|
||||
t_buffer[index] = final_dist;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -2897,6 +2897,10 @@
|
|||
/* `sdf_generate' is not used at the moment */
|
||||
#if 0
|
||||
|
||||
#error "DO NOT USE THIS!"
|
||||
#error "The function still output 16-bit data which might cause memory"
|
||||
#error "corruption. If required I will add this later."
|
||||
|
||||
/**************************************************************************
|
||||
*
|
||||
* @Function:
|
||||
|
@ -3193,7 +3197,7 @@
|
|||
FT_Int sp_sq; /* max value to check */
|
||||
|
||||
SDF_Contour* contours; /* list of all contours */
|
||||
FT_Short* buffer; /* the bitmap buffer */
|
||||
FT_SDFFormat* buffer; /* the bitmap buffer */
|
||||
|
||||
/* This buffer has the same size in indices as the */
|
||||
/* bitmap buffer. When we check a pixel position for */
|
||||
|
@ -3202,6 +3206,8 @@
|
|||
/* and also determine the signs properly. */
|
||||
SDF_Signed_Distance* dists = NULL;
|
||||
|
||||
const FT_16D16 fixed_spread = FT_INT_16D16( spread );
|
||||
|
||||
|
||||
if ( !shape || !bitmap )
|
||||
{
|
||||
|
@ -3229,12 +3235,12 @@
|
|||
contours = shape->contours;
|
||||
width = (FT_Int)bitmap->width;
|
||||
rows = (FT_Int)bitmap->rows;
|
||||
buffer = (FT_Short*)bitmap->buffer;
|
||||
buffer = (FT_SDFFormat*)bitmap->buffer;
|
||||
|
||||
if ( USE_SQUARED_DISTANCES )
|
||||
sp_sq = (FT_Int)FT_INT_16D16( spread * spread );
|
||||
sp_sq = fixed_spread * fixed_spread;
|
||||
else
|
||||
sp_sq = (FT_Int)FT_INT_16D16( spread );
|
||||
sp_sq = fixed_spread;
|
||||
|
||||
if ( width == 0 || rows == 0 )
|
||||
{
|
||||
|
@ -3347,21 +3353,23 @@
|
|||
/* if the pixel is not set */
|
||||
/* its shortest distance is more than `spread` */
|
||||
if ( dists[index].sign == 0 )
|
||||
dists[index].distance = FT_INT_16D16( spread );
|
||||
dists[index].distance = fixed_spread;
|
||||
else
|
||||
current_sign = dists[index].sign;
|
||||
|
||||
/* clamp the values */
|
||||
if ( dists[index].distance > (FT_Int)FT_INT_16D16( spread ) )
|
||||
dists[index].distance = FT_INT_16D16( spread );
|
||||
if ( dists[index].distance > fixed_spread )
|
||||
dists[index].distance = fixed_spread;
|
||||
|
||||
/* convert from 16.16 to 6.10 */
|
||||
dists[index].distance /= 64;
|
||||
/* flip sign if required */
|
||||
dists[index].distance *= internal_params.flip_sign ?
|
||||
-current_sign :
|
||||
current_sign;
|
||||
|
||||
if ( internal_params.flip_sign )
|
||||
buffer[index] = (FT_Short)dists[index].distance * -current_sign;
|
||||
else
|
||||
buffer[index] = (FT_Short)dists[index].distance * current_sign;
|
||||
/* concatenate to appropriate format */
|
||||
buffer[index] = map_fixed_to_sdf(
|
||||
dists[index].distance,
|
||||
fixed_spread );
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3498,9 +3506,9 @@
|
|||
SDF_Contour* head; /* head of the contour list */
|
||||
SDF_Shape temp_shape; /* temporary shape */
|
||||
|
||||
FT_Memory memory; /* to allocate memory */
|
||||
FT_6D10* t; /* target bitmap buffer */
|
||||
FT_Bool flip_sign; /* filp sign? */
|
||||
FT_Memory memory; /* to allocate memory */
|
||||
FT_SDFFormat* t; /* target bitmap buffer */
|
||||
FT_Bool flip_sign; /* filp sign? */
|
||||
|
||||
/* orientation of all the separate contours */
|
||||
SDF_Contour_Orientation* orientations;
|
||||
|
@ -3621,7 +3629,7 @@
|
|||
shape->contours = head;
|
||||
|
||||
/* cast the output bitmap buffer */
|
||||
t = (FT_6D10*)bitmap->buffer;
|
||||
t = (FT_SDFFormat*)bitmap->buffer;
|
||||
|
||||
/* Iterate over all pixels and combine all separate */
|
||||
/* contours. These are the rules for combining: */
|
||||
|
@ -3636,18 +3644,18 @@
|
|||
{
|
||||
for ( i = 0; i < width; i++ )
|
||||
{
|
||||
FT_Int id = j * width + i; /* index of current pixel */
|
||||
FT_Int c; /* contour iterator */
|
||||
FT_Int id = j * width + i; /* index of current pixel */
|
||||
FT_Int c; /* contour iterator */
|
||||
|
||||
FT_6D10 val_c = SHRT_MIN; /* max clockwise value */
|
||||
FT_6D10 val_ac = SHRT_MAX; /* min counter-clockwise val */
|
||||
FT_SDFFormat val_c = 0; /* max clockwise value */
|
||||
FT_SDFFormat val_ac = UCHAR_MAX; /* min counter-clockwise val */
|
||||
|
||||
|
||||
/* iterate through all the contours */
|
||||
for ( c = 0; c < num_contours; c++ )
|
||||
{
|
||||
/* current contour value */
|
||||
FT_6D10 temp = ((FT_6D10*)bitmaps[c].buffer)[id];
|
||||
FT_SDFFormat temp = ( (FT_SDFFormat*)bitmaps[c].buffer )[id];
|
||||
|
||||
|
||||
if ( orientations[c] == SDF_ORIENTATION_CW )
|
||||
|
@ -3658,7 +3666,10 @@
|
|||
|
||||
/* Finally find the smaller of the two and assign to output. */
|
||||
/* Also apply `flip_sign` if set. */
|
||||
t[id] = FT_MIN( val_c, val_ac ) * ( flip_sign ? -1 : 1 );
|
||||
t[id] = FT_MIN( val_c, val_ac );
|
||||
|
||||
if ( flip_sign )
|
||||
t[id] = invert_sign( t[id] );
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3681,6 +3692,9 @@
|
|||
}
|
||||
}
|
||||
|
||||
/* restore the `flip_sign` property */
|
||||
internal_params.flip_sign = flip_sign;
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
|
|
|
@ -115,7 +115,7 @@ FT_BEGIN_HEADER
|
|||
|
||||
typedef FT_Fixed FT_16D16; /* 16.16 fixed-point representation */
|
||||
typedef FT_Fixed FT_26D6; /* 26.6 fixed-point representation */
|
||||
typedef FT_Short FT_6D10; /* 6.10 fixed-point representation */
|
||||
typedef FT_Byte FT_SDFFormat; /* format to represent SDF data */
|
||||
|
||||
typedef FT_BBox FT_CBox; /* control box of a curve */
|
||||
|
||||
|
@ -162,6 +162,75 @@ FT_BEGIN_HEADER
|
|||
return (FT_16D16)q;
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
*
|
||||
* format and sign manipulating functions
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Convert 16.16 fixed point value to the desired output format.
|
||||
* In this case we reduce 16.16 fixed point value to normalized
|
||||
* 8-bit values.
|
||||
* The `max_value` in the parameter is the maximum value in the
|
||||
* distance field map and is equal to the spread. We normalize
|
||||
* the distances using this value instead of computing the maximum
|
||||
* value for the entire bitmap.
|
||||
* You can use this function to map the 16.16 signed values to any
|
||||
* format required. Do note that the output buffer is 8-bit, so only
|
||||
* use 8-bit format for `FT_SDFFormat`, or increase buffer size in
|
||||
* `ftsdfrend.c`.
|
||||
*/
|
||||
static FT_SDFFormat
|
||||
map_fixed_to_sdf( FT_16D16 dist, FT_16D16 max_value )
|
||||
{
|
||||
FT_SDFFormat out;
|
||||
FT_16D16 udist;
|
||||
|
||||
|
||||
/* normalize the distance values */
|
||||
dist = FT_DivFix( dist, max_value );
|
||||
|
||||
udist = dist < 0 ? -dist : dist;
|
||||
|
||||
/* Reduce the distance values to 8 bits, +1/-1 in */
|
||||
/* 16.16 takes the 16th bit. So we right shift the */
|
||||
/* number by 9 to make it fit in the 7 bit range. */
|
||||
/* 1 bit is reserved for the sign. */
|
||||
udist >>= 9;
|
||||
|
||||
/* Since char can only store max positive value */
|
||||
/* of 127 we need to make sure it does not wrap */
|
||||
/* around and give a negative value. */
|
||||
if ( dist > 0 && udist > 127 )
|
||||
udist = 127;
|
||||
if ( dist < 0 && udist > 128 )
|
||||
udist = 128;
|
||||
|
||||
/* Output the data; negative values are from [0, 127] and positive */
|
||||
/* from [128, 255]. One important thing is that negative values */
|
||||
/* are inverted here, that means [0, 128] maps to [-128, 0] linearly. */
|
||||
/* More on that in `freetype.h` near `FT_RENDER_MODE_SDF` */
|
||||
out = dist < 0 ? 128 - (FT_SDFFormat)udist :
|
||||
(FT_SDFFormat)udist + 128;
|
||||
return out;
|
||||
}
|
||||
|
||||
/*
|
||||
* Invert the signed distance packed into the corresponding format.
|
||||
* So if the values are negative they will become positive in the
|
||||
* chosen format.
|
||||
*
|
||||
* [Note]: This function should only be used after converting the
|
||||
* 16.16 signed distance values to `FT_SDFFormat`, if that
|
||||
* conversion has not been done, then simply invert the sign
|
||||
* and use the above function to pack the values.
|
||||
*/
|
||||
static FT_SDFFormat
|
||||
invert_sign( FT_SDFFormat dist ) {
|
||||
return 255 - dist;
|
||||
}
|
||||
|
||||
|
||||
FT_END_HEADER
|
||||
|
||||
|
|
|
@ -313,9 +313,9 @@
|
|||
bitmap->width += x_pad * 2;
|
||||
|
||||
/* ignore the pitch, pixel mode and set custom */
|
||||
bitmap->pixel_mode = FT_PIXEL_MODE_GRAY16;
|
||||
bitmap->pitch = (int)( bitmap->width * 2 );
|
||||
bitmap->num_grays = 65535;
|
||||
bitmap->pixel_mode = FT_PIXEL_MODE_GRAY;
|
||||
bitmap->pitch = (int)( bitmap->width );
|
||||
bitmap->num_grays = 255;
|
||||
|
||||
/* allocate new buffer */
|
||||
if ( FT_ALLOC_MULT( bitmap->buffer, bitmap->rows, bitmap->pitch ) )
|
||||
|
@ -524,9 +524,9 @@
|
|||
target.width = bitmap->width + x_pad * 2;
|
||||
|
||||
/* set up the target bitmap */
|
||||
target.pixel_mode = FT_PIXEL_MODE_GRAY16;
|
||||
target.pitch = (int)( target.width * 2 );
|
||||
target.num_grays = 65535;
|
||||
target.pixel_mode = FT_PIXEL_MODE_GRAY;
|
||||
target.pitch = (int)( target.width );
|
||||
target.num_grays = 255;
|
||||
|
||||
if ( FT_ALLOC_MULT( target.buffer, target.rows, target.pitch ) )
|
||||
goto Exit;
|
||||
|
|
Loading…
Reference in New Issue